Gå til innhold

Problemer med pekere


Anbefalte innlegg

Jeg har følgende kode som skal skrive inn tall i array a og så kopiere det til array b.

 

Hvorfor skriver den nederste linja ut en minneverdi og ikke innholdet i array b posisjon 0?

Utskriften av *p fungerer jo fint.

 

[

#include <stdio.h>
#define MAX 10
int main()
{
int a[MAX];
int b[MAX];
int i;
int *p;
int *q;
printf( "%d\n", MAX);
p=a;
for(i=0; i<MAX; i++)
	a[i]=i*2;
printf("kakemann %d\n",*p);
q=b;
for(i=0; i<MAX; i++)
{
	*q++ = *p++;
}

printf("tallet %d\n",b[7]);
printf("%d\n",*q);
}

Endret av r2d290 waits for Obi-Wan
Lenke til kommentar
Videoannonse
Annonse

Jeg testet koden, og jeg fikk ut følgende:

10

kakemann 0

tallet 14

0

 

Er ikke det du forvnenter?

Linje 1: Du skriver du max, som er 10

Linje 2: Du skriver ut det som er lagret i p[0], som er 0*2 = 0

Linje 3: Du skriver ut tallet i b[7], som er 7*2 = 14

Linje 4: Du skriver ut det som er i q[0] som er 0*2 = 0

Lenke til kommentar

Hvilken komplilator bruker du? For virker som det du skriver ut ikke er minneadressen med rett og slett "garbage". (At du ikke har gitt det noen verdi).

 

Dåg fungerer det helt fint i GCC.

 

Dåg er det litt skummelt det du prøver på her:

    q=b;
   for(i=0; i<MAX; i++)
   {
	    *q++ = *p++;
   }

 

Her lurer jeg litt på hva du egentlig tenkte? Ville endret det til

    q=b;
   for(i=0; i<MAX; i++)
   {
	    *q[i] = *p[i];
   }

Lenke til kommentar

Forandre q[0] til q[2].

Ser nå at det er noe rot med pekerene etter den forloopen jeg nevner i forrige post

for(i=0; i<MAX; i++)
{
   *q++ = *p++;
}

etter dette vil q ha adressen til q[MAX] og ikke q[0]. Noe som vil lage store problemer. Løses med å gjøre denne lille endringen:

q=b;
for(i=0; i<MAX; i++)
{
   *q++ = *p++;
}
q=b;

Vil legge til en interesant bemerkelse jeg nettop hadde. Jeg endre koden til følgende:

#include <stdio.h>
#define MAX 10
int main()
{
   int a[MAX];
   int b[MAX];
   int i;
   int *p;
   int *q;

   p=a;
   for(i=0; i<MAX; i++)
	    a[i]=i*2;
   q=b;
   for(i=0; i<MAX; i++)
   {
	    *q++ = *p++;
   }

   for(i=0; i<MAX; i++)
   {
    printf("%d\n",q[i]);
   }
}

 

og får da følgende output:

0

2

4

6

8

10

12

14

16

18

Som er det man ville forventet, selv om koden er helt feil. Noe som forklarer hvorfor det så riktig ut første gang jeg kjørte koden.

 

Årsaken til dette er at arrayene a og b ligger rett etter hverandre i minnet. Så når man trodde man skrev ut q[0] (som skulle være array b), skrev man egentlig ut q[max+0] som tilsvarer p[0], og dermed array a.

 

Dette ser man tydelig om jeg skriver ut minneadressene.

Endret av etse
Lenke til kommentar

There we go. :>

 

Kult triks:

 

23	 printf("%d\n",q[-8]);

 

For å utdype: koden og logikken din er i utgangspunktet helt riktig. Problemet er at du inkrementerer pekeren som forandrer verdien på den, så du er nødt til å "resette" den for å aksessere fra 0 igjen. Dette kan gjøres på flere måter. Her er to:

 

q = b;
q -= MAX; // funker siden det var dette du økte den med

 

Edit: kan legge ved noe mer info som kan være nyttig. Etse: hva kompilerte du med. O3? Uansett, det kan være flere grunner til at du får 0 der. Ene kan være at verdien som tilfeldigvis lå på minneplassen var 0. Mer sannsynlig er det at kompilatoren gjorde en memset( 0 ) på hele minneområdet før kjøring.

Endret av Lycantrophe
Lenke til kommentar

Edit: kan legge ved noe mer info som kan være nyttig. Etse: hva kompilerte du med. O3? Uansett, det kan være flere grunner til at du får 0 der. Ene kan være at verdien som tilfeldigvis lå på minneplassen var 0. Mer sannsynlig er det at kompilatoren gjorde en memset( 0 ) på hele minneområdet før kjøring.

Jeg så over koden en gang til. Og som nevnt over glemte jeg å tenke på at GCC har en tendens til å legge elementer på stacken rett etter hverandre. Og jeg skrev egentlig ut det andre arrayet.
Lenke til kommentar

Forandre q[0] til q[2].

Hva mente du med dette? Stemmer det ikke at det er q0 jeg printer fra?

 

Hvilken komplilator bruker du? For virker som det du skriver ut ikke er minneadressen med rett og slett "garbage". (At du ikke har gitt det noen verdi).

 

Dåg fungerer det helt fint i GCC.

 

Dåg er det litt skummelt det du prøver på her:

	q=b;
for(i=0; i<MAX; i++)
{
		*q++ = *p++;
}

 

Her lurer jeg litt på hva du egentlig tenkte? Ville endret det til

	q=b;
for(i=0; i<MAX; i++)
{
		*q[i] = *p[i];
}

Litt usikker på kompilator. Trodde det var GCC. Jeg bruker Code::blocs og det som følger med til den av kompilator. På linux.

Det andre eksempelet ditt ga kompileringsfeil:

Invalid type argument of unary * (have int).

Jeg synes det ser ut til at du øker arrayet q og arrayet p, men disse er jo pekere, ikke arrays?

 

 

Ser nå at det er noe rot med pekerene etter den forloopen jeg nevner i forrige post

for(i=0; i<MAX; i++)
{
*q++ = *p++;
}

 

etter dette vil q ha adressen til q[MAX] og ikke q[0]. Noe som vil lage store problemer. Løses med å gjøre denne lille endringen:

 

q=b;
for(i=0; i<MAX; i++)
{
*q++ = *p++;
}
q=b;

Stemmer stemmer. Eller q=&b[0]; som blir det samme, sant?

Jeg forstår nå hvorfor dette gikk galt. Men hvorfor fungerte det da for deg?

Lenke til kommentar

Hva mente du med dette? Stemmer det ikke at det er q0 jeg printer fra?

Nei. q++ øker verdien til pekeren (altså hvor den peker). Når løkken din er ferdig peker q på b[10], ikke b[0].

Litt usikker på kompilator. Trodde det var GCC. Jeg bruker Code::blocs og det som følger med til den av kompilator. På linux.

Det er nok gcc.

Det andre eksempelet ditt ga kompileringsfeil:

Invalid type argument of unary * (have int).

Jeg synes det ser ut til at du øker arrayet q og arrayet p, men disse er jo pekere, ikke arrays?

Det stemmer. q[5] "returnerer" en int, ikke en peker til. Det er det samme som å gjøre *(q+5). Det du har gjort er riktig, det er ikke i løkken feilen din er.

 

Stemmer stemmer. Eller q=&b[0]; som blir det samme, sant?

Jeg forstår nå hvorfor dette gikk galt. Men hvorfor fungerte det da for deg?

Ja, det vil bli det samme. Det fungerte nok for han fordi kompilatoren hans plasserte arrayene etterhverandre. Hadde det ikke blitt gjort hadde han også fått garbage.
Lenke til kommentar

[...]

Som er det man ville forventet, selv om koden er helt feil. Noe som forklarer hvorfor det så riktig ut første gang jeg kjørte koden.

[...]

 

Mens jeg som tydeligvis har et annet oppsett, får en helt annen out-print:

153392856

32767

153392904

32767

0

5

0

0

1625339757

32537

Lenke til kommentar

Stemmer stemmer. Eller q=&b[0]; som blir det samme, sant?

Jeg forstår nå hvorfor dette gikk galt. Men hvorfor fungerte det da for deg?

Problemer er at med det siste eksempelet så endrer du verdien til pekeren Q, Så når du skal skrive ut verdiene så har denne en helt annen verdi. Med andre ord, etter forloopen så vil q[0] ikke lenger være array b, men i stede array a.

 

Kan prøve å forklare hvorfor det fungerte for meg.

 

Lager først en tegning over minnet. Se for deg at minner ser noe slik ut før du begynner.

 

2238.jpg

 

I begynnelsen setter programmet av minne til arrayene A og B. For å ikke gjøre ting for vanskelige, har jeg valgt å bruke charater array (hvor hvert element tar 1 byte), og satt MAX til 8

 

Etter å ha satt av minnet, lar jeg også pekerene q og p peke på hvert sitt array

 

2242.jpg

 

Legg merke til at arrayene her ligger rett ved siden av hverandre, og at q[0] vil være verdien som ligger lagret på minneadresse 0x00012, mens p[0] vil være det som ligger på 0x00020.

 

La oss så gå gjennom den første for-loopen og fylle opp array A med verdier, minner vil da se ut som følger:

 

2243.jpg

 

Alt ser fortsatt helt fint ut. Og verdiene er bare lagt til array A slik vi ønsker. La oss nå gå gjennom den andre for-loopen.

 

2244.jpg

 

Her ser arrayene helt fine ut, men som du ser har verdiene som ligger lagret i Q og P endret seg. Q har nå adressen til første element i A, i stede for første element i B, mens P peker på noe minne som ikke er allokert

 

Dette betyr at når jeg nå prøver å skrive ut det som ligger på adressen lagret i Q, skriver jeg altså ut array A, i stede for Array B slik jeg ønsket. Og man får derfor kode som ser ut som det fungerer, men ikke fungerer helt som det skal.

 

Men da er spørsmålet, hvorfor fungerer det hos meg og ikke dere?

Vel, svaret er at ting trolig ligger allokert i minner litt annerledes hos dere. C garanterer ingenting om hvordan den legger ting i minnet. Og dette gjør at når man begynner å gjøre slike feil. Så vil man kunne få helt uventet oppførsel.

Lenke til kommentar

Men da er spørsmålet, hvorfor fungerer det hos meg og ikke dere?

Vel, svaret er at ting trolig ligger allokert i minner litt annerledes hos dere. C garanterer ingenting om hvordan den legger ting i minnet. Og dette gjør at når man begynner å gjøre slike feil. Så vil man kunne få helt uventet oppførsel.

Windows, Linux eller OS X? Hvilken gcc-versjon? Hvilke kompilatorflagg?
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...