Discussion:
assignment from incompatible pointer type
(demasiado antiguo para responder)
Olaf "El Blanco"
2006-06-10 16:48:19 UTC
Permalink
No entiendo cual es el problema, trato de agregar un solo entero al final y
el compilador me avisa de ese error.
También tengo una pregunta dentro de la función:

struct _nodo {
int dato;
struct nodo *sig;
};

typedef struct _nodo nodo;

/* ¿Cual es exactamente la diferencia entre **nodo y *nodo
Veo que muchos abajo del anterior typedef crean algo asi
typedef *nodo NODO; */


int esta_vacia(nodo *lista)
{
return (lista==NULL);
}

void insertar_dato(nodo **lista, int dato)
{
nodo *antes, *despues, *nuevo;
nuevo= (nodo*)malloc(sizeof(nodo));
nuevo->dato = dato;
if (esta_vacia(*lista))
*lista=nuevo;
else {
antes = *lista;
despues = antes->sig;
while (despues != NULL) {
antes = despues;
despues = despues->sig;
}
antes->sig = nuevo;
nuevo->sig = NULL;
}
}
Oscar Garcia
2006-06-10 17:39:37 UTC
Permalink
El Sat, 10 Jun 2006 18:48:19 +0200, "Olaf \"El Blanco\""
Post by Olaf "El Blanco"
No entiendo cual es el problema, trato de agregar un solo entero al final y
el compilador me avisa de ese error.
struct _nodo {
int dato;
struct nodo *sig;
};
¿No querrías decir...?

struct _nodo {
int dato;
struct _nodo *sig;
};

Prueba ahora.

Un saludo.
--
Óscar Javier García Baudet
LinaresDigital
http://redstar.linaresdigital.com/
Oscar Garcia
2006-06-10 17:43:19 UTC
Permalink
El Sat, 10 Jun 2006 18:48:19 +0200, "Olaf \"El Blanco\""
Post by Olaf "El Blanco"
/* ¿Cual es exactamente la diferencia entre **nodo y *nodo
Veo que muchos abajo del anterior typedef crean algo asi
typedef *nodo NODO; */
*nodo es un puntero que apunta a los datos almacenados.

**nodo es el puntero a dicho puntero.

Cuando quieres modificar el puntero inicial debes pasarlo por
referencia, es decir... pasar un puntero a dicho puntero (ole el
galimatías :).

Un saludo.
--
Óscar Javier García Baudet
LinaresDigital
http://redstar.linaresdigital.com/
Olaf (2)
2006-06-10 18:07:44 UTC
Permalink
Post by Oscar Garcia
El Sat, 10 Jun 2006 18:48:19 +0200, "Olaf \"El Blanco\""
Post by Olaf "El Blanco"
/* ¿Cual es exactamente la diferencia entre **nodo y *nodo
Veo que muchos abajo del anterior typedef crean algo asi
typedef *nodo NODO; */
*nodo es un puntero que apunta a los datos almacenados.
**nodo es el puntero a dicho puntero.
Cuando quieres modificar el puntero inicial debes pasarlo por
referencia, es decir... pasar un puntero a dicho puntero (ole el
galimatías :).
Un saludo.
Como siempre, Oscar... Eres un grande. Gracias.
Si quiero modificar la lista, uso los dos asteriscos, dirección, de
dirección...
Pero si no quiero modificar el puntero inicial, también debo pasarle **nodo?
Creía dominar este tema, pero parece que no...
Lo siguiente no me termina de cerrar, (dentro del Crea_Lista) funciona
perfecto, pero por haber echo prueba y error, no razono, porque al
"insertar_principio(lista, n);" no le paso la dirección de lista, o sea:
insertar_principio(&lista, n);

void Crea_Lista(int tam, nodo **lista)
{
int n;
for (n=tam; n>=0; n--)
insertar_principio(lista, n);
}

void insertar_principio(nodo **lista, int dato)
{
nodo *nuevo;
nuevo= (nodo*)malloc(sizeof(nodo));
nuevo->dato = dato; /* Porque no uso asteriscos aqui, si quiero
decirle que el CONTENIDO de
nuevo->dato sea dato? */
if (esta_vacia(*lista))
*lista=nuevo; ¿Porque no lista=nuevo? lista es un puntero
a los datos almacenados.
else {
nuevo->sig = *lista;
*lista = nuevo;
}
}

