Drucken von Zeigern in C

Lesezeit: 5 Minuten

Benutzeravatar von alcuadrado
Alcuarado

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?

Benutzeravatar von James Curran
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

Benutzeravatar von indiv
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

Benutzeravatar von Airsource Ltd
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.

vgl http://www.oberon2005.ru/paper/kr_c.pdf (E-Book-Version von K&R)

Benutzeravatar von 4pie0
4pie0

Es ist kein Hinweis auf Charakter char* aber ein Zeiger auf ein Array von 4 Zeichen: char* [4]. Mit g++ kompiliert es nicht:

main.cpp: In Funktion ‘int main(int, char**)’: main.cpp:126: Fehler: kann ‘char[4]

‘ zu ‘char**’ bei der Initialisierung Außerdem die Linux-Manpagessagt

:

p

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

.  Es ist nur eine Eigenart der Sprache.
Benutzeravatar von fizzer

Fizzer

Normalerweise wird es als schlechter Stil betrachtet, unnötigerweise Zeiger auf (void*) zu werfen.  Hier benötigen Sie jedoch die Umwandlungen in (void*) für die printf-Argumente, da printf variadisch ist.  Der Prototyp teilt dem Compiler nicht mit, in welchen Typ die Zeiger an der Aufrufstelle konvertiert werden sollen.
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.

    – James Curran

1412170cookie-checkDrucken von Zeigern in C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy