Search code examples
cpointersstructdynamic-memory-allocationrealloc

Realloc messing with my array of structs


I am doing a school project where I can manage a Zoo information. A Zoo has Areas, where they are saved in an array of structures. That Areas have a maximum of 3 neighbour Areas. When the program is initialized, it must read a file with some information of the Areas already. And it works pretty well. I got in the structure the char areas3[10] so I can save the neighbour areas names, and then search in the array of structures with the Areas and save the neighbour areas in an array of pointers to the struct (Area *adj3). It works fine until the total hits 6 Areas. I found the source of the problem. The realloc is messing with the values. But I don't really now why and how to fix it. Can someone help me? Thanks.

struct.h

typedef struct area Area;
struct area{
    char id[10];
    int peso, nadj;

    char areas[3][10];
    Area *adj[3]; ///ponteiros para areas adjacentes
}; 

main.c

int menu()
{
    int op;

    printf("\n\n1 - Mostrar Areas");
    printf("\n2 - Nova Area");
    printf("\n3 - Eliminar Area");
    printf("\n4 - Terminar");
    do{
        printf("\nOpcao: ");
        fflush(stdin);
        scanf(" %d", &op);
        putchar('\n');
    }while(op<1 || op>4);
    return op;
}

int main(int argc, char** argv) {

    int i, total;
    FILE *f;    ///FICHEIRO COM ÁREAS
    Area *areas = NULL; ///IMPORTANTE ESTAR A NULL PARA FUNCIONAR

    areas = le_fich("zoo.txt", &total);

    do{
        i = menu();
        switch(i){
            case 1: mostrar_areas(areas, total); break;
            case 2: areas = nova_area(areas, &total); break;
            case 3: printf("Funcao por introduzir."); break;
            case 4: printf("Funcao por introduzir."); break;
        }        
    }while(i != 4);

    free(areas);

    return (EXIT_SUCCESS);
}

funcoes.c

Area *nova_area(Area *p, int *total){
    int i, igual;
    Area *novo;
    char nome_area[TAM], nome_areadj[TAM];


    printf("********BEFORE p[1].adj[0]: %s\n", p[1].adj[0]->id);

    novo = realloc(p, ((*total)+1) * sizeof(Area));
    if(novo == NULL){
        printf("Erro na alocacao de memoria.\n");
        return p;
    }

    printf("******** AFTERp[1].adj[0]: %s\n", p[1].adj[0]->id);

    p = novo;   //CASO p TENHA MUDADO DE SITIO DEVIDO AO REALLOC
    *total = *total +1;

    do{
        printf("ID: ");
        scanf(" %10[^\n]", nome_area);

        igual = procura_area(p, nome_area, *total);
    }while(igual);

    strcpy(p[*total-1].id, nome_area);
    printf("Peso: ");
    scanf(" %d", &(p[*total-1].peso));
    do{
        printf("Nadj: ");
        scanf(" %d", &(p[*total-1].nadj));

        if(p[*total-1].nadj >= 4)
            printf("\tNumero de areas adjacentes excedidas.\n");
    }while(p[*total-1].nadj >= 4);

    for(i = 0; i < p[*total-1].nadj; i++){
        do{
                printf("Nome da area adjacente: ");
                scanf(" %10[^\n]", nome_areadj);
        }while(strcmp(nome_area, nome_areadj) == 0);

        p[*total-1].adj[i] = procura_areaAdj(p, nome_areadj, *total);
        //SE A AREA INSERIDA NAO FOR RECONHECIDA (NULL), O NUMERO DE ADJACENCIAS
        //É DIMINUÍDO
        if(p[*total-1].adj[i] == NULL){
//                p[*total-1].nadj -= p[*total-1].nadj; //AQUIIIIIIIIIIIIIIIIII DA ULTIMA VEZ

            p[*total-1].nadj--;
        }
        else if(p[*total-1].adj[i]->nadj < 3 && p[*total-1].adj[i] != NULL){
            atualiza_areas(p, nome_areadj, *total);
        }
        else{
            p[*total-1].nadj = 0;
            p[*total-1].adj[i] = NULL;
            printf("Numero maximo de areas adjacentes alcancado.\n");
        }
    }
//    printf("********DEPOISp[1].adj[0]: %s\n", p[1].adj[0]->id);
    return p;
}

Solution

  • Already solve it. When I realloc the pointer to the Array of structures, I lose the location of the pointers inside of it. My solution was: when searching for the neighbour area, instead of returning a pointer of it, I send its index and manage the areas easily. So now there's no away of losing any pointer location.

    struct.h

    ///STRUCT PARA AS AREAS. INCLUI LISTA LIGADA typedef struct area Area; struct area{
        char id[10];
        int peso, nadj;
        
        char areas[3][10];
        int adj[3]; ///array de indices das areas adjacentes };
    

    funcoes.c

    //when searching
    int procura_areaAdj(Area *p, char *nome_areadj, int total){
        for(int i = 0; i < total; i++){        
            if(strcmp(nome_areadj, p[i].id) == 0){    //SE ENCONTROU RETORNA O INDICE 
                return i;
            }
        }
        
        return -1;   //SE NÃO ENCONTROU, RETORNA -1. PARA FUTURAS VALIDAÇÕES
    }
    
    
    //UPDATING ARRAY OF STRUCTURES VALUES
    void atualiza_areas(Area *p, char *nome_areadj, int total){
        int i, j;
    
        if(total == 1)  //NAO EXISTEM ATUALIZACOES NA PRIMEIRA AREA INSERIDA
            ;
        else{
            for(i = 0; i < total; i++){        
                if(strcmp(nome_areadj, p[i].id) == 0){
                    
                    j=0;
                    while(j < p[i].nadj)
                        j++;
    
                    p[i].nadj++;
                    p[i].adj[j] = total-1; //RETURNS LAST AREA INDEX 
                    
                }
            }
        } }