Foros del Web » Programación para mayores de 30 ;) » C/C++ »

Printar lista enlazada

Estas en el tema de Printar lista enlazada en el foro de C/C++ en Foros del Web. Muy buenas, Tengo un problema a la hora de imprimir todos los elementos de una lista dinamica. El problema me ocurro cuando borro el ultimo ...
  #1 (permalink)  
Antiguo 18/02/2013, 14:29
 
Fecha de Ingreso: noviembre-2012
Mensajes: 136
Antigüedad: 11 años, 5 meses
Puntos: 0
Printar lista enlazada

Muy buenas,

Tengo un problema a la hora de imprimir todos los elementos de una lista dinamica.
El problema me ocurro cuando borro el ultimo elemento de la lista, es decir si añado unos cuantos nodos e imprimo todos los elementos funciona correctamente pero a la que borro el ultimo y hago que imprima otra vez todos los elementos de la lista se me desborda la memoria, es decir leo alguna posicion de memoria no declarada, haber si me podéis ayudar porque es muy raro.

Esta es la funcion de borrado:
Código:
void eliminarNode(char dominio[20])
{
	int trobat=0;
	NodeDNS *Aux1;	
	NodeDNS *Anterior;
	Aux1=PrimerNode;
	
	while (Aux1!=NULL && trobat==0)
	{

		if(strcmp(Aux1->nombre,dominio)==0)//Hemos encontrado el elemento a eliminar
		{
			trobat=1;
			if(PrimerNode==UltimNode)//Solament hi ha un element a la llista
			{	
				free(Aux1);
				PrimerNode=NULL;
				UltimNode=NULL;
			}
			
			if(Anterior->DNSseguent==UltimNode) //Queremos elimiar el ultimo elemento
			{				UltimNode=Anterior;
				
				printf("Ultim node ara es %s",UltimNode->nombre);
				printf("\nEl primer node ara es %s",PrimerNode->nombre);
				free(Aux1);
			}

		}
		else
		{
			Anterior=Aux1;
			Aux1=Aux1->DNSseguent;

		}
	}
}
y esta la de imprimir cada elemento de la lista:

Código:
void printarLlistaDNS()
{
	NodeDNS *Temp;	
	Temp=PrimerNode;
	printf("Aux es: %s\n",Temp->nombre);
	while(Temp!=NULL)
	{
		printf("%s ->", Temp->nombre); 
		
		if(Temp==NULL)
		{
			printf("NULL");
		}
		else
		{
		Temp=Temp->DNSseguent;
		}
	}
	printf("\n");
}
  #2 (permalink)  
Antiguo 18/02/2013, 16:16
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 11 años, 8 meses
Puntos: 83
Respuesta: Printar lista enlazada

El problema lo tienes en que en el resultado de quitar el ultimo nodo, el nodo resultante sigue apuntando a la direccion de memoria en que antes tenias el ultimo nodo pero que has eliminado liberando el bloque de memoria usado ok?

Código:
//cambias los punteros
UltimNode = Anterior;

//depuras
printf("Ultim node ara es %s", UltimNode->nombre);
printf("\nEl primer node ara es %s", PrimerNode->nombre);

//liberas memoria
free(Aux1);

//y quitas la asignacion anterior no valida
//lo pongo aqui al final pero tendrias que ponerlo immediatamente despues de cambiar los punteros
UltimNode->DNSseguent = NULL;
Estas asignaciones de valores nulos tienes que hacerlas siempre, en C no se hacen por si solas; de la misma forma deberias inicializar las globales 'PrimerNode' y 'UltimNode' a nulo antes de cualquier operacion para evitar que casulamente se inicien con datos basura.

Otra cosa, no mezcles cuatrocientos idiomas en el mismo codigo, o tot en catala o tot en castella o tot en angles, pero 'PrimerNode->nombre' i cosas por el estilo mejor no lo hagas.

Y una ultima cosa, creo que no te has dado cuenta de lo que hace tu funcion para imprimir nodos:

Código:
while(Temp!=NULL) {
    printf("%s ->", Temp->nombre); 
    if(Temp==NULL) {
        printf("NULL");
    }
    else {
        Temp=Temp->DNSseguent;
    }
}
Si el while se ejecuta mientras Temp no sea nulo, ¿cuando demonios se ejecuta el condicional de si Temp es nulo??

Código:
void printarLlistaDNS() {
    NodeDNS *Temp = PrimerNode;	
    int indexNode = 0;
	
    while(Temp) {
        if(indexNode++) {
            printf(" -> ");
	}
	printf("%s", Temp->nombre); 
	Temp = Temp->DNSseguent;
    }
    printf("\n");
}

Salut
vosk
  #3 (permalink)  
Antiguo 20/02/2013, 10:35
 
Fecha de Ingreso: noviembre-2012
Mensajes: 136
Antigüedad: 11 años, 5 meses
Puntos: 0
Respuesta: Printar lista enlazada

Muchas gracias por todo, me falta poner a NULL el siguiente,

respecto esto
Cita:
Iniciado por vosk Ver Mensaje

Si el while se ejecuta mientras Temp no sea nulo, ¿cuando demonios se ejecuta el condicional de si Temp es nulo??
ajajajajaj

modifique cosas y no me di cuenta.

Saludos y gracias de nuevo
  #4 (permalink)  
Antiguo 20/02/2013, 10:55
 
Fecha de Ingreso: noviembre-2012
Mensajes: 136
Antigüedad: 11 años, 5 meses
Puntos: 0
Respuesta: Printar lista enlazada

Parecia que funcionaba bien, pero ahora veo que si elimo el primer nodo, me peta aqui :

Código:
if(Anterior->DNSseguent==UltimNode)
Código:
void eliminarNode(char dominio[20])
{
	int trobat=0;
	NodeDNS *Aux1;	
	NodeDNS *Anterior;
	Aux1=PrimerNode;
	

	while (Aux1!=NULL && trobat==0)
	{

		if(strcmp(Aux1->nombre,dominio)==0)//Hemos encontrado el elemento a eliminar
		{
			trobat=1;
			if(PrimerNode==UltimNode)//Solament hi ha un element a la llista
			{	
				free(Aux1);
				PrimerNode=NULL;
				UltimNode=NULL;
				
			}
			
			if(Anterior->DNSseguent==UltimNode) //Queremos elimiar el ultimo elemento de la cola
			{
				UltimNode=Anterior;
				UltimNode->DNSseguent = NULL;
				printf("Ultim node ara es %s",UltimNode->nombre);
				printf("\nEl primer node ara es %s",PrimerNode->nombre);
				free(Aux1);
			}
			else //Eliminamos un elemento intermedio
			{
				Anterior->DNSseguent=Aux1->DNSseguent;
				free(Aux1);

			}
		}
		else
		{
			Anterior=Aux1;
			Aux1=Aux1->DNSseguent;

		}
	}
}
Tambien creo que la parte de eliminar el nodo si solo hay un elemento tendria que cambiarla, ya que creo que podria agrupar esta opcion junto con eliminar el primer nodo de la lista, se el ultimo o no.
  #5 (permalink)  
Antiguo 20/02/2013, 14:14
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 11 años, 8 meses
Puntos: 83
Respuesta: Printar lista enlazada

Has echo una funcion un poco liada, es mas simple de lo que parece:

Código:
buscas el nodo a eliminar
    - si es el el primero: asignas el siguiente al que se va a eliminar
    - si no es el primero: asignas al anterior el siguiente del que vas a eliminar
Te he modificado un poco la funcion pero no te constará entender lo que hay:

Código:
void eliminarNode(char *dominio) {
    NodeDNS *cur, *pre;
	
    cur = PrimerNode;
    pre = NULL;
	
    while(cur) {//cicle
        if(!strcmp(cur->nombre, dominio)) {//troba objectiu
            if(!pre) {//objectiu == primer node
                PrimerNode = cur->DNSseguent;
	    }
            else {//objectiu != primer node
                pre->DNSseguent = cur->DNSseguent;
            }
            
            //allibera
            free(cur);

            //surt del cicle
            break;
        }

        //iteracio
        pre = cur;
        cur = cur->DNSseguent;
	}
}
Creo que deberias modificar un poco la funcion para que retorne 1 o 0 en funcion de si encuentra el nodo a eliminar, de esta forma podras saber desde la llamada a eliminarNode si el nombre del nodo existe o no y si se ha ejecutado la operacion.