Las cosas salen, pero no lo estoy RAZONANDO. De antemano Gracias!
Oscar Garcia
2006-06-10 18:46:55 UTC
Permalink
Post by Olaf (2)
Pero si no quiero modificar el puntero inicial, también debo pasarle **nodo?
Exacto.

Aunque quizá no deberías hacerlo.

El primer nodo debería existir SIEMPRE y que valga "sig" NULL en caso
de ser una lista vacía o cualquier otro valor si existen elementos.

Como puedes ver eso implica que no es necesario cambiar para nada el
puntero inicial, de modo que puedes evitar el uso de "nodo **lista".

En tu caso, quizá estás planteando mal cómo inicializar la lista. Yo
usaría el primer elemento como referencia y no como un dato en sí.

Así, agregar un elemento al comienzo de la lista sería tal y como:

1.- Crear nuevo elemento en NUEVO.
2.- Asignar el valor a NUEVO.
3.- Cambiar el valor de NUEVO->sig a PRIMERO->sig.
4.- Cambiar el valor de PRIMERO->sig a NUEVO.

Como puedes ver no es necesario de esta manera saber si la lista está
previamente vacía o no.

Yo, por otro lado, usaría el primer eslabón de la cadena con un tipo
distinto, en el que se podría almacenar el número de elementos (por
ejemplo).
Post by Olaf (2)
Creía dominar este tema, pero parece que no...
Lo siguiente no me termina de cerrar, (dentro del Crea_Lista) funciona
perfecto, pero por haber echo prueba y error, no razono, porque al
insertar_principio(&lista, n);
No me dices cómo has definido "lista" antes de enviarla como
parámetro, pero tiene pinta de ser nodo **lista, que es exactamente el
tipo de datos que necesitamos.
Post by Olaf (2)
void insertar_principio(nodo **lista, int dato)
{
nodo *nuevo;
nuevo= (nodo*)malloc(sizeof(nodo));
nuevo->dato = dato; /* Porque no uso asteriscos aqui, si quiero
decirle que el CONTENIDO de
nuevo->dato sea dato? */
En tu caso es porque nuevo es un puntero a una estructura de tipo
"nodo" de modo que para acceder a sus datos necesitas usar el
modificador ->. Si hubieras puesto:

(*nuevo).dato = dato;

hubieras tenido el mismo resultado.
Post by Olaf (2)
if (esta_vacia(*lista))
*lista=nuevo; ¿Porque no lista=nuevo? lista es un puntero
a los datos almacenados.
Porque como te he dicho antes lista es un puntero que apunta a un
puntero al primer elemento.

Entonces hay que cambiar ese puntero (al que apunta lista) para que
apunte a la nueva estructura.
Post by Olaf (2)
else {
nuevo->sig = *lista;
*lista = nuevo;
}
}
Las cosas salen, pero no lo estoy RAZONANDO. De antemano Gracias!
Poco a poco las irás comprendiendo :)

Un saludo.
--
Óscar Javier García Baudet
LinaresDigital
http://redstar.linaresdigital.com/
Olaf (2)
2006-06-11 16:47:27 UTC
Permalink
Creo que si me explicas esta diferencia, se iran mis dudas.
A propósrito, ¿tu me recomiendas que cuando trabaje con listas cree, un
campo mas (que se repetira en todos los nodos) con la cantidad de elementos
actual de la lista??


Ahi va:

struct _nodo {
int cantidad;
int dato;
struct _nodo *sig;
};
typedef struct _nodo nodo;

void insertar(nodo **lista, int esto)
{
nodo *nuevo;
nuevo=(nodo*)malloc(sizeof(nodo));
(*nuevo).dato=esto;
nuevo->sig = *lista;
*lista=nuevo;
}

void iniciar(nodo **lista)
{
*lista=NULL;
}

main()
{
nodo *lista;

Acabo de declarar la variable de la lista.
Y ahora puedo hacer dos cosas para inicializarla:
1) lista=NULL
2) iniciar(&lista);

Olvidándonos de porque hacer un procedimiento para hacer eso solo... Te
pregunto:
"inciar" necesita recibir una direccion de memoria, por eso el &.
La direccion de memoria que recibe NO ES la direccion del primer
nodo verdad? Es la direccion que tiene un puntero a ese primer nodo?

Bien,

Pero dentro del procedimiento iniciar, utilizo "*lista=NULL"
¿porque? Si lista es un puntero a una estructura _nodo (NO A NINGUN NODO
PARTICULAR)
Y dentro del procedimeinto le estoy diciendo que el contenido de esa
direccion (o sea otra direccion, pero esta SI del primer nodo)
sea NULL. es cierto eso?

