Creación de una lista vinculada de n longitud -- ampo con linked-list camp codereview Relacionados El problema

Creating a linked list of n length


4
vote

problema

Español

Escribí este código de trabajo para crear una lista vinculada de una longitud dada e imprimir los valores de cada nodo.

  #include <stdlib.h> //NULL #include <stdio.h>  //printf  typedef struct Node {     int val;     struct Node* next; } node;  node* make_ll(int len){     node* head = malloc(sizeof(node));     node* cur = head;     for (int i = 0; i < len; i++) {         cur->val = i;         cur->next = (i < (len - 1)) ? malloc(sizeof(node)) : NULL;         cur = cur->next;     }     return head; }  void print_ll(node* head){     node* cur = head;     while (cur != NULL) {         printf("Node: %d @ %p ", cur->val, cur);         cur = cur->next;     } }  int main(){     node* ll = make_ll(4);     print_ll(ll);     free(ll); }   

Salida:

  Node: 0 @ 0x81b010 Node: 1 @ 0x81b030 Node: 2 @ 0x81b050 Node: 3 @ 0x81b070   

Me pregunto si hay una forma práctica de escribir make_ll() para que, en lugar de verificar si hemos llegado al último nodo deseado en cada pasada del for Bucle y configuración unzip(File, File, Charset)0 En consecuencia, como se hace aquí con la línea 14:

  unzip(File, File, Charset)1  

Podemos simplemente unzip(File, File, Charset)2 para cada nodo "Siguiente" hasta el último, configurando IT EXCHIPE a unzip(File, File, Charset)3 .

Soy nuevo en C, en su mayoría influenciado por Python, y las cosas que no intenté en vano fueron el resultado de mi ignorancia de la diferencia de las lenguas en las reglas de alcance. Probablemente sería ruidoso tratar de reproducirlos aquí.

¿Cualquier puntero en la dirección correcta?

Original en ingles

I wrote this working code to create a linked list of a given length and print each node's values.

#include <stdlib.h> //NULL #include <stdio.h>  //printf  typedef struct Node {     int val;     struct Node* next; } node;  node* make_ll(int len){     node* head = malloc(sizeof(node));     node* cur = head;     for (int i = 0; i < len; i++) {         cur->val = i;         cur->next = (i < (len - 1)) ? malloc(sizeof(node)) : NULL;         cur = cur->next;     }     return head; }  void print_ll(node* head){     node* cur = head;     while (cur != NULL) {         printf("Node: %d @ %p\n", cur->val, cur);         cur = cur->next;     } }  int main(){     node* ll = make_ll(4);     print_ll(ll);     free(ll); } 

Output:

Node: 0 @ 0x81b010 Node: 1 @ 0x81b030 Node: 2 @ 0x81b050 Node: 3 @ 0x81b070 

I'm wondering if there's a practical way to write make_ll() so that, rather than checking if we've reached the last desired node on every pass of the for loop and setting cur->next accordingly, as done here with line 14:

cur->next = (i < (len - 1)) ? malloc(sizeof(node)) : NULL; 

we can simply malloc() for each "next" node until the last, setting it equal to NULL.

I'm new to C, mostly influenced by Python, and the things I tried to no avail were the result of my ignorance of the languages' difference in scope rules. It would probably be noisy to try to reproduce them here.

Any pointers in the right direction?

     

Lista de respuestas

2
 
vote
vote
La mejor respuesta
 

Si hay una forma práctica de escribir make_ll () ... podemos simplemente malloc () para cada nodo "siguiente" hasta el último, configurándolo igual a nulo.