Saludos
vosk
  #6 (permalink)  
Antiguo 26/02/2013, 09:44
 
Fecha de Ingreso: noviembre-2012
Mensajes: 136
Antigüedad: 11 años, 5 meses
Puntos: 0
Respuesta: Printar lista enlazada

gracias por contestar de nuevo, no he tenido tiempo de comprovarlo ahora lo estaba mirando y haber si esta noche lo pruebo.

Pero tengo una duda cunado pones While(cur) cur es un puntero, esto que lo hara mientras sea diferente de Null?

No sabia que se podia hacer esto.

Saludos
  #7 (permalink)  
Antiguo 26/02/2013, 12:32
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 11 años, 8 meses
Puntos: 83
Respuesta: Printar lista enlazada

El 'while' opera en base al resultado de una condicion, ese resultado como tal será boleano (true o false); normalmente e considera que 0 o nulo es false y todo lo demas es true (todo lo demas incluye cualquier cosa que no sea nulo o 0, es decir numeros, punteros, y yo que se que mas), por eso puedes aplicar la condicion de puntero no nulo para el bucle while. Y aquí entra en juego la parte importante de asignar el valor nulo a todos los punteros que quieras que se consideren nulos.

Es una forma de escribir la condicion, tal vez sería recomendable usar la comparacion explicita por si vas a compartir codigo y quieres que los demas entiendan lo que haces, pero en estos casos suele hacerse de esta forma y normalmente se suele entender que 'while(puntero)' equivale a 'while(puntero != NULL)'.

Saludos
vosk
  #8 (permalink)  
Antiguo 27/02/2013, 09:32
 
Fecha de Ingreso: noviembre-2012
Mensajes: 136
Antigüedad: 11 años, 5 meses
Puntos: 0
Respuesta: Printar lista enlazada

Perdon por mi estupidez pero estoy encerrado en el problema y no encuentro la p... salida, estoy es deprimente , lo mejor de todo que esto ya lo hize en su dia.

Haber, me sigue petando lo mismo, cuando borro algun nodo que no se el primero al imprimir la lista me peta, tambe me pasa algo raro, cuando borro un nodo y quiero imprimir solo el primero ya que me salen caracteres extraños.

Código:
void afegirDNS(char dominio[20])
	
{	
	NodeDNS *Aux;	
	Aux=(NodeDNS *)malloc(sizeof(NodeDNS));

	strcpy(Aux->nombre,dominio);
	Aux->DNSseguent=NULL;

	if(PrimerNode==NULL)
	{
		PrimerNode=Aux;
		UltimNode=Aux;
	}
	else
	{
		UltimNode->DNSseguent=Aux;
		UltimNode=Aux;
	
	}
	
}

void printarLlistaDNS()
{
	NodeDNS *Temp;	
	Temp=PrimerNode;
	
	while(Temp)
	{
		printf("%s ->", Temp->nombre); 
		Temp=Temp->DNSseguent;
	}
	printf("NULL\n");
	
}

void printarprimer()
{
	
	if (PrimerNode!=NULL)
	{
		printf("El primer node es: %s\n\n",PrimerNode->nombre);
	}
	else
	{
		printf("Llista buida");
	}
}

void printarultim()
{

	if (UltimNode!=NULL)
	{
		printf("El ultim node es: %s\n\n",UltimNode->nombre);
	}
	else
	{
		printf("Llista buida");
	}

}

void eliminarNode(char dominio[20])
{
		
	
	NodeDNS *Actual;
	NodeDNS *Anterior;
	
	Actual=PrimerNode;
	Anterior=NULL;

	 while(Actual) 
	 {//cicle

        if(strcmp(Actual->nombre,dominio)==0)//Hemos encontrado el elemento a eliminar
            
			if(!Anterior)   //Es el primer node de la llista
			{   
                PrimerNode=Actual->DNSseguent;
			}
            else 
			{				//Si no es el primer node
                Anterior->DNSseguent = Actual->DNSseguent;
				UltimNode=Anterior;
            }
            
            //allibera
            free(Actual);

            //surt del cicle
            break;
        }

  
        Anterior = Actual;
        Actual = Actual->DNSseguent;
	
}

