Forum: PC-Programmierung verständisfrage zu pointer auf array


von Jens (Gast)


Lesenswert?

Hallo,
ich habe eine frage zu einem pointer.
Ich habe zum testen folgenden Code geschrieben
1
  int a[12] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
2
3
    int *b;
4
    printf("adresse b: %p\n", (void*)b); 
5
    b = &a[4];
6
7
    printf("adresse a: %p\n", (void*)a);  
8
  printf("adresse b: %p\n", (void*)b);
9
  printf("adresse a0: %p\n", &a[0]);
10
  printf("adresse a4: %p\n", &a[4]);
11
  printf("wert a0: %i\n", a[0]);
12
  printf("wert a4: %i\n", a[4]);
13
  printf("wert b0: %i\n", b[0]);
14
  printf("wert b4: %i\n", b[4]);
15
  printf("setze a[4] auf 44\n");
16
  a[4] = 44;
17
  printf("wert b0: %i\n", b[0]);
18
  printf("groesse a: %u\n", sizeof(a));
19
  printf("groesse b: %u\n", sizeof(b));
20
  printf("wert b12: %i\n", b[12]);
21
  printf("wert a16: %i\n", b[16]);
22
  
23
    return 0;

die Ausgabe ist
1
adresse b: 00400080
2
adresse a: 0061FEEC
3
adresse b: 0061FEFC
4
adresse a0: 0061FEEC
5
adresse a4: 0061FEFC
6
wert a0: 1
7
wert a4: 5
8
wert b0: 5
9
wert b4: 9
10
setze a[4] auf 44
11
wert b0: 44
12
groesse a: 48
13
groesse b: 4
14
wert b12: 4198966
15
wert a16: 2

Da habe ich jetzt zwei Fragen zu.
warum sind die Adressen von a[0] und a[4] auch 0061FEEC? Wie bekomme ich 
die Adresse von den einzelnen elementen?
Warum ist b[12] ungleich a[16]? dass dort müll drinn steht ist mir klar, 
aber sollte nicht bei beiden das selbe drinn stehen? Greifen doch beide 
auf die selbe adresse zu?

von Holger (Gast)


Lesenswert?

Jens schrieb:
> [...]
> Da habe ich jetzt zwei Fragen zu.
> warum sind die Adressen von a[0] und a[4] auch 0061FEEC? Wie bekomme ich
> die Adresse von den einzelnen elementen?

Die Adressen von a[0] und a[4] sind nicht identisch. Wenn du genau 
hinschaust (am besten die HEX Zahlen mal in Kleinbuchstaben schreiben) 
siehst du das sie unterschiedlich sind:

[...]
adresse a0: 0061feec
adresse a4: 0061fefc
[...]

Das erste Element des Arrays liegt an der Speicherstelle des Speichers, 
der dem Array zugewiesen wurde. Wenn du also "b" auf "a" zeigen lassen 
würdest, würde "b" auf das erste Element des Ararys zeigen. Beide 
Anweisungen sind also identisch:
1
b = a;
2
b = &a[0];

> Warum ist b[12] ungleich a[16]? dass dort müll drinn steht ist mir klar,
> aber sollte nicht bei beiden das selbe drinn stehen? Greifen doch beide
> auf die selbe adresse zu?

Vermutlich weil du nicht "a[16]" ausgibst, sondern zweimal "b[12]" 
(Tippfehler).

Gruß,

Holger

von Holger (Gast)


Lesenswert?

Jens schrieb:
> ("wert b12: %i\n", b[12]);
>   printf("wert a16: %i\n", b[16])

Holger schrieb:
>> Warum ist b[12] ungleich a[16]? dass dort müll drinn steht ist mir klar,
>> aber sollte nicht bei beiden das selbe drinn stehen? Greifen doch beide
>> auf die selbe adresse zu?
>
> Vermutlich weil du nicht "a[16]" ausgibst, sondern zweimal "b[12]"
> (Tippfehler).

Sorry, ich meinte das du zweimal auf den "b"-Zeiger zugreifst (b[12] und 
b[16]) anstatt bei der zweiten Ausgabe das Array zu benutzen (a[16]).

von Jens (Gast)


Lesenswert?

Holger schrieb:
> [...]
> adresse a0: 0061feec
> adresse a4: 0061fefc
> [...]

Tatsächlich, ist mir nicht aufgefallen. wie kann man es denn klein 
printen?

Holger schrieb:
> Vermutlich weil du nicht "a[16]" ausgibst, sondern zweimal "b[12]"
> (Tippfehler).

Auch hier tatsächlich :). es war ein Tippfehler. wenn ich jetzt steht in 
beiden das selbe drinn.

Beseten dank :)

von Rolf M. (rmagnus)


Lesenswert?

Jens schrieb:
> Holger schrieb:
>> [...]
>> adresse a0: 0061feec
>> adresse a4: 0061fefc
>> [...]
>
> Tatsächlich, ist mir nicht aufgefallen. wie kann man es denn klein
> printen?

Mir wären keine Optionen für %p bekannt. Da entscheidet der Compiler, 
wie die Ausgabe aussieht.

> Holger schrieb:
>> Vermutlich weil du nicht "a[16]" ausgibst, sondern zweimal "b[12]"
>> (Tippfehler).
>
> Auch hier tatsächlich :). es war ein Tippfehler. wenn ich jetzt steht in
> beiden das selbe drinn.

