Lio con compilación en C.

Que tal tios?
A ver si me podeis echar un cable que es una tonteria.
En la uni me ha pedido que implemente una lista enlanzada para meter unas coordenadas (un poco chorra).
El caso, es que me han pedido que en head_tail_list.h meta las estructuras y prototipos de las funciones; en list.c que implemente las funciones y en main.c que ponga el main().
Tengo todo hecho pero no sé como hacer que main.c llame a list.c para recoger las funciones. Es más, al compilar el list.c, gcc chilla diciendo que no hay un main().

head_tail_list.h
struct Coordenadas{
   int x, y;
};

typedef struct Tail{
   struct Coordenadas c;
   struct Tail *next;
} * ptrTail;
   
typedef struct Head{
   ptrTail first, last;
   int numElem;
} * ptrHead;

//Prototipos
   
ptrHead anadir(int coordx, int coordy, ptrHead p);
ptrHead borrar(int coordx, int coordy, ptrHead p);
void borrarTodo(ptrHead p);
void imprimir(ptrHead p);


list.c
#include <stdio.h>
#include <stdlib.h>
#include "head_tail_list.h"

ptrHead anadir(int coordx, int coordy, ptrHead p){
   if(p == NULL){
      p=(ptrHead) malloc(sizeof(struct Head));
      p->first=(ptrTail) malloc(sizeof(struct Tail));
      p->numElem=1;
      p->first->c.x=coordx;
      p->first->c.y=coordy;
      p->first->next=NULL;
      p->last=p->first;
      return p;
   }
   p->last->next=(ptrTail) malloc(sizeof(struct Tail));
   p->last->next->c.x=coordx;
   p->last->next->c.y=coordy;
   p->last->next->next=NULL;
   p->last=p->last->next;
   p->numElem++;
   return p;
}

ptrHead borrar(int coordx, int coordy, ptrHead p){
   if(p==NULL)
      return NULL;
   int i;   
   ptrTail t=p->first, t1=t;
   for(i=0; i < p->numElem; i++){
      if(t->c.x==coordx && p->first->c.y==coordy){
         t=t->next;
         free(t1);
         p->numElem--;
      }
      t=t->next;
      t1=t;
   }
   return p;
}

void borrarTodo(ptrHead p){
   int i;
   ptrTail t=p->first, t1=t;
   for(i=0; i< p->numElem; i++){
      t=t->next;
      free(t1);
      t1=t;
   }
   free(p);
   return;
}
   
void imprimir(ptrHead p){
   int i;
   ptrTail t=p->first;
   printf("El número de nodos es %d\n", p->numElem);
   for(i=0; i < p->numElem; i++){
      printf("Nodo %d:\n Coordenada x %d\n Coordenada y %d\n", i, t->c.x, t->c.y);
      t=t->next;
   }
}


main.c
#include <stdio.h>
#include "head_tail_list.h"

int main(int arg_count, char *arg_strings[]) {
   printf("Tienes las siguientes opciones para hacer:\n - Pulsa 'a' para añadi un elemento a la lista.\n - Pulsa 'r'para borrar un elemento de la lista.\n- Pulsa 'p' para imprimir todos los nodos.\n - Pulsa 'q' para salir.\n");
   char var;
   int x,y;
   ptrHead p=NULL;
   scanf("%s",&var);
   while(var != 'q'){
      switch(var){
         case 'a':
            printf("Introduzca las coordenadas x e y a añadir\n");
            scanf("%d %d",&x, &y);
            p=aniadir(x,y,p);
            break;
         case 'r':
            printf("Introduzca las coordenadas x e y a borrar\n");
            scanf("%d %d",&x, &y);
            p=borrar(x,y,p);
            break;
         case 'p':
            imprimir(p);
            break;
      }
   }
   borrarTodo(p);
    return 0;
}


Gracias :)
mm.. lo lógico es que el fichero de cabeceras tenga el mismo nombre que el fichereo que lo implementa
Para compilar haz:

gcc -c head_tail_list.c
gcc head_tail_list.o main.c -o nombrePrograma


Con gcc -c lo que hace es compilar el fichero pero no lo linka.
gcc main.c list.c -o ejecutable


Así debería ir, ¿no?
nu_kru escribió:mm.. lo lógico es que el fichero de cabeceras tenga el mismo nombre que el fichereo que lo implementa
Para compilar haz:

gcc -c head_tail_list.c
gcc head_tail_list.o main.c -o nombrePrograma


Con gcc -c lo que hace es compilar el fichero pero no lo linka.


Mil gracias ^^
De cualquiera de las dos formas supongo que irá. Con -c lo que hace es general el código objeto, y con -o compila y usa el linker para enlazar los distintos códigos objetos.

De hecho, creo que yo directamente hacía:

gcc *.c -o ejecutable


Siempre que tengas en una misma carpeta solamente los fuentes que te interesen.
Un makefile siempre viene bien en el momento que tengas muchos ficheros fuente y se haga engorroso escribirlos a mano en la línea de comandos, ya que por ahora solo tienes dos no hay mucho problema, pero cuando tengas varios puede serte util compilar todo el proyecto con solo un "make":
CC := gcc
TARGET = ejecutable
LIBS :=
INCLUDES :=
LIB_PATH :=
CFLAGS := -O2 -pipe -Wall
LDFLAGS :=
RM = rm -f
OBJS = main.o list.o