void main()
{
	int opcion=0;
	char dominio[20];
	
	while(1)
	{
		printf("\n1- A");
		printf("%c",164);
		printf("adir DNS: \n\n");
		printf("2- Printar primer element\n\n");
		printf("3- Printar ultim element\n\n");
		printf("4- Printar tots els elements\n\n");
		printf("5- Eliminar un domini\n\n");

		printf("Seleccione una opcion: ");
		
		scanf("%d",&opcion);
		printf("\n\n");
			switch(opcion)
			{
				case 1:		printf("Introdueix el nom de domini: ");
							scanf("%s",dominio);
							afegirDNS(dominio);
							
							break;
				case 2:		printarprimer();
							break;
			
				case 3:		printarultim();
							break;

				case 4:		printf("\n");
							printarLlistaDNS();
							break;

				case 5:		printf("Introdueix el domini que vols eliminar: ");
							scanf("%s",dominio);
							eliminarNode(dominio);
							break;
			}
	}

	system("Pause");
}
Te pongo todo el codigo, tengo que tener algun puntero mal referenciado pero no encuentro el fallo.

Saludos
  #9 (permalink)  
Antiguo 27/02/2013, 13:18
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 11 años, 8 meses
Puntos: 83
Respuesta: Printar lista enlazada

Ok fue culpa mia, omiti el puntero UltimNode cuando te plantee la funcion 'eliminarNode': en la condicion de eliminar nodo diferente del primero, solo debes asignar a la global UltimNode la referencia al nodo previo al que vas a borrar en el caso que vayas a borrar el ultimo elemento de la lista (esto incluye el caso de un unico elemento)

Código:
void eliminarNode(char *dominio) {
    NodeDNS *cur, *pre;
	
    cur = PrimerNode;
    pre = NULL;
	
    while(cur) {//cicle
        if(!strcmp(cur->nombre, dominio)) {//troba objectiu
            if(!pre) {//objectiu == primer node
                PrimerNode = cur->DNSseguent;
	    	}
            else {//objectiu != primer node
                pre->DNSseguent = cur->DNSseguent;
            }
            
            //node objectiu es l'ultim de la llista?
            //independentment de si es el primer o no
            if(!strcmp(cur->nombre, UltimNode->nombre)) {
		UltimNode = pre;
	    }
            
            //allibera
            free(cur);

            //surt del cicle
            break;
        }

        //iteracio
        pre = cur;
        cur = cur->DNSseguent;
	}
}
Ten en cuenta que los punteros al ultimo nodo de una lista solo son utiles cuando trabajas con listas doblemente enlazadas (dentro del struct tendrias dos punteros: uno al nodo siguiente y otro al anterior) y sirve para acelerar las busquedas; en este caso el puntero al ultimo nodo solo sirve para acelerar la adicion de un nodo al final de la lista.

Otra cosa, tienes algun error de concepto, te los comento:

La funcion de entrada a la aplicacion es de tipo entero, debes declararla como tal y retornar un valor entero (por defecto se usa 0 si todo ok, o un valor diferente de 0 como indice de error en caso que se produjera alguno)

Código:
int main() {
    ...
    return 0;
}
Lo de asignar el valor nulo a los punteros nulos, antes de comenzar a trabajar con las globales PrimerNode y UltimNode debes asignarles el valor nulo (puede darse el caso que les asigne un bloque de memoria con datos basura):

Código:
NodeDNS *PrimerNode = 0;
NodeDNS *UltimNode = 0;
Saludos
vosk
  #10 (permalink)  
Antiguo 03/03/2013, 06:34
 
Fecha de Ingreso: noviembre-2012
Mensajes: 136
Antigüedad: 11 años, 5 meses
Puntos: 0
Respuesta: Printar lista enlazada

Me sigue sin funcionar, yo creo que el problema esta en el printar.

Si voy añadiendo nodos y los voy printando no hay problema, pero si luego elimino alguno y los printo todos es cuando me hace un segment fault.

