Listas en C++

Iniciado por farresito, 9 Marzo 2011, 15:01 PM

0 Miembros y 1 Visitante están viendo este tema.

farresito

Hola a todos,

Tengo una pequeña duda que no acabo de resolver; es muy simple, pero es por quitármela de encima. Tengo este código, que funciona perfectamente, pues lo he quitado del libro del que estoy estudiando, pero no logro entender una cosa concreta. El el código siguiente, cuando se declara la estructura STRUCT T_NODO *PRINCIPIO, si solo es un puntero que indica el inicio de toda la lista, no podria declarar una variable puntero normal que guardase la direccion de memoria del lugar donde se inicia la la lista?. Esto es lo que tengo

Código (cpp) [Seleccionar]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;

struct t_nodo
{
    int numero; // Almacena los datos del nodo
    t_nodo *siguiente; // Variable puntero a otra estructura t_nodo
};

struct t_nodo *principio = NULL;


int main (void)
{
    //Declaro la funcion; lo podria haber puesto todo junto pero da igual
    void insertar_al_principio (struct t_nodo *&p);

}

void insertar_al_principio (struct t_nodo *&p)
{
    struct t_nodo *nuevo_nodo;

    // Creamos nuevo nodo

    nuevo_nodo = new struct t_nodo;

    // Rellenamos los campos de datos

    cout << "Escriba un numero: " << endl;
    cin >> nuevo_nodo->numero;

    /* Insertamos el nuevo nodo al principio de la lista */
    nuevo_nodo->siguiente = p;
    p = nuevo_nodo;
}


Gracias de antemano. Un abrazo!

Akai

#1
Para apuntar a una lista, necesitas un puntero a lista, y si tu lista es un "struct t_nodo" necesitas para apuntarlo un "struct tnodo"* . No hay un "puntero genérico" y tampoco puedes apuntar a una dirección de memoria en concreto, porque tu programa NUNCA (bueno, vale, puede suceder) se va a ejecutar en la misma sección de memoria, o va a declarar su memoria dinámica en la misma dirección, sino que la dirección se la dará el sistema operativo teniendo en cuenta lo que quede libre en ese momento.

Cuando tu declaras un puntero a entero, ese puntero está hecho para apuntar a una zona de memoria de 4 bytes (u 8, según la máquina) cuyo contenido se procesa como número entero. En cambio, no puedes tuilizar un puntero a entero para apuntar a un char, porque el char ocupa 1/4 de un entero, y por tanto, te comes el char y 3 de su alrededor.

Lo mismo pasa con las estructuras, cuando tu declaras un puntero a una estructura, digamos que preparas el puntero para hacer referencia a los campos de dicha estructura.

farresito

Gracias Akai, me lo dejaste claro ;)

Ahora también me surgió la duda de porque uso *&p. El ampersand se que se usa para recibir la dirección de memoria de alguna variable o cualquier cosa si lo pongo delante, pero en este caso, no podría pasar por parámetros directamente struct t_nodo *p?
Me suena haber leído que los parámetros con & hace que no se copie el valor de la variable y se trabaje con ella sino que lo que se hace es trabajar directamente con la propia variable. Es correcto lo que digo o me olvido de algo?

Gracias, un abrazo

Akai

Te comento, en C++, cuando tu utilizas el & en la cabecera de una función, como en el caso:
Código (cpp) [Seleccionar]
void insertar_al_principio (struct t_nodo *&p)

Lo que se está diciendo es : En vez de pasarme una copia de p, quiero que me lo pases por referencia. Con esto se consiguen dos cosas: no copias la estructura, y cualquier cambio que hagas dentro de la función se mantendrá fuera.

Posiblemente sea más claro de leer si estuviese puesto así:
Código (cpp) [Seleccionar]
void insertar_al_principio (struct t_nodo* &p)
De esta forma, digamos que dices que recibes un puntero a nodo, pasado por referencia.

La diferencia entre pasar por referencia y por copia es la siguiente:

Suponiendo que nuestra variable vale 4
Código (cpp) [Seleccionar]

void foo(int x){
x++;
}

La función termina y la variable que nos han pasado sigue valiendo 4, porque en realidad hemos modificado la copia de dicha variable que se ha pasado a la función, y que ha sido destruida al terminar.

Seguimos suponiendo que vale 4
Código (cpp) [Seleccionar]

void foo(int &x){
x++;
}

Aquí nuestra variable valdría 5, porque hemos pasado no una copia de ella, sino su referencia. Y por tanto, hemos modificado más allá del alcance de la función.

Para hacer esto en C, tenías que especificar en la función que recibirías un puntero, y bien pasar la dirección de la variable cuando llamases a la función, o bien un puntero a la misma para poder modificarla dentro de la propia función y que dicho cambio existiese fuera.

farresito

Gracias Akai. Me has aclarado las ideas. Me sonaba pero ahora lo tengo claro. Creo que lo que me ha despistado es no verlo así:

void insertar_al_principio (struct t_nodo* &p)

Realmente pensaba que había un puntero genérico; no exactamente, pero si de algún modo, pero veo que estaba equivocado :)

Un abrazo. Agradezco mucho tu ayuda ;)