all: $(TARGET)

$(TARGET): $(OBJS)
   $(CC) $(LDFLAGS) $(OBJS) $(LIB_PATH) $(LIBS) -o $(TARGET)

.c.o:
   $(CC) $(CFLAGS) $(INCLUDES) -c $*.c

clean:
   -$(RM) $(OBJS) $(TARGET)

.PHONY: all clean


No te preocupes por el resto de los parametros, cuando realmente los necesites pues ya tienes donde ponerlos, saludos.
Este es un problema con las universidades, que te enseñan con un IDE, te dicen que el IDE es el compilador, y luego no se sabe no lo que es el makefile ni compilar manualmente. Una simple clase explicando lo que es cada cosa y me habría quitado muchos quebraderos de cabeza...
Hombre, en mi universidad me enseñaron a programar a pelo, con emacs y gedit y compilando con gcc desde el terminal.
Chaky escribió:Este es un problema con las universidades, que te enseñan con un IDE, te dicen que el IDE es el compilador, y luego no se sabe no lo que es el makefile ni compilar manualmente. Una simple clase explicando lo que es cada cosa y me habría quitado muchos quebraderos de cabeza...


Eso no es asi. Yo tiro de kate y terminal. El problema es que nunca habia compilado un *.c sin main() y me escupia error.

Otro tema, a ver si me echais un cable con la función de borrar un nodo. No hay forma de lo haga bien, borrar un nodo cualquiera dada sus coordenadas y no sé por qué. Aparentemente está bien, adjunto todo de nuevo por si alguien le apetece darle un repaso :)

head_tail_list.h
struct Coordenadas{
   int x, y;
};

typedef struct Tail{
   struct Coordenadas c;
   struct Tail *next;
} * ptrTail;
   
typedef struct Head{
   ptrTail first, last;
   int numElem;
} * ptrHead;

//Prototipos
   
ptrHead anadir(int coordx, int coordy, ptrHead p);
ptrHead borrar(int coordx, int coordy, ptrHead p);
void borrarTodo(ptrHead p);
void imprimir(ptrHead p);


list.c
#include <stdio.h>
#include <stdlib.h>
#include "head_tail_list.h"

ptrHead anadir(int coordx, int coordy, ptrHead p){
   if(p == NULL){
      p=(ptrHead) malloc(sizeof(struct Head));
      p->first=(ptrTail) malloc(sizeof(struct Tail));
      p->numElem=1;
      p->first->c.x=coordx;
      p->first->c.y=coordy;
      p->first->next=NULL;
      p->last=p->first;
      return p;
   }
   p->last->next=(ptrTail) malloc(sizeof(struct Tail));
   p->last->next->c.x=coordx;
   p->last->next->c.y=coordy;
   p->last->next->next=NULL;
   p->last=p->last->next;
   p->numElem++;
   return p;
}

ptrHead borrar(int coordx, int coordy, ptrHead p){
   if(p==NULL)
      return NULL;
   
   int i, aux=p->numElem;   
   ptrTail t=p->first;
   for(i=0; i< aux; i++){
      ptrTail t1=t;
      if(t->c.x == coordx && t->c.y == coordy){
         t=t1->next;
         p->numElem--;
         free(t1);
      }
      else
        t=t->next;   
   }
   return p;
}

void borrarTodo(ptrHead p){
   int i;
   ptrTail t=p->first, t1=t;
   for(i=0; i< p->numElem; i++){
      t1=t->next;
      free(t);
      t=t1;
   }   
   free(p);
}
   
void imprimir(ptrHead p){
   int i;
   ptrTail t=p->first;
   printf("El número de nodos es %d\n", p->numElem);
   for(i=0; i < p->numElem; i++){
      printf("Nodo %d:\n Coordenada x %d\n Coordenada y %d\n", i, t->c.x, t->c.y);
      t=t->next;
   }
}


main.c
#include <stdio.h>
#include "head_tail_list.h"

int main(int arg_count, char *arg_strings[]) {
   char var='a';
   int x,y;
   ptrHead p=NULL;
   while(var != 'q'){
      printf("Tienes las siguientes opciones para hacer:\n - Pulsa 'a' para añadir un elemento a la lista.\n - Pulsa 'r' para borrar un elemento de la lista.\n - Pulsa 'p' para imprimir todos los nodos.\n - Pulsa 'q' para salir.\n");
      scanf("%s",&var);
      switch(var){
         case 'a':
            printf("Introduzca las coordenadas 'x' e 'y' a añadir\n");
            scanf("%d %d",&x, &y);
            p=anadir(x,y,p);
            break;
         case 'r':
            if(p==NULL){
                  printf("No hay nodos que borrar.\n");
                  break;
            }
            printf("Introduzca las coordenadas 'x' e 'y' a borrar\n");
            scanf("%d %d",&x, &y);
            p=borrar(x,y,p);
            break;
         case 'p':
            if(p==NULL){
                printf("No hay nodos.\n");
                break;
            }
            imprimir(p);
            break;
      }
   }
   if(p == NULL)
      return 0;
   borrarTodo(p);
    return 0;
}


prueba.sh (opcional, me quita trabajo xD)
#! /bin/bash

echo Compiando head_tail_list.h
gcc -Wall -g head_tail_list.h

echo Compilando list.c
gcc -Wall -c -g list.c