Código:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "datos.h"

void afegirDNS(char dominio[20])
	
{	
	NodeDNS *Aux;	
	Aux=(NodeDNS *)malloc(sizeof(NodeDNS));

	strcpy(Aux->nombre,dominio);
	Aux->DNSseguent=NULL;

	if(PrimerNode==NULL)
	{
		PrimerNode=Aux;
		UltimNode=Aux;
	}
	else
	{
		UltimNode->DNSseguent=Aux;
		UltimNode=Aux;
	
	}
	
}

void printarLlistaDNS()
{
	NodeDNS *Temp;	

	Temp=PrimerNode;
	
	while(Temp)
	{
		printf("%s ->", Temp->nombre); 
		Temp=Temp->DNSseguent;
	}
	printf("NULL\n");
	
}

void printarprimer()
{
	
	if (PrimerNode!=NULL)
	{
		printf("El primer node es: %s\n\n",PrimerNode->nombre);
	}
	else
	{
		printf("Llista buida");
	}
}

void printarultim()
{

	if (UltimNode!=NULL)
	{
		printf("El ultim node es: %s\n\n",UltimNode->nombre);
	}
	else
	{
		printf("Llista buida");
	}

}

void eliminarNode(char dominio[20])
{
		
	
	NodeDNS *Actual;
	NodeDNS *Anterior;
	
	Actual=PrimerNode;
	Anterior=NULL;

	 while(Actual) 
	 {//cicle

        if(strcmp(Actual->nombre,dominio)==0)//Hemos encontrado el elemento a eliminar
            
			if(!Anterior)   //Es el primer node de la llista
			{   
                PrimerNode=Actual->DNSseguent;
			}
            else 
			{				//Si no es el primer node
                Anterior->DNSseguent = Actual->DNSseguent;
				UltimNode=Anterior;

				if(!strcmp(Actual->nombre, UltimNode->nombre)) 
				{
					UltimNode = Anterior;
				}

            }
            
            //allibera
            free(Actual);

            //surt del cicle
            break;
        }

  
        Anterior = Actual;
        Actual = Actual->DNSseguent;
	
}

void main()
{
	int opcion=0;
	char dominio[20];
	
	while(1)
	{
		printf("\n1- A");
		printf("%c",164);
		printf("adir DNS: \n\n");
		printf("2- Printar primer element\n\n");
		printf("3- Printar ultim element\n\n");
		printf("4- Printar tots els elements\n\n");
		printf("5- Eliminar un domini\n\n");

		printf("Seleccione una opcion: ");
		
		scanf("%d",&opcion);
		printf("\n\n");
			switch(opcion)
			{
				case 1:		printf("Introdueix el nom de domini: ");
							scanf("%s",dominio);
							afegirDNS(dominio);
							
							break;
				case 2:		printarprimer();
							break;
			
				case 3:		printarultim();
							break;

				case 4:		printf("\n");
							printarLlistaDNS();
							break;

				case 5:		printf("Introdueix el domini que vols eliminar: ");
							scanf("%s",dominio);
							eliminarNode(dominio);
							break;
			}
	}

	system("Pause");
}
  #11 (permalink)  
Antiguo 03/03/2013, 10:26
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 11 años, 8 meses
Puntos: 83
Respuesta: Printar lista enlazada

La funcion 'eliminarNode' está mal, no es igual a la que te planteé en mi post anterior (como ultima opcion copia y pega directamente lo que colgué); la parte de asignacion al ultimo nodo no está donde debería, y ademas faltan algunos claudators. Tambien deberias iniciar a nulo los punteros a los nodos antes de hacer cualquier operacion.

Saludos
vosk
  #12 (permalink)  
Antiguo 03/03/2013, 11:55
 
Fecha de Ingreso: noviembre-2012
Mensajes: 136
Antigüedad: 11 años, 5 meses
Puntos: 0
Respuesta: Printar lista enlazada

Ostia es verdad, merci. Luego me lo miro con calma, haber que me he dejado.

Un saludo y gracias por todo. Nos vemos por aqui

Etiquetas: enlazada, funcion, int, lista
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 12:24.