Sida 1 av 2

arrayer och pekare i C

Postat: 15 februari 2012, 12:25:01
av jesse
Den kortfattade versionen:

uint8_t text[ANTAL][LENGD];

är då &text[nummer][0] ekvivalent med text[nummer] ?

-----------------------------------------------------------------------------------------------
Den långa versionen av samma fråga: :roll:

Om jag har en sträng i C kan jag använda strängens namn som pekare (t.ex. i funktiosanrop):

Kod: Markera allt

void print(uint8_t* pekare); // deklaration

uint8_t text[] = "Hello";
print (text);
detta är ekvivalent med att skriva:

Kod: Markera allt

uint8_t text[];
print (&text[0]); // gör om till pekare
Men hur är det om jag har en arrray med strängar....
och jag vill skicka en pekare till första tecknet i text nr n

Kod: Markera allt

uint8_t text[ANTAL][LENGD];
print(&text[n][0]);
Jag skapar ju en pekare om jag tar bort [0] , men hur vet jag vilken av 'dimensionerna' kompilatorn antar är noll? Är det alltid den sista, så jag borde kunna skriva:

Kod: Markera allt

uint8_t text[ANTAL][LENGD];
print(text[n]);
Skriver jag ut text nummer 'n', eller skriver jag ut från och med tecken 'n' i text nr 0 ?

Re: arrayer och pekare i C

Postat: 15 februari 2012, 12:28:58
av sodjan
> print(&text[n*LENGD]);

Eller något i den stilen. Alltså "peka" på första tecknet som ska skrivas.
Sen så måste ju även "print" känna till LENGD (eller stanna på null).

Re: arrayer och pekare i C

Postat: 15 februari 2012, 12:32:14
av jesse
> print(&text[n*LENGD]);
Det blir i alla fall garanterat fel... då [n] är ett index som automatiskt multipliceras med LENGD, alltså ingen pekare eller adress, även om det senare omvandlas till pekare innan det skickas till funktionen. print känner av '\0'

Vad jag egentligen har problem med är att jag blandar ihop de båda indexen i en tvådimensionell array, vilken av dem som förutsätts vara noll om jag tar bort en av dem.

Re: arrayer och pekare i C

Postat: 15 februari 2012, 12:34:40
av sodjan
OK. Kan man inte ange "den andra" till just 0 då ?

Re: arrayer och pekare i C

Postat: 15 februari 2012, 12:36:23
av johano
Gör ett litet testprogram och se själv :)

Kod: Markera allt


 uint8_t text[10][10];

 if( &(text[5][0]) == text[5] )
 {
  printf("De är lika");
 }
 else
 {
  printf("De är olika");
 }

/johan

Re: arrayer och pekare i C

Postat: 15 februari 2012, 12:42:52
av jesse
mja... så kan jag ju göra. men har bara AVRStudio5 uppe nu.... orkar inte starta ett nytt projekt i CodeBlocks.

Men jag har kollat lite andra exempel nu och det verkar som om det är det andra indexet (till höger) som anses vara default [0] om det tas bort. Det är alltid det indexet mest till höger som anger de kortaste avstånden i minnet, i det här fallet enstaka tecken, medan indexet till vänster multipliceras med hur lång den andra är.

uint8_t text[ANTAL][LENGD];

adress = &text[0][0] + (index1*LENGD) + index2

Re: arrayer och pekare i C

Postat: 15 februari 2012, 12:48:57
av AndLi
Det korta svaret är Ja.

--
Jag skulle vilja påstå att sodjan alternativ ska vara print((uint8_t*)text+n*LENGD)

Re: arrayer och pekare i C

Postat: 15 februari 2012, 13:09:37
av Ulf
För att peka ut hela din array så ska pekaren deklareras som uint8_t**.

begrunda följande:

Kod: Markera allt

uint8_t array[5][10];
uint8_t **minPek;
uint8_t *annanPek;

minPek = array; // OK

annanPek = array; // Inte OK, beroende på kompilatorinställning så kan det vara ok ändå

// Däremot funkar
annanPek = (uint8_t*) array

// Men detta är helt ok
annanPek = array[0];
annanPek = array[1];
annanPek = array[2];


uint8_t array[5][10] betyder egentligen att du har en endimensionell array, med 5 pekare till en array med 10 uint8_t.

Så andra tecknet i sträng 4 blir då array[3][1]. <- Rättat
Hoppas inte jag rör till det