Entonces porque, si utilizo la otra alternativa:
directamente un "lista=NULL" en el main hace exactamente lo mismo?

Obviamente interpreto mal, porque no le deberia encontrar diferencia,
hacen exactamente lo mismo.
Espero, me hayas entendido:
Se trata de diferenciar:

1) lista=NULL

2) void iniciar(nodo **lista) { *lista=NULL; }

Supongo que me complico con la sintaxis de los parametros.


Saludos.
Super_Lopez
2006-06-11 18:38:14 UTC
Permalink
[..] ¿tu me recomiendas que cuando trabaje con listas
cree, un campo mas (que se repetira en todos los nodos)
con la cantidad de elementos actual de la lista??
Hombre, es un desperdicio de memoria ingente y no aporta nada.
Mejor almacenar ese dato en otro sitio (fuera de la lista) y
actualizarlo convenientemente desde las propias funciones que
gestionan la lista, ¿no?
[..] Pero dentro del procedimiento iniciar, utilizo
"*lista=NULL" ¿porque? Si lista es un puntero a una
estructura _nodo (NO A NINGUN NODO PARTICULAR) [..]
No he seguido el hilo, pero sospecho que es simplemente porque
el "primer" elemento debe ser siempre nulo, para manejar el
recorrido y saber cuándo detenerse.

Esto es así porque cuando añades un nuevo elemento, no lo añades
"después del primero" (i.e. el primero apuntando a este nuevo, y
el nuevo apuntando a un "siguiente" nulo) sino que directamente
el nuevo apunta al inicio de la lista (pasa a ser el primero) y
el resto permanece igual. Ahorras la mitad de asignaciones.

Un saludo.
Super_Lopez
2006-06-11 18:54:25 UTC
Permalink
[..] No he seguido el hilo, pero sospecho que es
simplemente porque el "primer" elemento debe [..]
Creo que debería leerme primero el hilo :)
No hagas mucho caso de lo que comento en mi respuesta anterior.
arrase
2006-06-11 23:26:31 UTC
Permalink
Post by Olaf (2)
A propósrito, ¿tu me recomiendas que cuando trabaje con listas cree, un
campo mas (que se repetira en todos los nodos) con la cantidad de elementos
actual de la lista??
Guardar eso en todos los nodos es un gasto inutil de memoria y trabajo,
cada vez que almacenas un nuevo nodo tendrias que actualizar ese valor
en todos.

Personalmente, para listas simples sin nodos centinelas ni de mas
historias, prefiero usar esta estructura:

struct Nodo{
int data;
struct Nodo *next;
};

struct Lista{
int size;
struct Nodo *first,
*last;
};

Saludos.
--
<***@gulcas.org><http://arrase.no-ip.org><www.gulcas.org>
<Gnupg Keys: http://arrase.no-ip.org/pubkey.txt>

print "".join(map(lambda numChar:filter(lambda x:(x<"0") or \
(x>"9"),numChar),["0"+chr(104)+"0","1"+chr(111)+"1","2"+chr(108)+"2", \
"3"+chr(97)+"3","4"+chr(32)+"4","5"+chr(109)+"5","6"+chr(117)+"6", \
"7"+chr(110)+"7","8"+chr(100)+"8","9"+chr(111)+"9"]))
Oscar Garcia
2006-06-11 23:39:23 UTC
Permalink
Post by Olaf (2)
Creo que si me explicas esta diferencia, se iran mis dudas.
A propósrito, ¿tu me recomiendas que cuando trabaje con listas cree, un
campo mas (que se repetira en todos los nodos) con la cantidad de elementos
actual de la lista??
No hombre, lo has entendido mal.

Creas una estructura tal que:

typedef struct {
int cantidad;
nodo *primero;
} _lista;

De modo que creamos la lista así:

_lista *crear_lista (void) {
_lista *lista = malloc (sizeof(_lista));
if (lista) {
return lista;
} else {
return NULL;
}
}

Para insertar un elemento al principio de la lista sería:

int insertar_primero (_lista *lista, int dato) {
nodo *nuevo;

nuevo = (nodo *) malloc (sizeof (nodo));
if (nuevo) {
nuevo->dato = dato;
nuevo->sig = lista->primero;
lista->primero = nuevo;
return 0;
} else {
return 1;
}
}

Para crearlo al final sería:

