Sí, eso lo entiendo, pero a ver.. recurramos a un poco de teoría básica de punteros.
Supongamos que tenes un entero, este entero lo vas a almacenar en X espacio de memoria, este espacio va a tener su respectiva dirección de memoria.. en fin, lo importante es que una dirección de memoria corresponde a un espacio.
Cuando usas el WHILE, imagino que lo que estás intentando hacer es recorrer varias direcciones de memoria para ir leyendo los diferentes espacios, es decir en donde se encuentran tus "alumnos en este caso".
El tema es el siguiente, vos lo que estás haciendo es cada vez que almacenas un alumno aplicas a el puntero p1 un malloc, asignando un nuevo espacio en memoria para un nuevo alumno, el problema es que al hacer eso perdes la referencia.
alumno *puntero = NULL;
// Actualmente el puntero apunta a null.
agregarAlumno(puntero);
// Se agrega un alumno
// Actualmente puntero apunta a la dirección 1.
agregarAlumno(puntero);
// Se agrega otro alumno
// Actualmente puntero apunta a la dirección 2.
// Ahora no tenes manera de volver a apuntar a la dirección uno.
// De modo que perdiste la referencia a tu alumno anterior.
// Por lo que no es posible "mostrar tu alumno"
Para evitar esto vas a tener que trabajar con algún arreglo.
Podría ser un array de punteros del tipo alumno.
Es decir un array que almacene punteros.
int CANTIDAD_DE_ALUMNOS = 10;
alumno **alumnos[CANTIDAD_DE_ALUMNOS];
// De esta manera tendrías espacio para almacenar diez alumnos.
// Lo único que deberías hacer es almacenar la dirección de memoria en alguno de //los indices
// Por ejemplo.
alumno *puntero = NULL;
agregarAlumno(puntero);
// Puntero apunta a la direccion 1 y tiene un alumno cargado.
alumnos[0] = p1; // Guardamos la dirección del alumno anterior.
// alumnos[0] apunta a la direccion 1
agregarAlumno(puntero);
// Puntero apunta a 2 y tiene un alumno cargado.
alumnos[1] = p1; // Guardamos la dirección del alumno anterior.
// alumnos[0] apunta a la direccion 2