echo Compilando main.c
gcc list.o -g main.c -o main

echo Probando desde valgrind
valgrind --leak-check=yes ./main


Uso valgrind para mirar las fugas de memoria.
La función que borra todos los nodos, lo hace bien; si creo muchos nodos y le doy a salir, antes del return, borro todos los nodos creados para que no haya fugas. Valgrind no chilla con eso. En cambio, cuando quiero borrar un nodo, casca.
Gracias de nuevo a todos por el cable ;)
En lugar de 'casca' igual deberías mirar con gdb qué es lo que está ocurriendo.
Ferdy escribió:En lugar de 'casca' igual deberías mirar con gdb qué es lo que está ocurriendo.


Estabas en el GUL de la uc3m verdad?
Donato escribió:
Chaky escribió:Este es un problema con las universidades, que te enseñan con un IDE, te dicen que el IDE es el compilador, y luego no se sabe no lo que es el makefile ni compilar manualmente. Una simple clase explicando lo que es cada cosa y me habría quitado muchos quebraderos de cabeza...


Eso no es asi. Yo tiro de kate y terminal. El problema es que nunca habia compilado un *.c sin main() y me escupia error.

Otro tema, a ver si me echais un cable con la función de borrar un nodo. No hay forma de lo haga bien, borrar un nodo cualquiera dada sus coordenadas y no sé por qué. Aparentemente está bien, adjunto todo de nuevo por si alguien le apetece darle un repaso :)

head_tail_list.h
struct Coordenadas{
   int x, y;
};

typedef struct Tail{
   struct Coordenadas c;
   struct Tail *next;
} * ptrTail;
   
typedef struct Head{
   ptrTail first, last;
   int numElem;
} * ptrHead;

//Prototipos
   
ptrHead anadir(int coordx, int coordy, ptrHead p);
ptrHead borrar(int coordx, int coordy, ptrHead p);
void borrarTodo(ptrHead p);
void imprimir(ptrHead p);


list.c
#include <stdio.h>
#include <stdlib.h>
#include "head_tail_list.h"

ptrHead anadir(int coordx, int coordy, ptrHead p){
   if(p == NULL){
      p=(ptrHead) malloc(sizeof(struct Head));
      p->first=(ptrTail) malloc(sizeof(struct Tail));
      p->numElem=1;
      p->first->c.x=coordx;
      p->first->c.y=coordy;
      p->first->next=NULL;
      p->last=p->first;
      return p;
   }
   p->last->next=(ptrTail) malloc(sizeof(struct Tail));
   p->last->next->c.x=coordx;
   p->last->next->c.y=coordy;
   p->last->next->next=NULL;
   p->last=p->last->next;
   p->numElem++;
   return p;
}

ptrHead borrar(int coordx, int coordy, ptrHead p){
   if(p==NULL)
      return NULL;
   
   int i, aux=p->numElem;   
   ptrTail t=p->first;
   for(i=0; i< aux; i++){
      ptrTail t1=t;
      if(t->c.x == coordx && t->c.y == coordy){
         t=t1->next;
         p->numElem--;
         free(t1);
      }
      else
        t=t->next;   
   }
   return p;
}

void borrarTodo(ptrHead p){
   int i;
   ptrTail t=p->first, t1=t;
   for(i=0; i< p->numElem; i++){
      t1=t->next;
      free(t);
      t=t1;
   }   
   free(p);
}
   
void imprimir(ptrHead p){
   int i;
   ptrTail t=p->first;
   printf("El número de nodos es %d\n", p->numElem);
   for(i=0; i < p->numElem; i++){
      printf("Nodo %d:\n Coordenada x %d\n Coordenada y %d\n", i, t->c.x, t->c.y);
      t=t->next;
   }
}


main.c
#include <stdio.h>
#include "head_tail_list.h"

int main(int arg_count, char *arg_strings[]) {
   char var='a';
   int x,y;
   ptrHead p=NULL;
   while(var != 'q'){
      printf("Tienes las siguientes opciones para hacer:\n - Pulsa 'a' para añadir un elemento a la lista.\n - Pulsa 'r' para borrar un elemento de la lista.\n - Pulsa 'p' para imprimir todos los nodos.\n - Pulsa 'q' para salir.\n");
      scanf("%s",&var);
      switch(var){
         case 'a':
            printf("Introduzca las coordenadas 'x' e 'y' a añadir\n");
            scanf("%d %d",&x, &y);
            p=anadir(x,y,p);
            break;
         case 'r':
            if(p==NULL){
                  printf("No hay nodos que borrar.\n");
                  break;
            }
            printf("Introduzca las coordenadas 'x' e 'y' a borrar\n");
            scanf("%d %d",&x, &y);
            p=borrar(x,y,p);
            break;
         case 'p':
            if(p==NULL){
                printf("No hay nodos.\n");
                break;
            }
            imprimir(p);
            break;
      }
   }
   if(p == NULL)
      return 0;
   borrarTodo(p);
    return 0;
}


prueba.sh (opcional, me quita trabajo xD)
#! /bin/bash

echo Compiando head_tail_list.h
gcc -Wall -g head_tail_list.h

echo Compilando list.c
gcc -Wall -c -g list.c

echo Compilando main.c
gcc list.o -g main.c -o main

echo Probando desde valgrind
valgrind --leak-check=yes ./main