Use un nodo de cabeza temporal. Esto también maneja los casos cuando i <= 0 al devolver NULL , a diferencia del código de OP que abandona el nodo de la cabeza ininitorizado.

  node* make_ll(int len){   node head;  // Code only populates the next field.   head.next = NULL;   node* cur = &head;   for (int i = 0; i < len; i++) {     cur->next = malloc(sizeof *(cur->next));     assert(cur->next);     cur = cur->next;     cur->val = i;     cur->next = NULL;   }   return head.next; }   

Otras notas

AVISO CÓMO EL TAMAÑO DE ABAJO malloc() funciona sin saber siquiera saber el tipo del puntero. Este es menos error propenso y más fácil de mantener.

  // some_pointer = malloc(sizeof(some_type)); some_pointer = malloc(sizeof *some_pointer);   

Utilice el tipo de coincidencia con el especificador para evitar el comportamiento indefinido: void * CON "%p" .

  printf("Node: %d @ %p ", cur->val, (void *) cur);   

MENOR: Cuando una función no altera los objetos que se "apuntan", considere usar const a 1) indicar que no hay cambios 2) Permitir pasar un puntero a una lista constante enlazada (esto es raro con listas vinculadas)

  void print_ll(const node* head) {     const node* cur = head;     while (cur != NULL) {         printf("Node: %d @ %p ", cur->val, (const void *) cur);         cur = cur->next;     } }   
 

if there's a practical way to write make_ll() ... we can simply malloc() for each "next" node until the last, setting it equal to NULL.

Use a temporary head node. This also handles cases when i <= 0 by returning NULL, unlike OP's code that leaves the head node uninitialized.

node* make_ll(int len){   node head;  // Code only populates the next field.   head.next = NULL;   node* cur = &head;   for (int i = 0; i < len; i++) {     cur->next = malloc(sizeof *(cur->next));     assert(cur->next);     cur = cur->next;     cur->val = i;     cur->next = NULL;   }   return head.next; } 

Other notes

Notice how the below malloc() size works without even knowing the type of the pointer. This is less error prone and easier to maintain.

// some_pointer = malloc(sizeof(some_type)); some_pointer = malloc(sizeof *some_pointer); 

Use matching type with the specifier to avoid undefined behavior: void * with "%p".

printf("Node: %d @ %p\n", cur->val, (void *) cur); 

Minor: When a function does not alter objects that are "pointed", consider using const to 1) indicate no change 2) allow passing a pointer to a constant linked list (this is rare with linked lists)

void print_ll(const node* head) {     const node* cur = head;     while (cur != NULL) {         printf("Node: %d @ %p\n", cur->val, (const void *) cur);         cur = cur->next;     } } 
 
 
 
 
3
 
vote

Desnudo NULL0 Llamadas

Tenga en cuenta que NULL1 simplemente asigna la memoria: no tiene garantías sobre lo que contiene la memoria recién asignada. Por esa razón, es mejor escribir una función que asigna e inicializa un nuevo objeto, es decir:

  NULL2  

Ahora use NULL3 donde está utilizando NULL4 directamente.

NULL5

En primer lugar, ¿su NULL6 trabaja para len = 0?

Para la comparación, aquí hay una solución recursiva para NULL7 :

  NULL8  

Y aquí hay una forma en que transformaría esto en un bucle que evita la revisión doble de la condición de salida:

  NULL9  

La idea es realizar un seguimiento del último nodo en la cadena, por lo que puede actualizar su campo 998877666655443320 cuando crea un nuevo nodo.

 

naked malloc calls

Note that malloc() simply allocates memory - you have no guarantees about what the newly allocated memory contains. For that reason it is better to write a function which both allocates and initializes an new object, i.e.:

