| Ver tema anterior :: Ver siguiente tema | | Autor | Mensaje |
|---|
polly
Registrado: 19 Jul 2007 Mensajes: 61
| Publicado: 19/09/2007 1:43 pm | | | Título: problema : listas enlazadas |
| buenas , tengo la siguiente funcion:
| Código: | void insertar ( Nodo** cabeza, Item entrada) { Nodo* nuevo; nuevo=(Nodo*)malloc(sizeof(Nodo)); nuevo->dato=entrada; nuevo->siguiente=*cabeza; *cabeza=nuevo; }
con la estructura Nodo definida asi:
typedef int Item; typedef struct nodo { Item dato; struct nodo* siguiente; }Nodo;
|
mi duda es porque se pone (como argumento) Nodo**cabeza y no Nodo*cabeza ?? se supone que nodo cabeza apunta al primer elemento de la lista y (aunque no lo he puesto)
cabeza->dato = 5; cabeza->dato=NULL;
luego se hace que el nodo nuevo apunte a cabeza para insertar un nuevo elemento al principio de la lista no ?
de todas formas , podriais ponerme el codigo de : una lista con un solo elemento int , luego añadir un nuevo elemento a la cabeza ,,,gracias _________________ R.I.P Kurt Cobain ------------------------- |
| | Volver arriba | |  | david_celta
Registrado: 02 Jun 2005 Mensajes: 45
| Publicado: 19/09/2007 4:14 pm | | | Título: |
| Con clases:
class nodo { private: int dato; nodo *sgte;
public: nodo(int d,nodo*s) {dato=d;sgte=s;} };
void main() { nodo *cabeza=NULL; cabeza=new nodo(5,cabeza); cabeza=new nodo(4,cabeza); }
o alternativamente:
class lista { private: nodo *cabeza; public: lista(){cabeza=NULL;} void insertar(int d){cabeza=new nodo(d,cabeza);} };
void main() { lista l; l.inserta(5); l.inserta(4); }
-----------------------------
Nodo ** pasas un puntero a la funcion para que guarde que no se pierda el valor que asignas
Nodo * pasas el valor del puntero Nodo &* pasas una referencia al puntero
Por ejemplo si fuera una variable en vez de un puntero (supongo que sabes sobre pasos por valor y pasos por referencia en las funciones)
funcion(int a) { a=5; }
main() { a=4; funcion(a); //aqui a sigue valiendo 4 porque lo que se pasa a la funcion es el valor de a (que es 4) y no la variable a }
en cambio si fuera funcion(&a) { a=5; }
o en todo caso
funcion (*a) { *a=5; }
el valor de a si cambiaria en el main
Sucede lo mismo con los punteros *p,**p y &*p
Solo imagina el *p como una variable cualquiera
De paso puedes cambiarla con el typedef de esta forma:
typedef nodo * tiponodo;
A ver si asi se entiende mejor
typedef int Item; typedef struct nodo { Item dato; struct nodo* siguiente; }Nodo;
typedef nodo* tiponodo;
void insertar ( tiponodo * cabeza, Item entrada) { tiponodo nuevo; nuevo=(tiponodo)malloc(sizeof(Nodo)); nuevo->dato=entrada; nuevo->siguiente=*cabeza;
*cabeza=nuevo; }
void insertar ( tiponodo & cabeza, Item entrada) { tiponodo nuevo; nuevo=(tiponodo)malloc(sizeof(Nodo)); nuevo->dato=entrada; nuevo->siguiente=cabeza;
cabeza=nuevo; }
De todas maneras la version con clases la tienes como una alternativa en c++
- esto es solo una idea, hay que verificarla - _________________ Este es un bloque de texto que se puede agregar a los mensajes que publique. Texto Compilado en C++. 0 errors y 1 un warning. |
| | Volver arriba | |  | tonilope
Registrado: 16 Oct 2005 Mensajes: 249
| Publicado: 19/09/2007 4:32 pm | | | Título: |
| | Cita: | mi duda es porque se pone (como argumento) Nodo**cabeza y no Nodo*cabeza ?? se supone que nodo cabeza apunta al primer elemento de la lista y (aunque no lo he puesto)
cabeza->dato = 5; cabeza->dato=NULL;
luego se hace que el nodo nuevo apunte a cabeza para insertar un nuevo elemento al principio de la lista no ?
de todas formas , podriais ponerme el codigo de : una lista con un solo elemento int , luego añadir un nuevo elemento a la cabeza ,,,gracias _________________
|
La razón de mandarle un puntero doble a la función es porque en C TODOS los parámetros se pasan por copia y si quieres modificar una variable declarada fuera de la función tienes que enviarle un puntero a dicha variable. En tu caso, lo que quieres modificar es el valor de un puntero a NODO, así que le envías un puntero a un puntero a NODO (puntero doble a NODO).
EJEMPLO INCORRECTO:
| Código: |
typedef int Item;
typedef struct nodo { Item dato; struct nodo* siguiente; }Nodo;
void insertar ( Nodo *cabeza, Item entrada) { Nodo* nuevo; nuevo=(Nodo*)malloc(sizeof(Nodo)); nuevo->dato=entrada; nuevo->siguiente=cabeza; cabeza=nuevo; // MAL. NO estamos modificando el puntero cabeza del main(), sino el de una COPIA de dicho puntero. (Al salir de la función esa copia se destruirá). }
int main() { Nodo *cabeza=NULL;
//Insertamos un nodo en la lista insertar(cabeza, 1);
/* Si la función insertar estuviera bien definida cabeza apuntaría al nuevo nodo, pero en este caso, el puntero cabeza NO ha sido modificado dentro de la función insertar() y por tanto sigue valiendo NULL */
return 0;
}
|
EJEMPLO CORRECTO:
| Código: |
typedef int Item;
typedef struct nodo { Item dato; struct nodo* siguiente; }Nodo;
void insertar ( Nodo **cabeza, Item entrada) { Nodo* nuevo; nuevo=(Nodo*)malloc(sizeof(Nodo)); nuevo->dato=entrada; nuevo->siguiente=*cabeza; *cabeza=nuevo; //Ahora sí que estamos modificando el valor del puntero cabeza del main
}
int main() { Nodo *cabeza=NULL;
//Insertamos un nodo en la lista insertar(&cabeza, 1);
/* Ahora el puntero cabeza apunta al nuevo NODO. */
return 0;
}
|
Salu2  _________________ Be (void *) my friend |
| | Volver arriba | |  | | polly
Registrado: 19 Jul 2007 Mensajes: 61
| Publicado: 20/09/2007 3:09 am | | | Título: |
| gracias a ambos , ahora ya me aclaro el porque de mandarle NODO** , _________________ R.I.P Kurt Cobain ------------------------- |
| | Volver arriba | |  | cheroky
Registrado: 22 Sep 2005 Mensajes: 1372 Ubicación: En ecx esperando un call
| Publicado: 21/09/2007 3:17 am | | | Título: |
| Intentaré arrojar algo de luz desde la óptica del roll que juega el procesador y la pila en el paso de parámetros, en lo que concierne a los punteros y a lo que comúnmente se denomina "paso por referencia".
Supongamos una función común del estilo:
| Código: | void foo(int *p) { *p = 456; } |
Un puntero a int al cual en su indirección se le asigna el valor entero decimal 456. Para que esto se lleve a cabo la variable puntero p, debe almacenar una dirección de memoria, esta dirección es pasada a la pila desde la función llamante:
| Código: | /* */ int v = 0; foo(&v); /* en este punto (v) vale 456 */ /* */
|
Esto implica unas serie de instrucciones a bajo nivel, las que se van a reseñar son las típicas en arquitecturas x86 y pueden diferir en el tipo compilador siendo el mecanismo similar.
En la funcion que llama:
| Código: | ; .. sub esp, 8 ;Espacio en la pila, (2 * 4 bytes) 1 para la variable (v), 2 para su copia ;El puntero de pila decrece al aumentar esta.
mov [esp+4], 0 ;En este punto [esp+4] es nuestra variable
lea eax, [esp+4] ;Copiamos en el registro eax la dirección efectiva de [esp+4]
mov [esp], eax ;La movemos a la cabeza de la pila TOS (Top of Stack) convención de llamada C
call foo ;Llamamos a la función ; .. |
En este punto la copia se hace antes de llamar a la función y se observa que esta copia es el valor correspondiente a una dirección de memoria (léase dirección de la variable), lo que se traduce en la rutina C en:
Ahora entramos en otro contexto y otro marco de pila (stack frame), el de la función llamada.
| Código: | ; .. mov eax, [ebp+8] ;En este contexto [ebp+8] es el TOS en el stack frame anterior ;movemos a eax la dirección que teníamos
mov [eax], 456 ;esto es similar a una indireción C, movemos 456 a eax ; .. |
En este punto ya hemos asignado a la variable (v) un valor efectivo por medio de su dirección de memoria.
Con los punteros a punteros ocurre exactamente lo mismo, salvo que el valor que hay que asignar no corresponde a un valor arbitrario sino a una dirección de memoria efectiva, en este caso que nos ocupa, seria el retorno de la dirección de funciones como malloc, calloc, etc.
Hay que hacer notar que las referencias de C++ se implementan con el mismo mecanismo, es el compilador el que marca las restricciones en tiempo de diseño.
S2. _________________ - Explícito es mejor que implícito. - Simple es mejor que complejo. - Complejo es mejor que complicado. - Plano es mejor que anidado. - Ralo es mejor que denso. |
| | Volver arriba | |  | | |
| No puede crear mensajes No puede responder temas No puede editar sus mensajes No puede borrar sus mensajes No puede votar en encuestas
|
|
| |