Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: palacio29 en 31 Mayo 2019, 01:04 am



Título: (Consulta) Problema con un arreglo dinamico
Publicado por: palacio29 en 31 Mayo 2019, 01:04 am
Tengo el siguiente ejercicio que no se que es lo que esta fallando.  :huh:
Tengo una estructura  en la cual tengo:

- Una variable int que carga el legajo de un alumno (un numero cualquiera)
- Un puntero char, en donde se va a guardar el nombre del alumno (Ejemplo Juan)
- Un unsigned char en donde se guarda el codigo de una materia. (Ejemplo CATEGORIA B).

En el main lo que hago es cargar un arreglo estatico de esta estructura.
Lo que tengo que hacer con la funcion filtrar es crear un arreglo dinamico que cree e incluya los valores del arreglo estatico que tengan la categoria B.
No se cual es el error, pensaba que era algo de memoria dinamica que estaba fallando, pero puse una memoria grande e igualmente el programa falla.

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <conio.h>
  4. #define T 3
  5. struct s_alumno
  6. {
  7.    unsigned int leg;
  8.    char*nombre;
  9.    unsigned char cod_car;
  10. };
  11. typedef struct s_alumno t_alumno;
  12. t_alumno* filtrar(t_alumno arr[T],char cod_car);
  13. void IMPRIMIR(t_alumno*);
  14.  
  15. int main()
  16. {
  17.    t_alumno arr[T];
  18.    int i=0;
  19.    char letra;
  20.    t_alumno* listado=NULL;
  21.    arr[0].nombre="Fabian";
  22.    arr[1].nombre="Pablo";
  23.    arr[2].nombre="Manuel";
  24.    while(i<T)
  25.    {
  26.        printf("\nCARGAR NUMERO LEGAJO:\n ");
  27.        scanf("%d",&arr[i].leg);
  28.        printf("CARGAR CODIGO CARRERA\n");
  29.        letra=getche();
  30.        arr[i].cod_car=letra;
  31.        i++;
  32.    }
  33.    printf("\n");
  34.    printf("El nombre cargado es %s - CODIGO DE CARRERA: %c\n",arr[0].nombre,arr[0].cod_car);
  35.    printf("El nombre cargado es %s - CODIGO DE CARRERA: %c\n",arr[1].nombre,arr[1].cod_car);
  36.    printf("El nombre cargado es %s - CODIGO DE CARRERA: %c\n",arr[2].nombre,arr[2].cod_car);
  37.    listado=filtrar(arr,'B');
  38.    IMPRIMIR(listado);
  39.  
  40.    return 0;
  41. }
  42.  
  43.  
  44. t_alumno* filtrar(t_alumno arr[T],char cod_car)
  45. {
  46.    int i=0,j=0,fin=0;
  47.    t_alumno*lista=NULL;
  48.    lista=malloc(sizeof(struct s_alumno));
  49.    while(i<T)
  50.    {
  51.        if((cod_car)==arr[i].cod_car)
  52.        {
  53.            (lista+j)->leg=arr[i].leg;
  54.            strcpy((lista+j)->nombre,arr[i].nombre);
  55.            (lista+j)->cod_car=arr[i].cod_car;
  56.            j++;
  57.           lista=realloc(lista,(j+1)*sizeof(struct s_alumno));
  58.        }
  59.        i++;
  60.    }
  61.    (lista+j)->leg=0;
  62.    printf("\nTERMINO EL FILTRADO\n");
  63.    return lista;
  64.  
  65. }
  66.  
  67. void IMPRIMIR(t_alumno* listado)
  68.  
  69. {
  70. int i=0;
  71. printf ("\nIMPRESION DEL ARREGLO\n");
  72. while(listado[i].leg!=0)
  73. {
  74.     printf("NOMBRE: %s - CODIGO DE CARREA: %c\n",(listado+i)->nombre,(listado+i)->cod_car);
  75.     i++;
  76. }
  77. }
  78.  


Título: Re: (Consulta) Problema con memoria dinamica y arreglo estructuras
Publicado por: K-YreX en 31 Mayo 2019, 02:20 am
Varias cosas... Primero sobre los nombres. Al usar cadenas literales no estás reservando memoria en cada <struct> para guardar los nombres. Lo que estás haciendo es que los punteros del <struct> apunten a la dirección de memoria en la que se encuentran esas cadenas almacenadas desde antes de la ejecución del programa.
Entonces a la hora de crear la nueva lista con el filtro, no puedes copiar los nombres usando <strcpy()> puesto que tampoco estás reservando memoria para estos. Lo único que puedes hacer es hacer que los punteros a <char> de las nuevas <struct> apunten a las mismas cadenas literales.

Ahora sobre el <realloc()>. Si no reservas memoria con <malloc()> (cosa que no deberías hacer) lo único que tienes es un puntero a <t_alumno>. Entonces para "insertar" un nuevo <t_alumno> tendrás que hacer el <realloc()> antes, no después.

Para saber cuántos <t_alumno> hay en el filtro yo usaría otro parámetro por referencia para contabilizarlos y así no tener que poner el último <leg> a 0.
Código
  1. t_alumno* filtrar(t_alumno *arr, char cod_car, size_t *num_filtrados){
  2. t_alumno *filtro = NULL; // tenemos un array vacio
  3. *num_filtrados = 0;
  4.  
  5. for(size_t i = 0; i < SIZE; ++i){
  6. if(arr[i].cod_car == cod_car){ // si son iguales...
  7. (*num_filtrados)++; // ...tenemos un elemento mas en el filtro...
  8. filtro = (t_alumno*) realloc(filtro, *num_filtrados * sizeof(t_alumno)); // ...y reservamos memoria para introducirlo
  9. filtro[*num_filtrados-1].leg = arr[i].leg;
  10. filtro[*num_filtrados-1].nombre = arr[i].nombre; // hacemos que apunte al mismo sitio que arr[i].nombre, no copiamos la cadena porque no hay memoria
  11. filtro[*num_filtrados-1].cod_car = arr[i].cod_car;
  12. }
  13. }
  14. printf("\nTERMINO EL FILTRADO\n");
  15. return filtro;
  16. }