Uso valgrind para mirar las fugas de memoria.
La función que borra todos los nodos, lo hace bien; si creo muchos nodos y le doy a salir, antes del return, borro todos los nodos creados para que no haya fugas. Valgrind no chilla con eso. En cambio, cuando quiero borrar un nodo, casca.
Gracias de nuevo a todos por el cable ;)



Vamos a ver,. porque estoy algo dormido y frion con esto xD.

ptrHead borrar(int coordx, int coordy, ptrHead p){
   if(p==NULL)
      return NULL;
   
   int i, aux=p->numElem;   
   ptrTail t=p->first;
   for(i=0; i< aux; i++){
      ptrTail t1=t;
      if(t->c.x == coordx && t->c.y == coordy){
         t=t1->next;
         p->numElem--;
         free(t1);
      }
      else
        t=t->next;   
   }
   return p;
}


Lo primero, con ese for, estas recorriendo toda la lista, cuando solo necesitas llegar al que necesitas eliminar, osea buscas, y cuando encuentras haces lo que sea y paras. Por otro lado, por lo que veo, si no me he perdido mucho en el código, aquí:
t=t1->next;
p->numElem--;
free(t1);

Estas pasando a t la direccion del siguiente al que eliminar, pero ese t es un puntero que tu has declarado localmente, y cambiar este puntero no va a cambiar el del nodo anterior de la lista al que querias eliminar, no se si me explico... solo vas a cambiar ese puntero local, no el real que tienes en la lista.

PD: Seran cabrones los de mi unverisidad, que no te enseñan ni lo que es el IDE XD

PD2: Acabo de terminar un código que DEBERÍA de funcionar xD, pero a ver si lo consigues tu solo, que así se aprende mas xD
Donato escribió:
Ferdy escribió:En lugar de 'casca' igual deberías mirar con gdb qué es lo que está ocurriendo.


Estabas en el GUL de la uc3m verdad?


Hrm..... si.... ¿por qué?
Ferdy escribió:
Donato escribió:
Ferdy escribió:En lugar de 'casca' igual deberías mirar con gdb qué es lo que está ocurriendo.


Estabas en el GUL de la uc3m verdad?


Hrm..... si.... ¿por qué?


Porque mi compañero de practicas por lo visto te conoce del GUL (yo voy a la uc3m de leganés).

Chaky escribió:Estas pasando a t la direccion del siguiente al que eliminar, pero ese t es un puntero que tu has declarado localmente, y cambiar este puntero no va a cambiar el del nodo anterior de la lista al que querias eliminar, no se si me explico... solo vas a cambiar ese puntero local, no el real que tienes en la lista.

PD: Seran cabrones los de mi unverisidad, que no te enseñan ni lo que es el IDE

PD2: Acabo de terminar un código que DEBERÍA de funcionar xD, pero a ver si lo consigues tu solo, que así se aprende mas xD


Lo quiero sacar yo pero se "supone" que está bien, es decir, si quiero borrar al nodo que esta delante mia, redirijo mi puntero next al siguiente del que quiero eliminar para mas tarde cargarme el nodo a borrar. A ver que se me ocurre pero gracias por darme algo de luz.

PD: es raro, porque la función que borra TODO, si lo hace bien y basicamente es igual.. ¿Por qué puede ser?
PD2: recorro toda la lista por si tengo dos nodos iguales.
A ver, lo mejor es que te lo dibujes, es una forma sencilla de entender lo que estas haciendo.
Supongamos que el dato a borrar es [BORRAR], y t, t1 los punteros que tienes. Lo que veo que estas haciendo es esto:

t1->[BORRAR], t->[BORRAR], entonces luego haces que t->[SIG_BORRAR] y liberas la memoria a la que apunta t1 que es [BORRAR]. Pero ese t que apunta ahora a [SIG_BORRAR], no cambia nada en tu lista original, solo cambia la direccion de ese puntero que has creado localmente.

La idea, al menos siempre que hago una lista es la siguiente. Llevas dos punteros axiliares, uno que es el que borraremos, y otro que es el anterior, llamemoslo aux, antaux.

antaux->[ANT_BORRAR], aux->[BORRAR], entonces, ahora haces que el puntero next del [ANT_BORRAR] apunte al siguiente a borrar, en este caso: antaux->next=aux->next, y ahora, ya el [BORRAR] queda excluido de la lista, ahora ya puedes borrarlo.

Espero haberme explicado bien, es un poco complicado explicar esto por aquí.
Chaky escribió:A ver, lo mejor es que te lo dibujes, es una forma sencilla de entender lo que estas haciendo.
Supongamos que el dato a borrar es [BORRAR], y t, t1 los punteros que tienes. Lo que veo que estas haciendo es esto:

t1->[BORRAR], t->[BORRAR], entonces luego haces que t->[SIG_BORRAR] y liberas la memoria a la que apunta t1 que es [BORRAR]. Pero ese t que apunta ahora a [SIG_BORRAR], no cambia nada en tu lista original, solo cambia la direccion de ese puntero que has creado localmente.

La idea, al menos siempre que hago una lista es la siguiente. Llevas dos punteros axiliares, uno que es el que borraremos, y otro que es el anterior, llamemoslo aux, antaux.

antaux->[ANT_BORRAR], aux->[BORRAR], entonces, ahora haces que el puntero next del [ANT_BORRAR] apunte al siguiente a borrar, en este caso: antaux->next=aux->next, y ahora, ya el [BORRAR] queda excluido de la lista, ahora ya puedes borrarlo.

