0

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);
    }
}
3
  • 1
    You are not copying string data to your structures but a string pointer . You should use the strdup function to assign the strings to your structure members, as discussed in the answer to this question. Commented Jul 30, 2020 at 19:43
  • 1
    Does this answer your question? char* value changing after use of fgets Commented Jul 30, 2020 at 19:44
  • Thank you guys. I never worked with strdup so I'm going to check that out for sure. I realised by my own that the values in the string pointers were changing and replacing all the time. Commented Jul 30, 2020 at 19:45

2 Answers 2

1

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;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Yes I am learning C in college so my knowledge of functions is pretty limited. Also I am not sure if I can use functions that they didn't teach me in the exams. Your sample code looks very sexy
0

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;
}

4 Comments

Glad you solved your problem. It's simpler [and more idiomatic] to replace your malloc(1) calls with NULL as realloc will handle that just fine.
Thanks for the tip! I'll do that next time!
for (i=0; r!= EOF; i++){ though you use it correctly, is equivalent to Why is while ( !feof (file) ) always wrong?. Replace it with while ((r = fscanf(arch,"%d,",&legajo) == 1) { ... and remove the r = fscanf(arch,"%d,",&legajo); at the end of the loop.
Gotcha. That sounds more efficient I like it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.