int insertar_ultimo (_lista *lista, int dato) {
nodo *nuevo, **token;

nuevo = (nodo *) malloc (sizeof (nodo));
if (nuevo) {
nuevo->dato = dato;
nuevo->sig = NULL;
for (token = &nuevo->sig; (*token)->sig;
token = &(*token)->sig);
(*token)->sig = nuevo;
return 0;
} else {
return 1;
}
}
Post by Olaf (2)
Olvidándonos de porque hacer un procedimiento para hacer eso solo... Te
"inciar" necesita recibir una direccion de memoria, por eso el &.
La direccion de memoria que recibe NO ES la direccion del primer
nodo verdad? Es la direccion que tiene un puntero a ese primer nodo?
Yo haría que iniciar devolviera el puntero a la estructura ya
inicializada como puedes ver en mi ejemplo.
Post by Olaf (2)
Pero dentro del procedimiento iniciar, utilizo "*lista=NULL"
¿porque? Si lista es un puntero a una estructura _nodo (NO A NINGUN NODO
PARTICULAR)
lista apunta a un puntero que a su vez apunta a un puntero que debería
apuntar al primer elemento, pero en esa línea hacemos que apunte a
NULL.

Es decir.. metemos en la dirección de memoria al que apunta un NULL
(que es una zona de memoria donde se guarda el puntero al primer
elemento).
Post by Olaf (2)
Y dentro del procedimeinto le estoy diciendo que el contenido de esa
direccion (o sea otra direccion, pero esta SI del primer nodo)
sea NULL. es cierto eso?
No entiendo el sentido de esa frase.
Post by Olaf (2)
directamente un "lista=NULL" en el main hace exactamente lo mismo?
No, lista es una variable alojada en la zona de memoria reservada para
las variables privadas de la función, de modo que cuando salgas de la
función ese NULL se pierde.

Cuando pasas un parámetro por valor, se aloja en la pila dicho valor y
al finalizar la función la pila se restablece sin más.
Post by Olaf (2)
Obviamente interpreto mal, porque no le deberia encontrar diferencia,
hacen exactamente lo mismo.
1) lista=NULL
Asignamos NULL a una variable local, lo cual no afectará nada al
programa porque dicho valor se desvanecerá nada más finalizar la
función.
Post by Olaf (2)
2) void iniciar(nodo **lista) { *lista=NULL; }
Cambiamos la zona de memoria a la que apunta el parámetro por el valor
NULL (es decir.. cambiamos el puntero llamado "lista" por NULL).
Post by Olaf (2)
Supongo que me complico con la sintaxis de los parametros.
No, simplemente aún no controlas bien los punteros. Ojalá te tubiera
delante para hacerte una clase típica de punteros en la pizarra :)
Seguro que lo pillarías fácilmente.

Un saludo.
--
Óscar Javier García Baudet
LinaresDigital
http://redstar.linaresdigital.com/
Oscar Garcia
2006-06-11 23:46:35 UTC
Permalink
El Mon, 12 Jun 2006 01:39:23 +0200, Oscar Garcia
Post by Oscar Garcia
_lista *crear_lista (void) {
_lista *lista = malloc (sizeof(_lista));
if (lista) {
lista->primero = NULL
lista->cantidad = 0;
Post by Oscar Garcia
return lista;
} else {
return NULL;
}
}
int insertar_primero (_lista *lista, int dato) {
nodo *nuevo;
nuevo = (nodo *) malloc (sizeof (nodo));
if (nuevo) {
nuevo->dato = dato;
nuevo->sig = lista->primero;
lista->primero = nuevo;
lista->cantidad++;
Post by Oscar Garcia
return 0;
} else {
return 1;
}
}
int insertar_ultimo (_lista *lista, int dato) {
nodo *nuevo, **token;
nuevo = (nodo *) malloc (sizeof (nodo));
if (nuevo) {
nuevo->dato = dato;
nuevo->sig = NULL;
for (token = &nuevo->sig; (*token)->sig;
for (token = &lista->primero; (*token)->sig;
Post by Oscar Garcia
token = &(*token)->sig);
(*token)->sig = nuevo;
lista->cantidad++;
Post by Oscar Garcia
return 0;
} else {
return 1;
}
}
Fallos del directo :)

(No lo he compilado ni probado, pero teóricamente debería funcionar
todo bien).

Un saludo.
--
Óscar Javier García Baudet
LinaresDigital
http://redstar.linaresdigital.com/
Loading...