Espero haberme explicado bien, es un poco complicado explicar esto por aquí.


El problema que tengo entonces es que no sé como liberar el del original xD
Tio, ya no sé como hacerlo. Lo ultimo que he hecho esto:
ptrHead borrar(int coordx, int coordy, ptrHead p){
   if(p==NULL)
      return NULL;

   ptrTail t=p->first;
   ptrTail t1=p->first->next;
   while(t != NULL){
      if(t1->c.x == coordx && t1->c.y == coordy){
           t->next=t1->next;
           free(t1);
           p->numElem--;
      }
      t=t->next;

   }
   return p;
}


No sé como hacer lo que tu me dices. Donde me creo esos dos punteros? Si, son locales... Los saco de la función? No sé a que te refieres.
Donato escribió:
Chaky escribió:A ver, lo mejor es que te lo dibujes, es una forma sencilla de entender lo que estas haciendo.
Supongamos que el dato a borrar es [BORRAR], y t, t1 los punteros que tienes. Lo que veo que estas haciendo es esto:

t1->[BORRAR], t->[BORRAR], entonces luego haces que t->[SIG_BORRAR] y liberas la memoria a la que apunta t1 que es [BORRAR]. Pero ese t que apunta ahora a [SIG_BORRAR], no cambia nada en tu lista original, solo cambia la direccion de ese puntero que has creado localmente.

La idea, al menos siempre que hago una lista es la siguiente. Llevas dos punteros axiliares, uno que es el que borraremos, y otro que es el anterior, llamemoslo aux, antaux.

antaux->[ANT_BORRAR], aux->[BORRAR], entonces, ahora haces que el puntero next del [ANT_BORRAR] apunte al siguiente a borrar, en este caso: antaux->next=aux->next, y ahora, ya el [BORRAR] queda excluido de la lista, ahora ya puedes borrarlo.

Espero haberme explicado bien, es un poco complicado explicar esto por aquí.


El problema que tengo entonces es que no sé como liberar el del original xD


Jaja a ver, se que es algo lioso xD, cuando liberas estas liberando el bueno, es decir, te estas cargando el que es, el problema, es, el nodo anterior al que te estas cargado, no lo estas dejando al siguiente, solo dejas al siguiente la direccion de un puntero local. Lo que si puedes hacer, es, llevarte contigo un puntero que siempre este apuntando al anterior del que te quieres cargar. Entonces, a traves de este puntero, puedes acceder al next del anterior al que te vas a cargar y modificarlo para que apunte al siguiente del que te vas a cargar, si eso te ago un dibujito para que entiendas lo que digo, de la que me han salvado esos dichosos dibujitos xD.
He reditado mi post, a ver si es eso a lo que te refieres.
Donato escribió:He reditado mi post, a ver si es eso a lo que te refieres.

Excato, esa es la idea que queria trasmitir. Pero de esta manera, deberas crear antes un caso particuar, en el caso de que solo halla un elemento en la lista, ya que si solo hay uno, el primero que siempre vas a comprobar es realmente el segundo.
#include <stdio.h>
#include <stdlib.h>
#include "head_tail_list.h"

ptrTail actual=NULL, aux=NULL;

ptrHead anadir(int coordx, int coordy, ptrHead p){
   if(p == NULL){
      p=(ptrHead) malloc(sizeof(struct Head));
      p->first=(ptrTail) malloc(sizeof(struct Tail));
      p->numElem=1;
      p->first->c.x=coordx;
      p->first->c.y=coordy;
      p->first->next=NULL;
      p->last=p->first;
      return p;
   }
   p->last->next=(ptrTail) malloc(sizeof(struct Tail));
   p->last->next->c.x=coordx;
   p->last->next->c.y=coordy;
   p->last->next->next=NULL;
   p->last=p->last->next;
   p->numElem++;
   return p;
}

ptrHead borrar(int coordx, int coordy, ptrHead p){
   if(p->first->c.x == coordx && p->first->c.y == coordy){
       ptrTail t=p->first;
       p->first=p->first->next;
       free(t);
   }
   actual=p->first->next;
   aux=p->first;
   while(actual != NULL){
      if(actual->c.x == coordx && actual->c.y == coordy){
          if(actual == p->last){
            free(actual);
            p->last=aux;

          }
          else{
            aux->next=actual->next;
            free(actual);
          }
          p->numElem--;
      }
      else
        actual=actual->next;
   }
   return p;
}

void borrarTodo(ptrHead p){
   actual=p->first->next;
   aux=p->first;
   while(actual !=NULL){
      free(aux);
      aux=actual;
      actual=actual->next;
   }   
   free(p);
}
   
void imprimir(ptrHead p){
   int i=0;
   ptrTail t=p->first;
   printf("El número de nodos es %d\n", p->numElem);
   while(t!= NULL){
      printf("Nodo %d:\n Coordenada x %d\n Coordenada y %d\n", i, t->c.x, t->c.y);
      t=t->next;
      i++;
   }
}


Ultimos cambios.. Fugas de memoria a tutiplen. Me duele la cabeza, a ver si me das un poco mas de luz
Donato escribió:
#include <stdio.h>
#include <stdlib.h>
#include "head_tail_list.h"

ptrTail actual=NULL, aux=NULL;

ptrHead anadir(int coordx, int coordy, ptrHead p){
   if(p == NULL){
      p=(ptrHead) malloc(sizeof(struct Head));
      p->first=(ptrTail) malloc(sizeof(struct Tail));
      p->numElem=1;
      p->first->c.x=coordx;
      p->first->c.y=coordy;
      p->first->next=NULL;
      p->last=p->first;
      return p;
   }
   p->last->next=(ptrTail) malloc(sizeof(struct Tail));
   p->last->next->c.x=coordx;
   p->last->next->c.y=coordy;
   p->last->next->next=NULL;
   p->last=p->last->next;
   p->numElem++;
   return p;
}

ptrHead borrar(int coordx, int coordy, ptrHead p){
   if(p->first->c.x == coordx && p->first->c.y == coordy){
       ptrTail t=p->first;
       p->first=p->first->next;
       free(t);
   }
   actual=p->first->next;
   aux=p->first;
   while(actual != NULL){
      if(actual->c.x == coordx && actual->c.y == coordy){
          if(actual == p->last){
            free(actual);
            p->last=aux;

          }
          else{
            aux->next=actual->next;
            free(actual);
          }
          p->numElem--;
      }
      else
        actual=actual->next;
   }
   return p;
}

void borrarTodo(ptrHead p){
   actual=p->first->next;
   aux=p->first;
   while(actual !=NULL){
      free(aux);
      aux=actual;
      actual=actual->next;
   }   
   free(p);
}
   
void imprimir(ptrHead p){
   int i=0;
   ptrTail t=p->first;
   printf("El número de nodos es %d\n", p->numElem);
   while(t!= NULL){
      printf("Nodo %d:\n Coordenada x %d\n Coordenada y %d\n", i, t->c.x, t->c.y);
      t=t->next;
      i++;
   }
}


Ultimos cambios.. Fugas de memoria a tutiplen. Me duele la cabeza, a ver si me das un poco mas de luz


Vamos a ver, seguimos en la funcón borrar. Lo que haces en el caso de que sea el ultimo, esta incompleto, ya que aunq sea el ultimo de la lista, el peniltimo, que ahora es el ultimo, debes de dejarlo apuntando a NULL, ya que si no lo haces, cuando la recorras intetaras acceder a la memoria que ya has borrado. Por otro lado, esto:

else
actual=actual->next;

Si dejas este else ahí, me parece que una vez hallas eliminado, ese else no se va a cumplir, y no va a seguir avanzando en la lista, si dejas ese else, dentro del IF anterior tienes que dejar los puntero preparados para que prosiga el while.

Am casi se me olvida, lo primero que debes comprobar es si el primer elemento es NULL (p->first), porque si lo es, he intentas accerder al p->first->next, te a cascar, lo primero que debes comprbar esque p->first no sea nulo, y si no lo es ya haces todo lo demas.

PD: Por que usas el aux y actual como varibles globales?, no seria mas lógico usarlas como locales en la función?
Chaky escribió:
Donato escribió:
#include <stdio.h>
#include <stdlib.h>
#include "head_tail_list.h"

ptrTail actual=NULL, aux=NULL;

ptrHead anadir(int coordx, int coordy, ptrHead p){
   if(p == NULL){
      p=(ptrHead) malloc(sizeof(struct Head));
      p->first=(ptrTail) malloc(sizeof(struct Tail));
      p->numElem=1;
      p->first->c.x=coordx;
      p->first->c.y=coordy;
      p->first->next=NULL;
      p->last=p->first;
      return p;
   }
   p->last->next=(ptrTail) malloc(sizeof(struct Tail));
   p->last->next->c.x=coordx;
   p->last->next->c.y=coordy;
   p->last->next->next=NULL;
   p->last=p->last->next;
   p->numElem++;
   return p;
}

ptrHead borrar(int coordx, int coordy, ptrHead p){
   if(p->first->c.x == coordx && p->first->c.y == coordy){
       ptrTail t=p->first;
       p->first=p->first->next;
       free(t);
   }
   actual=p->first->next;
   aux=p->first;
   while(actual != NULL){
      if(actual->c.x == coordx && actual->c.y == coordy){
          if(actual == p->last){
            free(actual);
            p->last=aux;

          }
          else{
            aux->next=actual->next;
            free(actual);
          }
          p->numElem--;
      }
      else
        actual=actual->next;
   }
   return p;
}

void borrarTodo(ptrHead p){
   actual=p->first->next;
   aux=p->first;
   while(actual !=NULL){
      free(aux);
      aux=actual;
      actual=actual->next;
   }   
   free(p);
}
   
void imprimir(ptrHead p){
   int i=0;
   ptrTail t=p->first;
   printf("El número de nodos es %d\n", p->numElem);
   while(t!= NULL){
      printf("Nodo %d:\n Coordenada x %d\n Coordenada y %d\n", i, t->c.x, t->c.y);
      t=t->next;
      i++;
   }
}


Ultimos cambios.. Fugas de memoria a tutiplen. Me duele la cabeza, a ver si me das un poco mas de luz


Vamos a ver, seguimos en la funcón borrar. Lo que haces en el caso de que sea el ultimo, esta incompleto, ya que aunq sea el ultimo de la lista, el peniltimo, que ahora es el ultimo, debes de dejarlo apuntando a NULL, ya que si no lo haces, cuando la recorras intetaras acceder a la memoria que ya has borrado. Por otro lado, esto:

else
actual=actual->next;

Si dejas este else ahí, me parece que una vez hallas eliminado, ese else no se va a cumplir, y no va a seguir avanzando en la lista, si dejas ese else, dentro del IF anterior tienes que dejar los puntero preparados para que prosiga el while.

Am casi se me olvida, lo primero que debes comprobar es si el primer elemento es NULL (p->first), porque si lo es, he intentas accerder al p->first->next, te a cascar, lo primero que debes comprbar esque p->first no sea nulo, y si no lo es ya haces todo lo demas.

PD: Por que usas el aux y actual como varibles globales?, no seria mas lógico usarlas como locales en la función?


Como has dicho que son locales, pues nada, a variable globales xD

Aquí lo nuevo:
#include <stdio.h>
#include <stdlib.h>
#include "head_tail_list.h"

ptrHead anadir(int coordx, int coordy, ptrHead p){
   if(p == NULL){
      p=(ptrHead) malloc(sizeof(struct Head));
      p->first=NULL;
      p->last=NULL;
      p->numElem=0;
   }
   if(p->first == NULL){
        p->first=(ptrTail) malloc(sizeof(struct Tail));
      p->numElem=1;
      p->first->c.x=coordx;
      p->first->c.y=coordy;
      p->first->next=NULL;
      p->last=p->first;
      return p;
   }
   p->last->next=(ptrTail) malloc(sizeof(struct Tail));
   p->last->next->c.x=coordx;
   p->last->next->c.y=coordy;
   p->last->next->next=NULL;
   p->last=p->last->next;
   p->numElem++;
   return p;
}

ptrHead borrar(int coordx, int coordy, ptrHead p){
   if(p->first != NULL){
      ptrTail actual=NULL, aux=NULL;
      if(p->first->c.x == coordx && p->first->c.y == coordy){
         ptrTail t=p->first;
         p->first=p->first->next;
         free(t);
      }
      actual=p->first->next;
      aux=p->first;
      while(actual != NULL){
         if(actual->c.x == coordx && actual->c.y == coordy){
            if(actual == p->last){
               free(actual);
               p->last=aux;
               p->last->next=NULL;
            }
            else{
               aux->next=actual->next;
               free(actual);
            }
            p->numElem--;
         }
         actual=actual->next;
         aux=aux->next;
      }
   }
   return p;
}

void borrarTodo(ptrHead p){
   ptrTail actual=NULL, aux=NULL;
   actual=p->first->next;
   aux=p->first;
   while(actual !=NULL){
      free(aux);
      aux=actual;
      actual=actual->next;
   }   
   free(p);
}
   
void imprimir(ptrHead p){
   int i=0;
   ptrTail t=p->first;
   printf("El número de nodos es %d\n", p->numElem);
   while(t!= NULL){
      printf("Nodo %d:\n Coordenada x %d\n Coordenada y %d\n", i, t->c.x, t->c.y);
      t=t->next;
      i++;
   }
}


He mejorado el añadir y el borrar. Aun sigue habiendo fugas de memoria en el borrar pero el caso es que ya borra bien.
Donato escribió:
Chaky escribió:
Donato escribió:
#include <stdio.h>
#include <stdlib.h>
#include "head_tail_list.h"

ptrTail actual=NULL, aux=NULL;

ptrHead anadir(int coordx, int coordy, ptrHead p){
   if(p == NULL){
      p=(ptrHead) malloc(sizeof(struct Head));
      p->first=(ptrTail) malloc(sizeof(struct Tail));
      p->numElem=1;
      p->first->c.x=coordx;
      p->first->c.y=coordy;
      p->first->next=NULL;
      p->last=p->first;
      return p;
   }
   p->last->next=(ptrTail) malloc(sizeof(struct Tail));
   p->last->next->c.x=coordx;
   p->last->next->c.y=coordy;
   p->last->next->next=NULL;
   p->last=p->last->next;
   p->numElem++;
   return p;
}

ptrHead borrar(int coordx, int coordy, ptrHead p){
   if(p->first->c.x == coordx && p->first->c.y == coordy){
       ptrTail t=p->first;
       p->first=p->first->next;
       free(t);
   }
   actual=p->first->next;
   aux=p->first;
   while(actual != NULL){
      if(actual->c.x == coordx && actual->c.y == coordy){
          if(actual == p->last){
            free(actual);
            p->last=aux;

          }
          else{
            aux->next=actual->next;
            free(actual);
          }
          p->numElem--;
      }
      else
        actual=actual->next;
   }
   return p;
}

void borrarTodo(ptrHead p){
   actual=p->first->next;
   aux=p->first;
   while(actual !=NULL){
      free(aux);
      aux=actual;
      actual=actual->next;
   }   
   free(p);
}
   
void imprimir(ptrHead p){
   int i=0;
   ptrTail t=p->first;
   printf("El número de nodos es %d\n", p->numElem);
   while(t!= NULL){
      printf("Nodo %d:\n Coordenada x %d\n Coordenada y %d\n", i, t->c.x, t->c.y);
      t=t->next;
      i++;
   }
}


Ultimos cambios.. Fugas de memoria a tutiplen. Me duele la cabeza, a ver si me das un poco mas de luz


