【问题标题】:My realloc function is doing realloc only once when working with a dynamic array of structs在使用动态结构数组时,我的 realloc 函数只执行一次 realloc
【发布时间】:2020-11-20 14:23:09
【问题描述】:

我有一个函数leerArch(),它读取包含学生信息的文件并返回指向structs t_alumno动态数组的指针。

但是当我进行调试时,除了 realloc 函数之外,似乎一切正常。指针*arrDin 只改变了一次就没有再改变。

当我打印我的动态数组时,我得到了元素的数量和学生 ID,但名字和姓氏只是我数组中每个元素的最后一个学生。

所以我怀疑我的 realloc 函数不能正常工作,因为经过多次调试并查看我的代码后,我找不到任何其他可能导致此问题的缺陷。

这是我的结构:

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

这是我的函数,它读取文件并返回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;
}

我的文件有:

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

当我打印这个数组时的输出是:

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

打印功能:

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

【问题讨论】:

  • 您不是将字符串 data 复制到您的结构中,而是复制字符串 pointer 。您应该使用strdup 函数将字符串分配给您的结构成员,如this question 的答案中所述。
  • 这能回答你的问题吗? char* value changing after use of fgets
  • 谢谢你们。我从未与 strdup 合作过,所以我要确定一下。我自己意识到字符串指针中的值一直在变化和替换。

标签: arrays c file dynamic realloc


【解决方案1】:

问题是您一直在为“apellido”和“nombre”使用相同的指针。 因此,在两个 for 循环中,您都在更改字符,但指针仍然相同。

您必须以这种方式使用 strdup 函数复制指针

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

不过,我不知道您目前是否正在学习 C 语言,但您可以使用 getline 和 strsep 函数做得比您在此处所做的更好,这里有一个示例代码:

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

【讨论】:

  • 是的,我正在大学学习 C,所以我对函数的了解非常有限。我也不确定我是否可以使用他们在考试中没有教给我的功能。你的示例代码看起来很性感
【解决方案2】:

我刚刚发现我的错误。所以基本上我放入数组的char*指针被一遍又一遍地替换,因为我们在这里使用指针,所以我在再次写入字符串之前添加了一个新的malloc,所以我们得到了新的char指针固定。

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

【讨论】:

  • 很高兴您解决了问题。用NULL 替换你的malloc(1) 调用更简单[也更惯用],因为realloc 可以处理得很好。
  • 感谢您的提示!下次我会这样做!
  • for (i=0; r!= EOF; i++){ 虽然你使用正确,但它等价于Why is while ( !feof (file) ) always wrong?。将其替换为 while ((r = fscanf(arch,"%d,",&legajo) == 1) { ... 并删除循环末尾的 r = fscanf(arch,"%d,",&legajo);
  • 明白了。这听起来更有效率,我喜欢它
猜你喜欢
  • 2020-03-07
  • 2015-02-13
  • 2017-06-08
  • 2019-05-23
  • 1970-01-01
  • 1970-01-01
  • 2014-07-21
  • 2013-10-27
  • 2016-03-19
相关资源
最近更新 更多