Se tiene un struct con los siguientes campos:

 #define L 25
 #define M 10
 struct alumno {
    char apellido[L];
    char nombre[L];
    int edad;
 
    int notas[M];
    float promedio;
 };
 typedef struct alumno alumno_t;

1) Se pide realizar un programa que permita cargar los campos apellido, nombre y edad de un array de estructuras definido estáticamente en el main como:

 #define CANT 4
 int main (void) {
    alumno_t alumnos[CANT];
    ...
    

2) Convertir el código anterior a una función que realice el trabajo de pedir los datos al usuario y guardar los mismos en el array alumnos definido en el main. La función devuelve cero si no hubo errores, y debe tener el siguiente prototipo:

 int IngresarDatosAlumnos (alumnos_t*pAlumnos, int cant);
 

3) Realizar una función llamada ImprimirDatosAlumnos que me permita imprimir en pantalla los campos nombre, apellido y edad, de un array de structs del tipo alumnos_t.

4) Realizar una copia del programa y la función del punto 2) pero ahora usando memoria dinámica, es decir, al iniciar la carga de datos, se debe consultar primero al usuario cuántos alumnos va a ingresar y reservar la memoria exacta para ello. Realizar todas las modificaciones necesarias teniendo en cuenta:

- hace falta reservar en el main la memoria del array completo como en el punto 1?

- que debe declararse en el main? un array de struct o un puntero a struct?

La nueva función debe tener el siguiente prototipo:

 
 int IngresarDatosAlumnosMemDin(alumnos_t**pAlumnos);
 

Recibe por el puntero pAlumnos un puntero apuntando a nada, y se debe utilizar para apuntar el nuevo espacio de memoria reservado dentro de la función. Se debe retornar el largo del array creado, o si hubo algún problema con la reserva de memoria, devuelvo cero y el puntero pAlumnos apuntando a NULL.