Vamos a ver, seguimos en la funcón borrar. Lo que haces en el caso de que sea el ultimo, esta incompleto, ya que aunq sea el ultimo de la lista, el peniltimo, que ahora es el ultimo, debes de dejarlo apuntando a NULL, ya que si no lo haces, cuando la recorras intetaras acceder a la memoria que ya has borrado. Por otro lado, esto:

else
actual=actual->next;

Si dejas este else ahí, me parece que una vez hallas eliminado, ese else no se va a cumplir, y no va a seguir avanzando en la lista, si dejas ese else, dentro del IF anterior tienes que dejar los puntero preparados para que prosiga el while.

Am casi se me olvida, lo primero que debes comprobar es si el primer elemento es NULL (p->first), porque si lo es, he intentas accerder al p->first->next, te a cascar, lo primero que debes comprbar esque p->first no sea nulo, y si no lo es ya haces todo lo demas.

PD: Por que usas el aux y actual como varibles globales?, no seria mas lógico usarlas como locales en la función?


Como has dicho que son locales, pues nada, a variable globales xD

Aquí lo nuevo:
#include <stdio.h>
#include <stdlib.h>
#include "head_tail_list.h"

ptrHead anadir(int coordx, int coordy, ptrHead p){
   if(p == NULL){
      p=(ptrHead) malloc(sizeof(struct Head));
      p->first=NULL;
      p->last=NULL;
      p->numElem=0;
   }
   if(p->first == NULL){
        p->first=(ptrTail) malloc(sizeof(struct Tail));
      p->numElem=1;
      p->first->c.x=coordx;
      p->first->c.y=coordy;
      p->first->next=NULL;
      p->last=p->first;
      return p;
   }
   p->last->next=(ptrTail) malloc(sizeof(struct Tail));
   p->last->next->c.x=coordx;
   p->last->next->c.y=coordy;
   p->last->next->next=NULL;
   p->last=p->last->next;
   p->numElem++;
   return p;
}

ptrHead borrar(int coordx, int coordy, ptrHead p){
   if(p->first != NULL){
      ptrTail actual=NULL, aux=NULL;
      if(p->first->c.x == coordx && p->first->c.y == coordy){
         ptrTail t=p->first;
         p->first=p->first->next;
         free(t);
      }
      actual=p->first->next;
      aux=p->first;
      while(actual != NULL){
         if(actual->c.x == coordx && actual->c.y == coordy){
            if(actual == p->last){
               free(actual);
               p->last=aux;
               p->last->next=NULL;
            }
            else{
               aux->next=actual->next;
               free(actual);
            }
            p->numElem--;
         }
         actual=actual->next;
         aux=aux->next;
      }
   }
   return p;
}

void borrarTodo(ptrHead p){
   ptrTail actual=NULL, aux=NULL;
   actual=p->first->next;
   aux=p->first;
   while(actual !=NULL){
      free(aux);
      aux=actual;
      actual=actual->next;
   }   
   free(p);
}
   
void imprimir(ptrHead p){
   int i=0;
   ptrTail t=p->first;
   printf("El número de nodos es %d\n", p->numElem);
   while(t!= NULL){
      printf("Nodo %d:\n Coordenada x %d\n Coordenada y %d\n", i, t->c.x, t->c.y);
      t=t->next;
      i++;
   }
}


He mejorado el añadir y el borrar. Aun sigue habiendo fugas de memoria en el borrar pero el caso es que ya borra bien.


Ajam, yo por lo que veo creo que ya esta bien, habría que ver que y cuando ocurren esas fugas, que siempre se escapa algo. Los de añadir y tal me lio un poco porque suelo programar en c++, y suelo usar el new y delete, con los malloc estos ya no me acuerdo apenas y me ago la pixa un lio xD
Da igual, muchisimas gracias tio ;)
Estoy ecándole un vistazo y lo primero que veo es que borrarTodo no borra bien una lista de un solo elemento.

Actualizaré el post si veo cosas raras.

- ferdy
Ferdy escribió:Estoy ecándole un vistazo y lo primero que veo es que borrarTodo no borra bien una lista de un solo elemento.

Actualizaré el post si veo cosas raras.

- ferdy


Gracias ^^
borrar tambien falla si quieres borrar el único elemento de la lista.
borrar no actualiza bien numElements si borra el primer elemento de una lista.
A borrar no le gusta que le pases una lista inexistente (p == NULL).
borrarTodo realmente no funciona. Siempre se deja un elemento sin borrar. Da igual la longitud de la lista.

En fin... que a repasar el código o a estudiar un poco más. Un libro muy didáctico para estas cosas es "Mastering Algorithms with C" de Kyle Loudon.

- ferdy

PS: ¿Quién es tu compañero de prácticas?
Ferdy escribió:borrar tambien falla si quieres borrar el único elemento de la lista.
borrar no actualiza bien numElements si borra el primer elemento de una lista.
A borrar no le gusta que le pases una lista inexistente (p == NULL).
borrarTodo realmente no funciona. Siempre se deja un elemento sin borrar. Da igual la longitud de la lista.

En fin... que a repasar el código o a estudiar un poco más. Un libro muy didáctico para estas cosas es "Mastering Algorithms with C" de Kyle Loudon.

- ferdy

PS: ¿Quién es tu compañero de prácticas?



Te he mandado un mp. Gracias por echarle un vistazo.
27 respuestas