【问题标题】:Previously stored strings are overwritten by fgets以前存储的字符串被 fgets 覆盖
【发布时间】:2017-06-27 22:14:41
【问题描述】:

我正在使用 fgets() 从 CSV 文件中读取记录,一次读取一行,使用 strtok() 解析每一行中的字段。我遇到了一个问题,其中 fgets() 覆盖了以前编写的字符串,有利于新字符串。
这是我的意思的一个例子:

record.csv(这是我正在阅读的文件)

John,18
Johann,29

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct customer {
    char *name;
    int age;
} Customer;

int main(void) 
{
    FILE *csv_data;
    char line[100], *token;
    Customer newData[2];

    csv_data = fopen("record.csv", "r");
    // Index 0 for John's data, index 1 for Johann's data
    int i = 0;

    /* loops until end of file */
    while(fgets(line, 100, csv_data)) {

        /* name field */
        token = strtok(line, ",");
        if (token != NULL) {
            newData[i].name = token;        
        }

        /* age field */
        token = strtok(NULL, ",");
        if (token != NULL) {
            // atoi() converts ascii char to integer
            newData[i].age = atoi(token);
        }
        i++;
    }
    /* print John's records */
    printf("%s\n", newData[0].name);
    printf("%d\n", newData[0].age);

    /* print Johann's records */
    printf("%s\n", newData[1].name);
    printf("%d\n", newData[1].age);

    return 0;
}


当我们编译并执行它时,它会打印出来:

Johann
18
Johann 
29

newData[0].name 中的“John”在while 循环的第二次迭代中被“Johann”覆盖。但是请注意,只有字符串会混淆,而整数不会。我怀疑这与fgets 有关,因为当我将上述源代码修改为仅运行fgets 一次时,“John”的输出应该是这样。
也许我在滥用fgets(或者我的假设是错误的),但是有人可以给我一些关于为什么每次调用fgets 都会覆盖字符串的指针吗?

第二次更新:再次感谢所有评论者和回答者。很高兴知道我不知道的那些事情。源代码现在完美运行。

【问题讨论】:

  • 你将每一行复制到同一个变量line;您不会复制strtok 找到的数据。这就是覆盖发生的方式。分配空间并复制数据,可能使用strdup()。 C 不会为您管理字符串的内存;你必须自己做。
  • @xing,哦,newData[i].name 的内存必须在堆中手动分配?我没有意识到这一点。谢谢,我试试。 @JonathanLeffler 所以newData[i].name = token 不会复制数据?
  • 您可以通过将这个:newData[i].name = token; 更改为这个:newData[i].name = strdup(token); 来为名称分配内存。
  • 谢谢@bruceg。是的,我实现了strdup,它按预期复制了字符串。

标签: c csv fgets strtok


【解决方案1】:

你复制的不是字符串,而是指向字符串的指针。

复制字符串的一种非常简单的方法,但请注意,这会将字符串的大小限制为 99 个字符。

typedef struct customer {
    char name[100];
    int age;
} Customer;

strcpy(newData[i].name, token);   

【讨论】:

    【解决方案2】:

    做:

    newData[i].name = malloc( strlen( token ) + 1 );
    strcpy( newData[i].name, token );
    

    或将name 成员定义为char name[64];,然后再将strcpy( newData[i].name, token ); 定义为没有malloc。 name 的 64 字节可多可少。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-01
      • 2015-09-25
      • 1970-01-01
      • 2013-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-02
      相关资源
      最近更新 更多