node* newNode(int v) {   node* p = (node*) malloc( sizeof(node) );   // assume malloc never fails   p->val = v;   p->next = NULL;   return p; } 

Now use newNode() where you are using malloc() directly.

make_ll

First of all, does your make_ll work for len = 0?

For comparison, here is a recursive solution for make_ll:

node* make_ll(int len) {   if (len <= 0) {     return NULL;        // a list of length 0   } else {     node *tail = make_ll(len-1);     node *head = newNode(len);     head->next = tail;     return head;   } } 

And here is a way I would transform this into a loop which avoids double checking the exit condition:

node* make_ll(int len) {   if (len <= 0) {     return NULL;   }   node* head = newNode(len);   node* last = head;   for (; len > 0; --len) {     node* n = newNode(len);     last->next = n;     last = n;    }   return head; } 

The idea is to keep track of the last node in the chain so you can update its next field when you create a new node.

 
 
         
         
1
 
vote

Formato de la cadena MISMATCH

GCC me advierte:

  node* make_ll(int len){   node head;  // Code only populates the next field.   head.next = NULL;   node* cur = &head;   for (int i = 0; i < len; i++) {     cur->next = malloc(sizeof *(cur->next));     assert(cur->next);     cur = cur->next;     cur->val = i;     cur->next = NULL;   }   return head.next; } 1  

Necesita fundir node* make_ll(int len){ node head; // Code only populates the next field. head.next = NULL; node* cur = &head; for (int i = 0; i < len; i++) { cur->next = malloc(sizeof *(cur->next)); assert(cur->next); cur = cur->next; cur->val = i; cur->next = NULL; } return head.next; } 2 al tipo correcto cuando se usa en node* make_ll(int len){ node head; // Code only populates the next field. head.next = NULL; node* cur = &head; for (int i = 0; i < len; i++) { cur->next = malloc(sizeof *(cur->next)); assert(cur->next); cur = cur->next; cur->val = i; cur->next = NULL; } return head.next; } 3 , porque es una función de varargs.

Fugas de memoria

Informes de Valgrind:

  node* make_ll(int len){   node head;  // Code only populates the next field.   head.next = NULL;   node* cur = &head;   for (int i = 0; i < len; i++) {     cur->next = malloc(sizeof *(cur->next));     assert(cur->next);     cur = cur->next;     cur->val = i;     cur->next = NULL;   }   return head.next; } 4  

Eso es porque solo soltamos el nodo principal de la lista; Los otros nodos todavía están asignados, pero ya no se pueden alcanzar. Tenemos que pasar por la lista y eliminar todos los nodos:

  node* make_ll(int len){   node head;  // Code only populates the next field.   head.next = NULL;   node* cur = &head;   for (int i = 0; i < len; i++) {     cur->next = malloc(sizeof *(cur->next));     assert(cur->next);     cur = cur->next;     cur->val = i;     cur->next = NULL;   }   return head.next; } 5  

Utilice que en lugar de node* make_ll(int len){ node head; // Code only populates the next field. head.next = NULL; node* cur = &head; for (int i = 0; i < len; i++) { cur->next = malloc(sizeof *(cur->next)); assert(cur->next); cur = cur->next; cur->val = i; cur->next = NULL; } return head.next; } 6 .

Const-Corrección

La función "Imprimir" debe estar clara que no modificará la lista:

  node* make_ll(int len){   node head;  // Code only populates the next field.   head.next = NULL;   node* cur = &head;   for (int i = 0; i < len; i++) {     cur->next = malloc(sizeof *(cur->next));     assert(cur->next);     cur = cur->next;     cur->val = i;     cur->next = NULL;   }   return head.next; } 7  

No asuma que la asignación tendrá éxito

SIEMPRE Pruebe el puntero devuelto desde node* make_ll(int len){ node head; // Code only populates the next field. head.next = NULL; node* cur = &head; for (int i = 0; i < len; i++) { cur->next = malloc(sizeof *(cur->next)); assert(cur->next); cur = cur->next; cur->val = i; cur->next = NULL; } return head.next; } 8 malloc()29 malloc()30

código> Antes de usarlo.
 

Format string mismatch

GCC warns me:

104278.c:23:29: warning: format xe2x80x98%pxe2x80x99 expects argument of type xe2x80x98void *xe2x80x99, but argument 3 has type xe2x80x98node *xe2x80x99 {aka xe2x80x98struct Node *xe2x80x99} [-Wformat=]          printf("Node: %d @ %p\n", cur->val, cur);                             ~^               ~~~ 

You need to cast cur to the correct type when using it in printf(), because it's a varargs function.

Memory leak

Valgrind reports:

==1612== 48 (16 direct, 32 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2 ==1612==    at 0x48357BF: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==1612==    by 0x10919C: make_ll (104278.c:14) ==1612==    by 0x109227: main (104278.c:29) 

That's because we only release the head node of the list; the other nodes are still allocated, but no longer reachable. We need to go through the list and delete all the nodes:

void free_ll(node *head) {     while (head) {         node *n = head;         head = head->next;         free(n);     } } 

Use that in place of free(ll).

Const-correctness

The "print" function should be clear that it won't modify the list:

void print_ll(const node *head) {     const node *cur = head;     while (cur) {         printf("Node: %d @ %p\n", cur->val, (const void*)cur);         cur = cur->next;     } } 

Don't assume that allocation will succeed

Always test the pointer returned from malloc()/calloc()/realloc() before using it.

 
 

Relacionados problema

7  Simulando una lista enlazada lineal usando una matriz  ( Simulating a linear linked list using an array ) 
Un programa para simular una lista enlazada lineal usando una matriz: Especificaciones: A Y: cree un nuevo nodo con el valor de datos y, y agregue este...

0  Agregando dos números extremadamente grandes usando una estructura de datos personalizada  ( Adding two extremely large numbers using a custom data structure ) 
Tengo una implementación para agregar 2 números extremadamente grandes, mayor que el techo proporcionado por long , por ejemplo, 1238913893838383813813813813...

14  Implementando una lista relacionada adecuada para un entorno profesional  ( Implementing a proper linked list for a professional environment ) 
Tengo algunas preocupaciones: ¿Es normal que la clase tenga al menos un nodo? En otras palabras, esta implementación no puede tener una lista vinculada va...

3  Lista doblemente vinculada en óxido usando los punteros crudos  ( Doubly linked list in rust using raw pointers ) 
Estoy practicando la oxidación escribiendo una lista doblemente vinculada usando los punteros crudos, 9988776655544330 Para asignar datos en el montón, 998...

1  DEQUEUE () en la implementación de la cola que utiliza una lista circular vinculada  ( Dequeue in queue implememtation that uses a circular linked list ) 
Utilizo una lista de enlaces circulares para implementar un queue , y solo sostiene un 99887776665544332 (Tenga en cuenta que 99887776655443333 enlaces a...

4  ADT Pila con Linkedlist  ( Adt stack with linkedlist ) 
Actualmente estoy preparando para mi examen y estoy tratando de implementar algunos tipos de datos abstractos con listas vinculadas como preparación para el e...

5  Destructor para una lista vinculada  ( Destructor for a linked list ) 
El código completo se encuentra aquí: https://gist.github.com/4521540 < / p> Es un maniquí List en C ++. Mi preocupación es para liberar la memoria. No s...

10  Lista vinculada de objetos de conejito  ( Linked list of bunny objects ) 
El ejercicio es el ejercicio de la lista de conejitos vinculados; El último ejercicio para principiantes de aquí . Estoy buscando comentarios sobre absolut...

4  Eliminar nodos alternativos de una lista vinculada  ( Delete alternate nodes of a linked list ) 
Si la lista vinculada es 1- & gt; 2- & gt; 3- & gt; 4 entonces la salida debe ser 1- & gt; 3. Si la lista vinculada es 1- & gt; 2- & gt; 3- & gt; 4- & gt; 5,...

5  Cola de bloqueo con la exactitud de la lista doblemente vinculada  ( Lock free queue with doubly linked list correctness ) 
Necesito una cola de bloqueo que se implementa mediante la lista doblemente vinculada. es mi código correcto? ¿Hay algún error? ¿Hay alguna mejoras a realiz...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos