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);
    }
}
David Choi
  • 145
  • 1
  • 10
  • 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](https://stackoverflow.com/q/61414715/10871073). – Adrian Mole Jul 30 '20 at 19:43
  • 1
    Does this answer your question? [char\* value changing after use of fgets](https://stackoverflow.com/questions/61414715/char-value-changing-after-use-of-fgets) – Adrian Mole Jul 30 '20 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. – David Choi Jul 30 '20 at 19:45

2 Answers2

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;
}
kilio
  • 26
  • 3
  • 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 – David Choi Aug 02 '20 at 20:56
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;
}
David Choi
  • 145
  • 1
  • 10
  • 1
    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. – Craig Estey Jul 30 '20 at 20:00
  • Thanks for the tip! I'll do that next time! – David Choi Jul 30 '20 at 20:01
  • 1
    `for (i=0; r!= EOF; i++){` though you use it correctly, is equivalent to [**Why is while ( !feof (file) ) always wrong?**](https://stackoverflow.com/questions/5431941/why-is-while-feoffile-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. – David C. Rankin Jul 30 '20 at 20:14
  • Gotcha. That sounds more efficient I like it – David Choi Aug 02 '20 at 20:56