C: Método que maneja el puntero.

Me preguntaba por qué el primer método no funciona, pero el segundo sí:

// primer método

int create_node(struct node *create_me, int init){ create_me = malloc(sizeof(struct node)); if (create_me == 0){ perror("Out of momory in ''create_node'' "); return -1; } (*create_me).x = init; (*create_me).next = 0; return 1; } int main( void ){ struct node *root; create_node(root, 0); print_all_nodes(root); } 

Ok, aquí la función print_all_nodes me dice que la raíz no se ha inicializado. Ahora segundo método que funciona bien:

 struct node* create_node(struct node *create_me, int init){ //<------- create_me = malloc(sizeof(struct node)); if (create_me == 0){ perror("Out of momory in ''create_node'' "); exit(EXIT_FAILURE); } (*create_me).x = init; (*create_me).next = 0; return create_me; //<--------- } int main( void ){ struct node *root; root = create_node(root, 0); //<--------------- print_all_nodes(root); } 

En mi entendimiento (hablando del método 1), cuando le doy a la función create_node el puntero al nodo raíz, en realidad cambia la x y la next raíz.

Como cuando haces:

 void change_i(int* p){ *p = 5; } int main( void ){ int i = 2; printf("%d\n", i); change_i(&i); printf("%d", i); } 

En realidad cambia i . ¿Captar la idea? ¿Puede alguien compartir sus conocimientos conmigo por favor!

Necesita un puntero para apuntar, no solo un puntero.

Si desea cambiar una variable en otra función, debe enviar un puntero a esa variable. Si la variable es una variable entera, envíe un puntero a esa variable entera. Si la variable es una variable de puntero, envíe un puntero a esa variable de puntero.

Usted está diciendo en su pregunta que “cuando le doy a la función create_node el puntero al nodo raíz, entonces realmente cambia la x y la next raíz”. Tu redacción me hace sospechar que hay cierta confusión aquí. Sí, estás cambiando los contenidos de x y next , pero no de root . root no tiene x y la next , ya que la root es un puntero que apunta a una estructura que contiene una x y la next . Su función no cambia el contenido de la root , ya que lo que obtiene su función es solo una copia de ese puntero.

Cambios en su código:

 int create_node(struct node **create_me, int init) { *create_me = malloc(sizeof(struct node)); if (*create_me == 0){ perror("Out of momory in ''create_node'' "); return -1; } (*create_me)->x = init; (*create_me)->next = 0; return 1; } int main( void ){ struct node *root; create_node(&root, 0); print_all_nodes(root); } 

Necesitas hacer algo como create_node(&root, 0); y luego acceder a ella como un ** en el método llamado. C no tiene concepto de paso por referencia. Necesitas dar la dirección para acceder a ella en otra función.

Esta es una cuestión del scope de sus variables. En el primer ejemplo, cuando suministra un puntero a un nodo , puede cambiar ese nodo y los cambios persistirán después. Sin embargo, su malloc cambia este puntero, que se descarta una vez que finaliza el ámbito (su función).

En el segundo ejemplo, devuelve este puntero y, por lo tanto, lo copia antes de ser descartado.

Esto correspondería a esto en su ejemplo dado no. 3:

 void change_i(int* p){ *p = 5; // you can 'change i' p = 5 // but not p (pointer to i), as it is local -> gets discarded after following '}' } 

cuando le doy a la función create_node el puntero al nodo raíz, entonces realmente cambia la x y la siguiente de la raíz.

No le da a la función create_node() (en ambas versiones) un puntero al nodo raíz porque, en primer lugar, no tiene el nodo raíz.

La declaracion:

 struct node *root; 

crea la root , de tipo struct node * y la deja sin inicializar. root es una variable que puede almacenar la dirección en la memoria de un valor de struct node (un puntero a un valor de struct node ). Pero el código no crea ningún valor de struct node y el valor de la root es simplemente basura.

A continuación, ambas versiones de la función create_node() reciben el valor de basura de la root en el parámetro create_me como consecuencia de la llamada:

 create_node(root, 0); 

Lo primero que hacen ambas implementaciones de create_node() es ignorar el valor que reciben en el parámetro create_me (sea válido o no), crear un valor de tipo struct node y almacenar su dirección en create_me .

Las líneas:

 (*create_me).x = init; (*create_me).next = 0; 

ponga algunos valores en las propiedades del objeto de struct node recién asignado.

La primera versión de la función devuelve 1 e ignora el valor almacenado en create_me . Al ser un parámetro de función (una variable local de la función), su valor se descarta y se pierde para siempre. El código acaba de crear una pérdida de memoria: un bloque de memoria que está asignado pero inaccesible porque no hay un puntero a él. ¡No hagas esto!

La segunda versión de la función devuelve el valor de create_me (es decir, la dirección del nuevo valor asignado de type struct node ). El código que llama ( root = create_node(root, 0); ) almacena el valor devuelto por la función en la variable root (reemplazando el valor de basura usado para inicializar esta variable).

¡Gran éxito! La segunda versión de la función create_node() crea un nuevo objeto struct node , inicializa sus propiedades y devuelve la dirección del nuevo objeto para ser almacenado y / o procesado. No olvides llamar free(root) cuando el objeto ya no sea necesario.