[C con Clase] problemillas con una lista

Steven Davidson steven en conclase.net
Jue Mayo 31 20:08:26 CEST 2007


Hola Duna,

El pasado 2007-05-31 07:51:53, Duna escribió:

D> Gracias Steven.
D> ---Las dos cuestiones están ligadas entre sí. Cuando creas un nuevo nodo,
D> con 'malloc()', no asignas valores al contenido de tal nodo. En el bucle,
D> asignas casi ---todos los campos del nodo, a excepción del puntero 'next'.
D> Si este nuevo nodo es el último nodo de la lista enlazada, entonces el
D> puntero 'next' debería ser ---'NULL'.
D> Cuando me dices lo de que apunte a NULL, eso lo hago en una línea que no
D> incluí en el código:
D> if (i != 0)
D>  {
D>         consulta1->next=NULL;
D>         consulta1=uno;
D>  }
D> Supongo que es a eso a lo que te referías

Sí. A esto me refería. Sin embargo, la última sentencia anterior acarrearía otro error. El puntero 'consulta1' apunta al nuevo nodo, mientras que 'uno' apunta a la "cabeza" de la lista. No podemos perder la dirección de memoria del nuevo nodo hasta que no exista otro vínculo a ello. Esto es,

if( i != 0 )
{
  consulta1 = (uno_l *) malloc( (i+1) * sizeof(uno_l) );
  consulta1->next = NULL;

  /* Agregamos el primer nodo a la lista encabezada por 'uno' */
  uno = consulta1;
}

D> Pensé que cuando pongo:
D> uno= consulta1;
D> Querría decir que tengo un puntero que apunta al principio de la lista
D> dinámica, y aunque me vaya moviendo con consulta1, el puntero uno realmente
D> apunta al principio de la lista, esto no es así?

Esto es correcto. Sin embargo, el código que nos mandaste, solamente creas un nodo, aunque usas un bucle para obtener varios tuplos (filas) de la base de datos y recorrer varios nodos usando 'consulta1' a modo de "índice". El esquema que usas viene a ser el siguiente:

for( l=0; l<i; l++ )
{
  row = mysql_fetch_row(res);
  lon = mysql_fetch_lengths(res);

  k=0;
  consulta1->cl = atoi( row[k] );
  ...
  consulta1 = consulta1->next;
}

En la primera iteración (l=0), no tenemos problemas. Sin embargo, llegamos a la última sentencia:

consulta1 = consulta1->next;

Esto equivale a:
consulta1 = NULL;

porque 'consulta1->next' = 'uno->next' = NULL, que hicimos al comienzo.

A partir de aquí, tenemos problemas, ya que 'consulta1' es un puntero nulo. Al intentar acceder a sus campos y asignarles valores, el sistema operativo se quejará y con razón, porque estamos accediendo a un puntero nulo.


Lo que dije en mi mensaje anterior es que tienes que ir creando dinámicamente cada nodo. Ya te mostré el esquema a seguir en mi mensaje anterior, pero si quieres algo de código sería algo así:

for( l=0; l<i; l++ )
{
  row = mysql_fetch_row(res);
  lon = mysql_fetch_lengths(res);

  /* Creamos memoria */
  consulta1 = (uno_l *) malloc( (i+1) * sizeof(uno_l) );
  consulta1->next = NULL;

  k=0;
  consulta1->cl = atoi( row[k] );
  ...
}

Aún así seguimos teniendo un problema: enlazar el nuevo nodo con la lista. Para esto, necesitamos alguna manera de asignar el campo 'next' del último nodo en la lista. Sugiero usar otro puntero para esto. Por ejemplo,

if( i != 0 )
{
  consulta1 = (uno_l *) malloc( (i+1) * sizeof(uno_l) );
  consulta1->next = NULL;

  /* Agregamos el primer nodo a la lista encabezada por 'uno' */
  uno = ultimo = consulta1;

  for( l=0; l<i; l++ )
  {
    row = mysql_fetch_row(res);
    lon = mysql_fetch_lengths(res);

    /* Creamos memoria */
    consulta1 = (uno_l *) malloc( (i+1) * sizeof(uno_l) );
    consulta1->next = NULL;

    /* Enlazamos el nuevo nodo a la lista */
    ultimo->next = consulta1;

    k=0;
    consulta1->cl = atoi( row[k] );
    ...
    /* Avanzamos el puntero */
    ultimo = ultimo->next;
  }
}


Otra implementación puede ser la siguiente:

if( i != 0 )
{
  consulta1 = (uno_l *) malloc( (i+1) * sizeof(uno_l) );
  consulta1->next = NULL;

  /* Agregamos el primer nodo a la lista encabezada por 'uno' */
  uno = consulta1;

  for( l=0; l<i; l++ )
  {
    row = mysql_fetch_row(res);
    lon = mysql_fetch_lengths(res);

    /* Creamos y ligamos un nuevo nodo al final de nuestra lista */
    consulta1->next = (uno_l *) malloc( (i+1) * sizeof(uno_l) );
    consulta1 = consulta1->next;
    consulta1->next = NULL;  /* Recordamos "cerrar" la lista */

    k=0;
    consulta1->cl = atoi( row[k] );
    ...
  }
}

D> Como puedes ver con el nuevo código que he mandado, asigno el puntero a
D> consulta1 otra vez a uno, que se supone que está apuntando al principio de
D> la lista.

Creo que queda explicado anteriormente.


Quiero dar por sentado que el código y la explicación que he escrito se basan en agregar nodos al final de la lista dinámicamente enlazada. Si quieres agregar al comienzo de la lista, entonces hay que cambiar la lógica de la vinculación de los nodos.

Espero que todo esto te ayude.

Steven


Más información sobre la lista de distribución Cconclase