2010-07-28 11 views
7

Cuando hablamos de desreferencia, ¿es necesario que se use *? Si se accede a la referente del puntero de alguna otra manera, ¿se puede considerar como la eliminación de referencias puntero o no, como:¿Por qué printf ("% s", ptr) puede desreferenciar un vacío *?

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

Esa es la primera parte de mi pregunta.

Ahora, si printf("%s" , ptr) es un ejemplo de desreferenciación, responda amablemente la siguiente parte de mi pregunta también.

K & R dice

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

Por lo tanto,

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

no compila, compilador da error

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

Pero si usamos

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

Compila y funciona. Lo que significa que el puntero void puede ser desreferenciado - tenemos el puntero del objeto al que se refiere.
Si ese es el caso, entonces, ¿qué significa K & R cita arriba en este contexto?

Gracias por su tiempo.

+1

No veo dónde está desreferenciando 'void * 'con éxito. Por favor vuelve a leer tu código. – leppie

Respuesta

9

No. lo que tiene es "comportamiento indefinido": el estándar de lenguaje C no dice lo que debería suceder. En su caso, "funciona", pero para otro usuario/compilador/plataforma podría no funcionar. Su declaración:

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

es equivalente a:

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

y es igualmente indefinido.

+0

Entiendo tu punto. Gracias. ¿Qué hay de la primera parte de la pregunta? ¿'Printf ("% s ", ptr)' también se considera desreferenciación de un puntero? –

+1

@andrew printf() sin duda tendrá que eliminar la referencia del puntero para hacer lo que hace para el formateador "% s". OTOH, si usaste el formateador "% p" en el mismo puntero, no se necesita deferencia. –

+0

No sé cómo el estándar define 'printf' o si me falta algo, pero es concebible que' void * 'se transfiera a' char * ', ya que' printf' puede inferir que es un cadena por el '% s'. Por otra parte, el problema podría ser un problema vararg. No tengo ganas de investigarlo. –

0

En el ejemplo dado:

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

Lo que está pasando, en el primer printf, el valor de 'c' se pasa desde dereferencing el puntero char, printf sólo sabe que le dio un char debido a la %c etiqueta de formato.

Ahora, un void* es solo un puntero sin formato que tiene un tipo desconocido, no puede desreferenciarlo porque el compilador no sabe qué tipo leer a menos que lo lance a otra cosa.

En la segunda impresión, se pasa el puntero void*. printf solo lo ve como un número simple, y no tiene idea de lo que es hasta que lee la etiqueta de formato dada. Al usar %s, le está diciendo a la función printf que pasó en realidad en char*, por lo que la arroja en consecuencia y la lee correctamente como una cadena, es decir, desreferencia un puntero char*, no un puntero void*.

Es un código válido, siempre que el puntero void* apunta a una matriz char terminada en nulo. Si el puntero void* apunta a algo diferente, la función printf intentará leerlo como un puntero char* (si especifica %s) y provocará un comportamiento no definido.

Un mal ejemplo diferente:

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

No se puede eliminar la referencia de un entero cualquiera, pero me dijeron printf que es un char*, por lo que funciona.

Cuestiones relacionadas