Re: arrayer och pekare i C

Postat: 15 februari 2012, 13:29:41
av bearing
uint8_t array[5][10] betyder egentligen att du har en endimensionell array, med 5 pekare till en array med 10 uint8_t.
Stämmer verkligen detta?
uint8_t array[5][10] har jag alltid trott allokerar ett sammanhängande block på 5*10 bytes. Om det är som du säger skulle arrayen ta upp 5*pekarstorlek + 5*10 bytes, och varje block på 10 bytes skulle kunna ligga var som helst i minnet.

Re: arrayer och pekare i C

Postat: 15 februari 2012, 13:33:40
av Nerre
Eller för att säga det enklare: Det finns bara 1-dimensionella arrays.

Det som kallas "2-dimensionella" är egentligen 1-dimensionella arrays av 1-dimensionella arrays.

Re: arrayer och pekare i C

Postat: 15 februari 2012, 13:44:24
av AndLi
bearing: du har helt rätt

uint8_t array[5][10] kommer bli 50 bytes i följd... en sizeof(array) kommer ge 50 och de kommer ligga på rad.

Re: arrayer och pekare i C

Postat: 15 februari 2012, 13:48:47
av Ulf
Helt rätt bearing, var lite snabb där.

Det finns dock implementerat för några plattformar att de allokeras på olika ställen inte som ett block,
men en endimensionella allockeras dock som ett block.

Pekar är ju rätt kul egentligen, och otroligt användbart.
Det gäller bara att hålla tungan i rätt mun.

Re: arrayer och pekare i C

Postat: 15 februari 2012, 13:49:07
av kimmen
En flerdimensionell array är kontinuerlig i minnet och har inte flera nivåer av pekare, även om p[j] går att använda i båda fallen! För att komma åt en array via en pekare skall pekaren deklareras

uint8_t (*arraypekare)[LENGD];

dvs som en pekare till en LENGD-elementsarray (eller flera).

Det som jesse skriver skall dock fungera, men bara för en array och inte om man hade haft uint8_t ** text.

uint8_t text[ANTAL][LENGD];
adress = &text[0][0] + (index1*LENGD) + index2

Detta ger samma funktion för arrayer som någon av

adress = &text[index1][index2]
adress = text[index1] + index2
adress = *(text+index1) + index2

med skillnaden att dessa tre också fungerar för fallet du beskriver där man har en array av pekare på högsta nivån.

Följande exempel kraschar på sista raden, men jag får också en varning på den felaktiga tilldelningen "int *** felp = v;" med Microsofts C-kompilator:
"warning C4047: 'initializing' : 'int ***' differs in levels of indirection from 'int (*)[4][3]'"

Kod: Markera allt

void testfunc(void)
{
	int v[5][4][3];
	int *** felp = v;
	int (*p)[4][3];
	int i;

	for(i=0;i<5*4*3;i++)
	{
		v[0][0][i] = i;
	}


	p = v; // p och v uppför sig likadant

	i = felp[0][0][0]; // Krasch
}
edit: Men enligt 2.11 här: http://www.lysator.liu.se/c/c-faq/c-2.html är inte
adress = &text[0][0] + (index1*LENGD) + index2
garanterat av standarden att fungera, och det gäller ju då också v[0][0] = i;

Möjligen skulle detta kunna betyda att det är möjligt för en kompilator att implementera flerdimensionella arrayer som Ulf skrev. Om det inte finns något krav på att arrayen skall ha en särskild minneslayout alltså.

Re: arrayer och pekare i C

Postat: 15 februari 2012, 13:58:53
av johano
@Ulf,
visst är det kul med pekare och arrayer, här en personlig favorit:

Kod: Markera allt

char c = 4["abcdef"];
Eftersom a är ekvivalent med *(a+b) så länge som den ena är en är en pekare
och den andra en integral, så funkar ovanstående konstruktion, och c kommer få
värdet 'e' i uttrycket ovan :)

/johan

Re: arrayer och pekare i C

Postat: 15 februari 2012, 14:36:51
av jesse
char c = 4["abcdef"]; :shock:

Har aldrig tänkt på vad en konstant sträng egentligen är, men det som 'skickas vidare' är givetvis en pekare...

Innebär det också att

Kod: Markera allt

char text = "abcdef";
int i = 4;
char c = i[text]
så får jag ut 'e'?

Det här börjar bli komplicerat...