Wobei das nicht zwingend so sein muss. Denn beim Zugriff ausßerhalb des 
Arrays kommt nicht nur "müll" raus, sondern das ganze Verhalten ist 
undefiniert. Da kann alles passieren, und durch Optimierungen können 
ggf. auch recht unerwartete Effekte auftreten. Ein Absturz des Programms 
wäre natürlich auch möglich.

von Holger (Gast)


Lesenswert?

Jens schrieb:
> Tatsächlich, ist mir nicht aufgefallen. wie kann man es denn klein

Du kannst anstatt %p einfach %x bzw. %X benutzen (im ersten Fall ist die 
Ausgabe mit Klein- im zweiten mit Großbuchstaben).

von Alexander S. (alesi)


Lesenswert?

Jens schrieb:
1
int a[12] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

Nur am Rande: Hier würde ich
1
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
schreiben. Der Compiler berechnet die Größe und es ist automatisch 
konsistent.

von Rolf M. (rmagnus)


Lesenswert?

Holger schrieb:
> Jens schrieb:
>> Tatsächlich, ist mir nicht aufgefallen. wie kann man es denn klein
>
> Du kannst anstatt %p einfach %x bzw. %X benutzen (im ersten Fall ist die
> Ausgabe mit Klein- im zweiten mit Großbuchstaben).

Das hängt dann allerdings vom System ab, ob das passt. %p ist eigentlich 
schon das richtige für Zeiger.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Rolf M. schrieb:
> Holger schrieb:
>> Jens schrieb:
>>> Tatsächlich, ist mir nicht aufgefallen. wie kann man es denn klein
>>
>> Du kannst anstatt %p einfach %x bzw. %X benutzen (im ersten Fall ist die
>> Ausgabe mit Klein- im zweiten mit Großbuchstaben).
>
> Das hängt dann allerdings vom System ab, ob das passt.

Auf 64-Bit-Plattformen mit 32-Bit-int-Typ werden damit die höherwertigen
32 Bit des Pointers bei der Ausgabe abgeschnitten.

> %p ist eigentlich schon das richtige für Zeiger.

Oder alternativ %"PRIxPTR" & Co. Damit kann man zwischen verschiedenen
Darstellungen der Hexzahl wählen:

1
#include <stdio.h>
2
#include <inttypes.h>
3
4
int a[12] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
5
6
int main(void) {
7
  printf("%%p          -> %p\n", a);                        // ok
8
  printf("%%x          -> %x\n", a);                        // Warnung
9
  printf("%%X          -> %X\n", a);                        // Warnung
10
  printf("%%\"PRIxPTR\"  -> %"PRIxPTR"\n", (uintptr_t)a);   // ok
11
  printf("%%\"PRIXPTR\"  -> %"PRIXPTR"\n", (uintptr_t)a);   // ok
12
  printf("%%#\"PRIxPTR\" -> %#"PRIxPTR"\n", (uintptr_t)a);  // ok
13
  printf("%%#\"PRIXPTR\" -> %#"PRIXPTR"\n", (uintptr_t)a);  // ok
14
}


Ausgabe:
1
%p          -> 0x563e5392c040
2
%x          -> 5392c040
3
%X          -> 5392C040
4
%"PRIxPTR"  -> 563e5392c040
5
%"PRIXPTR"  -> 563E5392C040
6
%#"PRIxPTR" -> 0x563e5392c040
7
%#"PRIXPTR" -> 0X563E5392C040

von Rolf M. (rmagnus)


Lesenswert?

Yalu X. schrieb:
>> Das hängt dann allerdings vom System ab, ob das passt.
>
> Auf 64-Bit-Plattformen mit 32-Bit-int-Typ werden damit die höherwertigen
> 32 Bit des Pointers bei der Ausgabe abgeschnitten.

Oder auch die niederwertigen, je nach Endianness. Und die Anzeige bringt 
auch nix mehr, wenn das Zeigerformat etwas komplizierter ist als einfach 
nur ein einzelner Hex-Wert. Kommt heut zugegebenermaßen wohl nicht mehr 
so oft vor.

von Roland (Gast)


Lesenswert?

Rolf M. schrieb:
> Kommt heut zugegebenermaßen wohl nicht mehr
> so oft vor

Warum nicht?

von Rolf M. (rmagnus)


Lesenswert?

Roland schrieb:
> Rolf M. schrieb:
>> Kommt heut zugegebenermaßen wohl nicht mehr
>> so oft vor
>
> Warum nicht?

Ich würde sagen, weil man in der Regel heute eher mit einem 
durchgängigen linearen Adressraum arbeitet und nicht wie z.B. noch unter 
DOS mit seiner Unterteilung in Segement- und Offset-Register und sehr 
starker Überlappung. Da gab es noch Zeigerwerte, die dann z.B: 1000:A010 
heißen. Und 1001:A000 war zwar ein anderer Zeigerwert, der aber auf die 
selbe physische Adresse zeigte.

von Gaehn... (Gast)


Lesenswert?

Jens schrieb:
> int *b;
>     printf("adresse b: %p\n", (void*)b);

Wird hier nicht auf den Inhalt der Adresse zugegriffen?

von Dirk B. (dirkb2)


Lesenswert?

Gaehn... schrieb:
> Jens schrieb:
>> int *b;
>>     printf("adresse b: %p\n", (void*)b);
>
> Wird hier nicht auf den Inhalt der Adresse zugegriffen?

Da wird nicht auf den Inhalt der Adresse zugegriffen.

Das ist ein Cast (Typumwandlung)

von Gaehn... (Gast)


Lesenswert?

Hast natürlich Recht, ist noch zu früh.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.