No sabia que que cuando pasabas un vector a una función lo podías pasar como puntero con "*", hasta lo que he visto cuando se pasaba algo por referencia a una función se hacia con &
Cuando se pasa algo por referencia se pasa con &, eso es cierto. Pero un puntero no siempre se pasa por referencia.
void funcion1(int a); // variable por valor
void funcion2(int &a); // variable por referencia
void funcion3(int *pa); // puntero por valor
void funcion4(int *&pa); // puntero por referencia
Diría que esos son los tipos de parámetros que podemos usar más típicos. Luego claro está que podemos hacer conversiones de uno a otro. Por ejemplo es lo mismo pasar una variable por referencia que pasar un puntero a esa variable por valor. Todo depende de lo que nos guste más o lo que más nos convenga en cada momento: si estás trabajando todo el tiempo con variables y necesitas mandar una a una función y modificarla pero no puedes retornarla porque ya tienes un <return> (o cualquier otro motivo) pues la pasas por referencia (así ahorras crear un puntero y hacer que apunte a esa variable). En cambio si por un casual estás trabajando con punteros y quieres pasar el valor del puntero (es decir la variable a la que apunta) y modificarla pues para qué vas a crear otra variable y asignarle el valor del puntero para pasarla por referencia? En este caso te ahorras trabajo pasando el puntero directamente.
Como te he comentado antes el paso de un puntero por referencia es muy aislado. Hasta donde yo he visto y además si estás empezando sólo lo necesitarás para pasar un puntero a una función y dentro de la función reservar memoria con <new> o bien pasar un array (es decir, un puntero al que ya le has hecho <new>) y liberar esa memoria con <delete>. Quitando esos casos, no creo que necesites pasar un puntero por referencia. Por lo que puedes olvidarte un poco de él hasta que veas memoria dinámica.
y si querías pasar un puntero tenias que crearlo del mismo tipo que el vector, luego vincularlo al primer espacio de la memoria y luego ya se pasaba con "*".
Esto no es necesario pero en algunas ocasiones se hace. Cuando tú creas un vector, el propio vector funciona como un puntero que apunta a la primera posición del vector.
int numeros[5] = {1,2,3,4,5};
// aqui podemos usar <numeros> como si fuera un puntero que apunta a &numeros[0]
// por lo tanto podemos hacer cosas como:
cout << *numeros << endl; // imprime: 1
for(size_t i = 0; i < 5; ++i)
cout << *(numeros+i) << " " << endl; // imprime: 1 2 3 4 5
¿Y para qué sirve crear otro puntero? Bueno, imagina que tienes una función para recorrer todo un vector. Esta la podemos hacer de varias formas, por ejemplo:
void recorrerVector1(int *numeros, int longitud){
for(int i = 0; i < longitud; ++i)
cout << *(numeros+i) << endl;
}
void recorrerVector2(int *numeros, int longitud){
for(int i = 0; i < longitud; ++i){
cout << *numeros << endl;
++numeros;
}
}
Con ambas vas a obtener el mismo resultado pero tienen una diferencia. La primera le va diciendo a <numeros> "imprime el valor que está i posiciones por delante de ti" mientras que la segunda le dice a <numeros> "imprime el valor que hay en tu posición 0 y muévete". La primera no tiene ningún inconveniente, sin embargo, la segunda sí. Si a la segunda función le pasamos el nombre del vector para que haga de puntero y avanzamos el puntero, los valores que vaya dejando atrás los perderemos para siempre. Un vector se puede encontrar en memoria siempre que tengamos un puntero apuntando a él (al comienzo de él), si perdemos el puntero, perdemos el vector. Para ello se crea otro puntero nuevo que sea el que se vaya moviendo mientras el original siempre apunta al comienzo.
int numeros[5] = {1,2,3,4,5};
int *puntero = numeros;
recorrerVector2(puntero, 5); // aqui no hay problemas porque aunque <puntero> se mueva, <numeros> siempre apunta al comienzo del vector
//en cambio si hacemos esto...
recorrerVector2(numeros, 5); // ... adios al vector. Ya no hay forma de volver a usarlo ni de liberarlo si fuera memoria dinamica
PD: Entonces lo que paso con: (char* nombre)
es la posición de memoria de la posición v[0] del vector?
o
es un puntero del vector que se llama nombre y esta en la posición v[0] del vector con su mismo nombre?.
Lo que pasas es lo primero que dices, la posición de memoria de la posición 0 del vector.
En el caso de (char& letra) que es un paso por referencia pasas la dirección de memoria también no? ya que puedes modificar la variable en otra funciones.
Exacto. Cuando pasas una variable por referencia siempre pasas la dirección de memoria en la que está almacenada esa variable.
Y por qué no se usa (char& letra) como por ejemplo sí pasar un solo char como 'a'.
Respecto a esto voy a extenderme un poco más para intentar explicarlo del todo...
Este ha sido tu planteamiento de antes:
int pedirNombre(char& us){
int longitud;
cout<<"Digite su nombre: ";
cin.getline(us,30,'\n');
longitud = strlen(us);
return longitud;
}
¿Se puede hacer? ¿No se puede hacer? La respuesta es que sí, se puede hacer pero como todo, hay que hacerlo bien. Pasamos primero a un ejemplo más simple:
void funcion1(int a){
cout << "La variable vale: " << a << " y su direccion de memoria es: " << &a << endl;
// Se muestra la direccion de memoria de la copia
// IMPORTANTE: el valor se obtiene con el nombre tal cual y la direccion con &
}
void funcion2(int &a){
cout << "La variable vale: " << a << " y su direccion de memoria es: " << &a << endl;
// Se muestra la direccion de memoria de la original
// IMPORTANTE: el valor se obtiene con el nombre tal cual y la direccion con &
}
void funcion3(int *pa){
cout << "La variable vale: " << *pa << " y su direccion de memoria es: " << pa << endl;
// Se muestra la direccion de memoria de la original pero no de <pa> sino a la que apunta <pa>
// IMPORTANTE: el valor se obtiene con * y la direccion con el nombre tal cual
}
// USO DE LAS FUNCIONES
int numero = 2;
funcion1(numero); // se pasa un <int>
funcion2(numero); // se pasa un <int> aunque el programa ya sabe que es por referencia
funcion3(numero); // ERROR: El programa espera una direccion de memoria (puntero) y le estamos pasando un <int>
funcion3(&numero); // Correcto: Le pasamos una direccion de memoria sin crear un puntero auxiliar (que tambien se podria hacer)
Lo que quiero que veas con esto es que tanto en el paso por valor como por referencia lo que pasamos es el nombre de la variable y eso que en el primer caso estamos copiando el valor y en el segundo caso estamos usando su dirección de memoria pero nosotros siempre pasamos siempre el nombre de la variable tal cual y dentro de las funciones usamos también el nombre de la variable tal cual para mostrarla. En cambio, en la tercera función no pasamos el nombre de la variable tal cual sino que pasamos su dirección de memoria y dentro de la función no usamos el nombre tal cual para mostrarla <pa> sino que usamos el operador de desreferencia (el asterisco).
Entonces volviendo a tu función. La forma más simple es esta:
int pedirNombre(char *nombre){
cout << "Introduce nombre: ";
cin.getline(nombre, 30, '\n');
return strlen(nombre);
}
// USO DE LA FUNCION
int longitud = pedirNombre(nombre); // Como hemos visto antes tiene que recibir directamente la direccion de memoria, bien asi o bien asi:
int longitud = pedirNombre(&nombre[0]); // que es exactamente lo mismo
¿Se puede hacer usando el paso por referencia? Claro que se puede pero necesitamos hacer algunos cambios:
int pedirNombre(char &nombre){
cout << "Introduce tu nombre: ";
cin.getline(&nombre, 30, '\n');
return strlen(&nombre);
}
// o bien:
int pedirNombre(char &nombre){
char *puntero = &nombre;
cout << "Introduce nombre: ";
cin.getline(puntero, 30, '\n');
return strlen(puntero);
}
// USO DE LA FUNCION
int longitud = pedirNombre(nombre[0]); // como hemos visto antes se pasa la variable y ya el programa sabe que tiene que usar su direccion de memoria
Lo importante es saber cuando se usa la dirección de memoria y cuando no pero también hay que saber cuando es necesario que lo indiquemos nosotros y cuando no. ¿Cuál usar? Pues cada uno la que más le guste pero lo ideal sería usar la más legible en cada momento y para vectores siempre va a ser más legible el paso de punteros que el de referencias.