Gracias por su respuesta pero creo que no me hice entender muy bien
Asi que voy a ser mas directo
En esta linea de codigo se muestra el valor al que apunta el puntero
//codigo1
cout<<"edad: "<<(punteroemp+pos)->edad<<endl;
//Codigo2
Mientras en esta otra tengo que poner los astericos por que de lo contrario solo me va a mostrar la direccion de memoria y no el valor
//codigo2
cout<<*(*(matriz+i)+j)<<" ";
Porque en el primer caso no es necesario poner los astericos mientras en el segundo si hay que ponerlo?
Esto es porque en el primer caso no estás mostrando el contenido de un puntero sino de una variable "normal" (edad) aunque estés accediendo a esa variable por medio de un puntero.
Si ves en tu código original, (línea 8) 'edad' es una variable de tipo int.
Supongamos que en lugar de tu código original, tienes el siguiente:
struct Empleado {
int* edad;
};
int main() {
Empleado *puntero_empleado = new Empleado; // Reservamos memoria para el puntero a 'Empleado' -> No relevante ahora mismo
// 'puntero_empleado->edad' es equivalente a: '(*puntero_empleado).edad'
// La primera sintaxis es mas elegante y mas facil de leer pero significa exactamente lo mismo
puntero_empleado->edad = new int; // Reservamos memoria para poder guardar un int (ahora es necesario porque edad es un puntero) -> No relevante ahora mismo
puntero_empleado->edad = 5; // ERROR!! Estas asignando un int (5) a un puntero
*(puntero_empleado->edad) = 5; // CORRECTO!!
*(*(puntero_empleado).edad) = 5; // Esto tambien es correcto pero se lee peor
cout << puntero_empleado->edad << endl; // Esto te mostrara la direccion de memoria del puntero 'edad'
cout << *(puntero_empleado->edad) << endl; // Esto te mostrara el contenido de la direccion de memoria del puntero 'edad': 5
// Si reservamos memoria dinamica mediante 'new', al dejar de usarla hay que liberarla con 'delete' -> No relevante ahora mismo
delete(puntero_empleado->edad);
delete(puntero_empleado);
}
Como ves, si la variable 'edad' que es la que tú realmente estás usando fuera un puntero, también tendrías que usar el asterisco
En cambio, en el segundo caso que muestras, estás accediendo a una variable que es un puntero (más concretamente una matriz = puntero a punteros) y por eso tienes que usar el asterisco.
Entendiendo bien los operadores (* y &) puedes concatenar tantos punteros/no punteros como quieras. Claro que si concatenas demasiado perderás el hilo de a qué estás accediendo:
- Operador * -> Sólo se puede usar con punteros: Devuelve el contenido que está almacenado en la dirección de memoria a la que apunta el puntero.
- Operador & -> Se puede usar con cualquier tipo de variable: Devuelve la dirección de memoria de esa variable.
int var = 5; // Variable "normal"
// NOTA: Cuando se asigna un valor (direccion de memoria) a un puntero al mismo tiempo que se declara estamos ante una situacion especial
// Aunque estemos usando el asterisco realmente no estamos accediendo al contenido al que apunta, en este momento el asterisco solo significa que hemos declarado un puntero
int *p_var = &var; // Puntero a int
// La linea anterior es equivalente a:
// int *p_var;
// p_var = &var;
cout << var << endl; // Muestra el contenido de var: 5
cout << &var << endl; // Muestra la direccion de memoria donde se esta guardando 'var'. Imaginemos que es: 0x1 (realmente sera un numero mas largo)
// Ahora estamos accediendo al contenido del puntero p_var -> ¿Que guarda un puntero? Una direccion de memoria, en este caso la de 'var'
cout << p_var << endl; // Muestra: 0x1
cout << *p_var << endl; // Muestra el contenido guardado en la direccion de memoria guardada en 'p_var' -> p_var = 0x1 -> Contenido en 0x1: 5
cout << &p_var << endl; // Muestra la direccion de memoria donde se esta almacenando el puntero 'p_var'. Supongamos 0x5 (realmente sera otro numero largo)
// Ahora complicamos mas la situacion:
int **pp_var; // Doble puntero -> Significa que tiene que guardar una direccion de memoria pero no una cualquiera. Tiene que guardar la direccion de memoria de un puntero
pp_var = &p_var; // Aqui tenemos la direccion de memoria de un puntero (0x5), nos sirve.
// Y ahora llega lo divertido. Te reto a entender que se esta mostrando en cada momento y si lo consigues, ya tendras los punteros mucho mas dominados de lo que pensabas:
cout << pp_var << endl;
cout << &pp_var << endl;
cout << *pp_var << endl;
cout << **pp_var << endl;
Puedes hacer un programa con el código anterior y ejecutarlo para verlo con valores de verdad.
Verás que aunque las direcciones de memoria son más largas, se cumple que el valor real de lo que yo he llamado 0x1 en la línea 11 es el mismo que en la línea 14. Y así con 0x5 también.
PD: Soluciones:
cout << pp_var << endl; // Muestras lo que esta guardando el puntero doble 'pp_var' -> Guarda la direccion de memoria de 'p_var' -> 0x5
cout << &pp_var << endl; // Muestra la direccion de memoria propia de 'pp_var' -> Sera otra diferente: 0x15 por ejemplo
cout << *pp_var << endl; // Muestra el contenido de 'p_var' -> 'p_var' contiene la direccion de memoria de 'var' -> 0x1
cout << **pp_var << endl; // Muestra el contenido del contenido de 'p_var' -> 'p_var' contiene la direccion de memoria de 'var' (0x1) -> Esta direccion contiene el valor de 'var' -> 5