Puntero C básico y confusión por referencia de paso.

Tengo el siguiente progtwig básico:

#include  void doit(char *c) { c = "world"; } int main() { char *c = "hello"; doit(c); printf("%s\n", c); return 0; } 

Yendo línea por línea:

  • c almacena la dirección a la cadena (secuencia de caracteres) a la que apunta
  • * c apunta a “hola” dentro de la función principal

Ahora cuando c (puntero) se pasa a la función que intenta modificarla. El valor modificado no está disponible dentro de main. ¿Por qué?

 #include  void doit(char **c) { *c = "world"; } int main() { char *c = "hello"; doit(&c); printf("%s\n", c); return 0; } 

funciona bien? Espero que el primer ejemplo funcione bien solo ya que estoy pasando doit(c) que ya es un puntero a la cadena que quiero modificar.

Es porque en la primera versión se pasa el puntero por valor . Eso significa que el puntero real de main se copia y en la función doit solo modifica la copia.

En la segunda versión, emula paso por referencia (C no tiene referencias adecuadas) al pasar un puntero al puntero.


Veamos si esto lo hace más claro para ti.

Para el primer progtwig, en la función main tiene un puntero c que apunta a la cadena literal "hello" :

 + -------- + + --------- +
 |  principal: c |  ----> |  "hola" |
 + -------- + + --------- +

Luego, cuando se pasa a la función, el puntero se copia, por lo que tiene esto:

 + -------- +
 |  principal: c |  -
 + -------- + \ + --------- +
               > -> |  "hola" |
 + -------- + / + --------- +
 |  doit: c |  -
 + -------- +

Después de cambiar el puntero en doit tienes esto:

 + -------- + + --------- +
 |  principal: c |  ----> |  "hola" |
 + -------- + + --------- +

 + -------- + + --------- +
 |  doit: c |  ----> |  "mundo" |
 + -------- + + --------- +

Para el segundo progtwig comienza lo mismo:

 + -------- + + --------- +
 |  principal: c |  ----> |  "hola" |
 + -------- + + --------- +

Pero luego cambia cuando llama usando un puntero al puntero:

 + -------- + + -------- + + --------- +
 |  doit: c |  ----> |  principal: c |  ----> |  "hola" |
 + -------- + + -------- + + --------- +

Luego, la anulación de la referencia c in doit le da el puntero c original de main , y al cambiarlo usted tiene

 + -------- + + -------- + + --------- +
 |  doit: c |  ----> |  principal: c |  ----> |  "mundo" |
 + -------- + + -------- + + --------- +

En el primer caso:

 void doit(char *c) 

Estás pasando puntero por valor. Y como sabemos que pasar algo por valor a función significa que la función no puede cambiar el valor original pasado.

En el primer caso está pasando una copia del puntero c para hacerlo. Como resultado de cualquier modificación que haga al puntero, no se reflejarán en la persona que llama. Cambia la ubicación a la que apunta la copia de c , pero la c original permanece sin cambios.

Como contraste en el segundo ejemplo, pasa un puntero al puntero y cuando cambia el valor al que apunta, cambia el puntero original c .