arrayer och pekare i C

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

arrayer och pekare i C

Inlägg 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 ?
Senast redigerad av jesse 15 februari 2012, 12:29:06, redigerad totalt 1 gång.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: arrayer och pekare i C

Inlägg 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).
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: arrayer och pekare i C

Inlägg 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.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: arrayer och pekare i C

Inlägg av sodjan »

OK. Kan man inte ange "den andra" till just 0 då ?
johano
Inlägg: 1943
Blev medlem: 22 januari 2008, 10:07:45
Ort: Stockholm

Re: arrayer och pekare i C

Inlägg 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
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: arrayer och pekare i C

Inlägg 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
Användarvisningsbild
AndLi
Inlägg: 18288
Blev medlem: 11 februari 2004, 18:17:59
Ort: Knivsta
Kontakt:

Re: arrayer och pekare i C

Inlägg av AndLi »

Det korta svaret är Ja.

--
Jag skulle vilja påstå att sodjan alternativ ska vara print((uint8_t*)text+n*LENGD)
Användarvisningsbild
Ulf
Inlägg: 399
Blev medlem: 15 februari 2006, 14:04:03

Re: arrayer och pekare i C

Inlägg 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
bearing
Inlägg: 11676
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Re: arrayer och pekare i C

Inlägg 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.
Nerre
Inlägg: 27235
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: arrayer och pekare i C

Inlägg 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.
Användarvisningsbild
AndLi
Inlägg: 18288
Blev medlem: 11 februari 2004, 18:17:59
Ort: Knivsta
Kontakt:

Re: arrayer och pekare i C

Inlägg 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.
Användarvisningsbild
Ulf
Inlägg: 399
Blev medlem: 15 februari 2006, 14:04:03

Re: arrayer och pekare i C

Inlägg 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.
Användarvisningsbild
kimmen
Inlägg: 2042
Blev medlem: 25 augusti 2007, 16:53:51
Ort: Stockholm (Kista)

Re: arrayer och pekare i C

Inlägg 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å.
Senast redigerad av kimmen 15 februari 2012, 14:05:13, redigerad totalt 1 gång.
johano
Inlägg: 1943
Blev medlem: 22 januari 2008, 10:07:45
Ort: Stockholm

Re: arrayer och pekare i C

Inlägg 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
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: arrayer och pekare i C

Inlägg 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...
Skriv svar