Ich habe versucht, etwas mit Zeigern zu verstehen, also habe ich diesen Code geschrieben:
#include <stdio.h>
int main(void)
{
char s[] = "asd";
char **p = &s;
printf("The value of s is: %p\n", s);
printf("The direction of s is: %p\n", &s);
printf("The value of p is: %p\n", p);
printf("The direction of p is: %p\n", &p);
printf("The direction of s[0] is: %p\n", &s[0]);
printf("The direction of s[1] is: %p\n", &s[1]);
printf("The direction of s[2] is: %p\n", &s[2]);
return 0;
}
Beim Kompilieren mit gcc erhalte ich diese Warnungen:
$ gcc main.c -o main-bin -ansi -pedantic -Wall -lm
main.c: In function ‘main’:
main.c:6: warning: initialization from incompatible pointer type
main.c:9: warning: format ‘%p’ expects type ‘void *’, but argument 2 has type ‘char (*)[4]’
main.c:11: warning: format ‘%p’ expects type ‘void *’, but argument 2 has type ‘char **’
main.c:12: warning: format ‘%p’ expects type ‘void *’, but argument 2 has type ‘char ***’
(Die Flags für gcc sind, weil ich C89 sein muss)
Warum inkompatible Zeigertypen? Ist der Name eines Arrays nicht ein Zeiger auf sein erstes Element? Wenn also s ein Zeiger auf ‘a’ ist, &s muss ein sein char **, nein? Und warum erhalte ich die anderen Warnungen? Muss ich die Zeiger mit (void *) um sie auszudrucken?
Und beim Laufen bekomme ich so etwas:
$ ./main-bin
The value of s is: 0xbfb7c860
The direction of s is: 0xbfb7c860
The value of p is: 0xbfb7c860
The direction of p is: 0xbfb7c85c
The direction of s[0] is: 0xbfb7c860
The direction of s[1] is: 0xbfb7c861
The direction of s[2] is: 0xbfb7c862
Wie kann der Wert von s und seine Richtung (und natürlich der Wert von p) gleich sein?
James Curran
“s” ist kein “char*”, sondern ein “char[4]”. Und so ist “&s” kein “char**”, sondern eigentlich “ein Zeiger auf ein Array von 4 Zeichen”. Ihr Compiler behandelt “&s” möglicherweise so, als ob Sie “&s” geschrieben hätten[0]”, was ungefähr dasselbe ist, aber ein “char*”.
Wenn Sie “char** p = &s;” schreiben Sie versuchen zu sagen: „Ich möchte, dass p auf die Adresse des Dings gesetzt wird, das derzeit auf „asd“ zeigt. Aber derzeit gibt es nichts, was Punkte zu “asd”. Es gibt nur ein Array, das hält “asd”;
char s[] = "asd";
char *p = &s[0]; // alternately you could use the shorthand char*p = s;
char **pp = &p;
ein Array bedeutet auch eine zusammenhängende Speicheradresse eines bestimmten Typs, da s zerfällt zu einem Zeiger, wir könnten sagen, es ist ein Zeiger auf char* [first element of an array ]
– Cholthi Paul Ttiopic
23. September 2015 um 6:32 Uhr
@CholthiPaulTtiopic – Nein. Zuallererst sollte das lauten: “Wir könnten sagen, es ist ein Hinweis darauf char” (nicht char*). ABER, Sie können es als Zeiger auf verwenden char in einigen Fällen, aber das macht es nicht zu einem. “5.0” kann eine Ganzzahl sein, ist es aber nicht intobwohl Sie es an einigen Stellen verwenden können, die eine erfordern int.
– James Curran
23. September 2015 um 22:01 Uhr
Einzeln
Ja, Ihr Compiler erwartet void *. Wirf sie einfach auf void *.
/* for instance... */
printf("The value of s is: %p\n", (void *) s);
printf("The direction of s is: %p\n", (void *) &s);
Das ist falsch. Casting to void* verbirgt lediglich das Problem, löst es aber nicht.
– James Curran
13. Oktober 2008 um 14:46 Uhr
Mein erster Gedanke war, dass er nur Zahlen ausgeben wollte, um die Werte zu sehen, die der Compiler zugewiesen hatte, und eine Umwandlung in void würde es ihm ermöglichen, unabhängig von irgendwelchen Problemen in seinen Deklarationen. Aber ja, das vermeidet sicherlich das Problem.
– individuell
13. Oktober 2008 um 15:19 Uhr
Casting zu void * für Argumente zum %p Format in einer variadischen Funktion ist eigentlich erforderlich nach Sprachstandard.
– Jens
17. April 2011 um 10:54 Uhr
Dies ist einer der seltenen Fälle, in denen ein Casting in C wirklich notwendig ist.
– alk
12. August 2013 um 15:12 Uhr
Airsource Ltd
Wenn Sie den Namen eines Arrays als Argument an eine Funktion übergeben, wird dies so behandelt, als ob Sie die Adresse des Arrays übergeben hätten. Also sind &s und s identische Argumente. Siehe K&R 5.3. &s[0] ist dasselbe wie &s, da es die Adresse des ersten Elements des Arrays nimmt, was dasselbe ist wie die Adresse des Arrays selbst.
Für alle anderen, obwohl alle Zeiger im Wesentlichen Speicherplätze sind, werden sie immer noch typisiert, und der Compiler warnt davor, einen Zeigertyp einem anderen zuzuweisen.
void* p; besagt, dass p eine Speicheradresse ist, aber ich weiß nicht, was sich im Speicher befindet
char* s; besagt, dass s eine Speicheradresse ist und das erste Byte ein Zeichen enthält
char** ps; besagt, dass ps eine Speicheradresse ist und die vier Bytes dort (für ein 32-Bit-System) einen Zeiger vom Typ char* enthalten.
Das Zeigerargument void * wird hexadezimal ausgegeben (wie bei %#x oder %#lx). Es sollte ein Hinweis auf Nichtigkeit sein.
char* s = "asd";
char** p = &s;
printf("The value of s is: %p\n", s);
printf("The address of s is: %p\n", &s);
printf("The value of p is: %p\n", p);
printf("The address of p is: %p\n", &p);
printf("The address of s[0] is: %p\n", &s[0]);
printf("The address of s[1] is: %p\n", &s[1]);
printf("The address of s[2] is: %p\n", &s[2]);
Sie können Ihren Code ändern in:
Ergebnis:
Der Wert von s ist: 0x403f00
Die Adresse von s lautet: 0x7fff2df9d588
Der Wert von p ist: 0x7fff2df9d588
Die Adresse von p lautet: 0x7fff2df9d580[0] Die Adresse von S
lautet: 0x403f00[1] Die Adresse von S
lautet: 0x403f01[2] Die Adresse von S
lautet: 0x403f02 s == &sSie können den Wert (dh die Adresse) eines statischen Arrays nicht ändern. Technisch gesehen ist der Lvalue eines Arrays die Adresse seines ersten Elements. Somit
Benutzeravatar von fizzer
Fizzer
Scotts Benutzeravatar
Scott
char s[] = "asd";
Zeile ändern:
char *s = "asd";
zu:
und die Dinge werden klarer
Der Fehler wird verschwinden, aber nichts wird klarer, da Sie eine Erklärung des ursprünglichen Problems vermeiden.