David Choi
David Choi

Reputation: 175

My realloc function is doing realloc only once when working with a dynamic array of structs

I have a function leerArch() that reads a file with information of students and returns a pointer to a dynamic array of structs t_alumno.

But when I did the debugging it seems like everything works fine except for the realloc function. The pointer *arrDin only changes once and then didn't change again.

When I print my dynamic array I get the number of elements and the students id's right but the name and surname is just the last student for every element in my array.

So I suspect my realloc function is not working properly because after debugging many times and reviewing my code I couldn't find any other flaw that could cause this problem.

Here is my struct:

typedef struct alumno{
    int nro_registro;
    char *nombre;
    char *apellido;
}t_alumno;

and here is my function this one reads a file and returns a dynamic array of struct alumno:

t_alumno *leerArch(char *nomArch){
    int r,i,legajo,j;
    char c;
    char *nombre = malloc(1);
    char *apellido = malloc(1);
    t_alumno *arrDin = malloc(sizeof(t_alumno));

    //reading file
    //rach line has: 123456,name,surname
    FILE *arch = fopen(nomArch,"r");
    r = fscanf(arch,"%d,",&legajo);
    for (i=0; r!= EOF; i++){
        //writing name in a string
        c = fgetc(arch);
        for(j=0; c!=',' && c != EOF; j++){
            *(nombre+j) = c;
            nombre = realloc(nombre,j+2);
            c = fgetc(arch);
        }
        c = fgetc(arch);
        *(nombre+j) = '\0';
        //writing surname in a string
        for(j=0;  c != EOF && c!='\n'; j++){
            *(apellido+j) = c;
            apellido = realloc(apellido,j+2);
            c = fgetc(arch);
        }
        *(apellido+j) = '\0';
        //adding element to my array. I suspect this realloc doesn't work properly
        (arrDin+i)->nro_registro = legajo;
        (arrDin+i)->nombre = nombre;
        (arrDin+i)->apellido = apellido;
        arrDin = realloc(arrDin,(i+2)*sizeof(t_alumno));

        r = fscanf(arch,"%d,",&legajo);
    }
    //adding an ending element
    (arrDin+i)->nro_registro = 0;
    (arrDin+i)->nombre = "void";
    (arrDin+i)->apellido = "void";

    fclose(arch);

    return arrDin;
}

my file has:

170022,Juan,Rodriguez
170050,Maria,Perez
170125,Lorena,Ledesma
170245,Tomas,Garcia

And the output when I print this array is:

{170022,Tomas,Garcia}
{170050,Tomas,Garcia}
{170125,Tomas,Garcia}
{170245,Tomas,Garcia}

Printing function:

void imprimirArr(t_alumno *arrDin){
    int i;
    for(i=0; (arrDin+i)->nro_registro != 0; i++){
        printf("\n{%d,%s,%s}",(arrDin+i)->nro_registro,(arrDin+i)->nombre,(arrDin+i)->apellido);
    }
}

Upvotes: 0

Views: 116

Answers (2)

kilio
kilio

Reputation: 26

The problem is that you are constantly using the same pointer for "apellido" and "nombre". Consequently, in both for loops, you are changing chars but the pointer still the same.

You must duplicate your pointer using the strdup function this way

(arrDin+i)->nombre = strdup(nombre);
(arrDin+i)->apellido = strdup(apellido);

However, I don't know if you are currently learning C language, but you can do better than what you've done here using getline and strsep functions, here is a sample code:

void print_alumnos(t_alumno **arrDin)
{
    for (size_t i = 0; arrDin[i] != NULL; i++) {
        printf("{%d, %s, %s}\n", arrDin[i]->nro_registro, arrDin[i]->nombre, arrDin[i]->apellido);
    }
}

char **split_line(char *line)
{
    char **splited_line = NULL;
    char *token = NULL;
    size_t i = 0;

    while ((token = strsep(&line, ",")) != NULL) {
        splited_line = realloc(splited_line, sizeof(char *) * (i + 2));
        splited_line[i] = strdup(token);
        splited_line[++i] = NULL;
    }
    return splited_line;
}

FILE *open_file(char *filename)
{
    FILE *filestream = NULL;

    if (!filename) {
        return NULL;
    }
    filestream = fopen(filename, "r");
    if (filestream == NULL) {
        return NULL;
    }
    return filestream;
}

struct alumno **read_file(char *filename)
{
    FILE *filestream = open_file(filename);
    char *line = NULL;
    char *tmp_ptr = NULL;
    char **splited_line = NULL;
    size_t i = 0;
    size_t nread = 0;
    struct alumno **alumnos = NULL;

    if (filestream == NULL)
        return NULL;
    while (getline(&line, &nread, filestream) > 0) { // getting line by line
        tmp_ptr = line;
        if (line[strlen(line) - 1] == '\n') {
            line[strlen(line) - 1] = '\0'; // delete \n because getline is keeping it
        }
        splited_line = split_line(line);
        alumnos = realloc(alumnos, sizeof(struct alumno *) * (i + 2));
        alumnos[i] = malloc(sizeof(struct alumno));
        alumnos[i]->nro_registro = atoi(splited_line[0]);
        alumnos[i]->apellido = splited_line[1];
        alumnos[i]->nombre = splited_line[2];
        alumnos[++i] = NULL;
        free(tmp_ptr);
        line = NULL;
        nread = 0;
    }
    fclose(filestream);
    return alumnos;
}

int main(void)
{
    struct alumno **alumnos = read_file("test.txt");

    print_alumnos(alumnos);
    return 0;
}

Upvotes: 1

David Choi
David Choi

Reputation: 175

I just found my mistake. So basically the char* pointer that I was putting into my array was being replaced over and over because we are working with pointers here, so I added a new malloc before writing the strings again so we get new char pointers and that got fixed.

t_alumno *leerArch(char *nomArch){
    int r,i,legajo,j;
    char c;
    char *nombre;
    char *apellido;
    t_alumno *arrDin = malloc(sizeof(t_alumno));

    //reading file
    //rach line has: 123456,name,surname
    FILE *arch = fopen(nomArch,"r");
    r = fscanf(arch,"%d,",&legajo);
    for (i=0; r!= EOF; i++){
        //writing name in a string
        c = fgetc(arch);
        nombre = malloc(1);
        for(j=0; c!=',' && c != EOF; j++){
            *(nombre+j) = c;
            nombre = realloc(nombre,j+2);
            c = fgetc(arch);
        }
        c = fgetc(arch);
        *(nombre+j) = '\0';
        //writing surname in a string
        apellido = malloc(1);
        for(j=0;  c != EOF && c!='\n'; j++){
            *(apellido+j) = c;
            apellido = realloc(apellido,j+2);
            c = fgetc(arch);
        }
        *(apellido+j) = '\0';
        //adding element to my array. I suspect this realloc doesn't work properly
        (arrDin+i)->nro_registro = legajo;
        (arrDin+i)->nombre = nombre;
        (arrDin+i)->apellido = apellido;
        arrDin = realloc(arrDin,(i+2)*sizeof(t_alumno));

        r = fscanf(arch,"%d,",&legajo);
    }
    //adding an ending element
    (arrDin+i)->nro_registro = 0;
    (arrDin+i)->nombre = "void";
    (arrDin+i)->apellido = "void";

    fclose(arch);

    return arrDin;
}

Upvotes: 0

Related Questions