2010-07-28 4 views
7

Wenn wir über Dereferenzierung sprechen, ist es notwendig, dass * darin verwendet wird? Wenn wir den referenten des Zeigers auf anderer Weise zugreifen, kann es als dereferencing einen Zeiger oder nicht in Betracht gezogen werden, wie:Warum kann printf ("% s", ptr) eine Lücke dereferenzieren *?

char *ptr = "abc" ; 
printf("%c" , *ptr); // Here pointer is dereferenced. 
printf("%s" , ptr); // What about this one? 

, dass der erste Teil meiner Frage ist.

Wenn nun printf("%s" , ptr) ein Beispiel für Dereferenzierung ist, dann bitte den folgenden Teil meiner Frage beantworten.

K & R sagt

a "pointer to void" is used to hold any type of pointer but cannot be dereferenced itself

Daher

char a = 'c' ; 
char *p = &a ; 
void *k = &a; 
printf("\n%c\n" , *p); 
printf("\n%c\n" , *k); 

lässt sich nicht kompilieren, gibt complier Fehler

In function ‘main’: warning: dereferencing ‘void *’ pointer error: invalid use of void expression

Aber wenn wir verwenden

char *a = "c" ; 
char *p = a ; 
void *k = a; 
printf("\n%c\n" , *p); 
printf("\n%s\n" , k); 

Es kompiliert und funktioniert. Was bedeutet, dass der Zeiger auf den Zeiger dereferenziert werden kann - wir haben den Objektzeiger, auf den er sich bezieht.
Wenn das der Fall ist, was bedeutet K & R oben genannten Zitat in diesem Zusammenhang?

Danke für Ihre Zeit.

+1

Ich sehe nicht, wo Sie 'void *' erfolgreich dereferenzieren. Bitte lesen Sie Ihren Code erneut. – leppie

Antwort

9

Nein, was Sie haben, ist "undefined Verhalten" - der C-Standard sagt nicht, was passieren soll. In Ihrem Fall "funktioniert" es, aber für einen anderen Benutzer/Compiler/Plattform nicht. Ihre Aussage:

printf("\n%s\n" , k); 

entspricht:

int k = 42; 
printf("\n%s\n" , k); 

und ist ebenso nicht definiert.

+0

Ich habe deinen Standpunkt verstanden. Vielen Dank. Was ist mit dem ersten Teil der Frage? Wird 'printf ("% s ", ptr)' auch als Dereferenzierung eines Zeigers betrachtet? –

+1

@andrew printf() muss sicherlich den Zeiger dereferenzieren, um das für den Formatierer "% s" zu tun. OTOH, wenn Sie den Formatierer "% p" für denselben Zeiger verwendet haben, ist keine Abweichung erforderlich. –

+0

Ich weiß nicht, wie der Standard 'printf' definiert oder ob ich etwas vermisse, aber es ist denkbar, dass das' void * 'in ein' char * 'umgewandelt wird, da' printf' daraus folgern kann, dass es sich um ein string mit dem '% s'. Andererseits könnte das Problem ein vararg Problem sein. Ich möchte nicht hinein graben. –

0

Im Beispiel gegeben:

char *a = "c"; 
char *p = a; 
void *k = a; 
printf("\n%c\n" , *p); 
printf("\n%s\n" , k); 

Was geschieht, in der ersten printf, der Wert ‚c‘ in von dereferencing den char Zeiger übergeben wird, printf nur weiß, dass Sie es eine char gab wegen der %c Format-Tag.

Jetzt ist ein void* nur ein unformatierter Zeiger, der einen unbekannten Typ hat, Sie können ihn nicht dereferenzieren, weil der Compiler nicht weiß, welchen Typ er liest, wenn Sie ihn nicht auf etwas anderes anwenden.

Im zweiten printf wird der void* Zeiger übergeben. printf sieht es nur als eine einfache Zahl, und hat keine Ahnung was es ist, bis es das Formatierungs-Tag liest. Wenn Sie %s verwenden, sagen Sie die printf-Funktion, die Sie tatsächlich in char* übergeben haben, so dass es es entsprechend umwandelt und ordnungsgemäß als Zeichenfolge liest, d. H. Es referenziert einen char* Zeiger - nicht einen void* Zeiger.

Es ist ein gültiger Code, solange der Zeiger void* auf ein nullterminiertes char Array zeigt. Wenn der Zeiger void* auf etwas anderes zeigt, versucht die printf Funktion immer noch, es als char* Zeiger zu lesen (wenn Sie %s angeben) und nicht definiertes Verhalten verursachen.

Ein anderes schlechtes Beispiel:

char *a = "ce"; 
int b = (int)a; 
printf("\n%s\n" , b); 

Sie können nicht dereferenzieren eine ganze Zahl entweder, aber ich sagte printf, dass es ein char* ist, so dass es funktioniert.