【问题标题】:Char array value will print as empty unless value is printed when assigned - C字符数组值将打印为空,除非在分配时打印值 - C
【发布时间】:2019-02-22 17:44:02
【问题描述】:

我正在使用我的 c 程序中的两个函数,但无法让它们合作。我的第一个函数遍历一个 csv 文件并使用 strtok() 根据“,”分隔符分隔标记。每个标记被保存到一个大小为 3 的字符数组中,如果特定标记与目标标记不匹配,则读取下一行输入并进行标记化,并用新的输入标记覆盖字符数组。

这里是使用的全局变量:

char * stateCityZip[3];

这是第一个函数的代码:

int zipToCity(char * zip)
{
char line[1024];
char * tok = malloc(20 * sizeof(char));
FILE * file = fopen("cityzip.csv", "r");
while (fgets(line, sizeof(line), file))
{
    //State
    tok = strtok(line, ",");
    stateCityZip[0] = tok;
    //City
    tok = strtok(NULL, ",");
    stateCityZip[1] = tok;
    //Zip
    tok = strtok(NULL, ",");
    stateCityZip[2] = tok;

    if (strcmp(stateCityZip[2], newZip) == 0) {
        //printf("Found %s, %s\n", stateCityZip[0], stateCityZip[1]);
        strlen(stateCityZip[1]));
        return 1;
    }
}
return 0;
}

我的第二个函数只是尝试打印 stateCityZip 的值。但是,当我打印这些值时,它们显示为空白。我发现解决此问题的唯一方法是取消注释

//printf("Found %s, %s\n", stateCityZip[0], stateCityZip[1]);

行。

这是我的第二个函数的代码:

int main() {
    printf("City: [%s]", stateCityZip[1]);
    printf("State: [%s]", stateCityZip[0]);

    return 0;
}

输出:

City: []
State: []

【问题讨论】:

  • strtok 返回char*,所以当您执行tok = strtok(line, ","); 时,您正在泄漏使用malloc 分配给tok 的内存,所以不要将内存分配给tok
  • @kiranBiradar 即使将 tok 的定义更改为:“char * tok”,它的行为也是一样的。
  • 请参考 Daniel Pryden 的回答。我的第一条评论只是告诉您可能的内存泄漏,并没有解决您的问题。

标签: c arrays char printf


【解决方案1】:

strtok 返回指向其输入子串的指针。所以你所有的tok 值都是指向line 部分的指针,它具有自动存储持续时间,所以一旦zipToCity 返回,stateCityZip 中的指针都会失效。

(实际上,如果文件中有不止一行,那么只要您前进到下一行,tok 指针就会全部失效,因为它们现在指向缓冲区中新行的任意子字符串。 )

相反,您应该使用strdup 将令牌的副本分配为新字符串,并将从strdup 返回的指针保存到stateCityZip

重要提示:strdup 分配的字符串需要由free 释放。如果stateCityZip 是全局的,那么您可以不释放它们(当您的进程退出时将释放最后一个内存)。但是如果再次调用zipToCity,它将覆盖stateCityZip 中的指针并泄漏相应的字符串。因此,在分配新值之前,首先 free() stateCityZip 中的任何字符串可能是最安全的(如果它们为 NULL,那很好,因为 free(NULL) 是无操作的)。

关于内存分配的主题:您的示例代码有一个 malloc 调用 tok 这是完全多余的,并且保证会泄漏,因为您覆盖了从 malloc 返回的指针而没有 free喜欢它。

关于良好编码实践的主题:fopen 可能会失败。您需要检查返回的 FILE * 是否不为 NULL。 (如果为 NULL,errno 会告诉你原因。)你还需要 fcloseFILE *,你似乎也没有这样做。

更一般地说:这段代码似乎根本没有进行任何错误检查。每次调用 any 标准库函数(或任何函数,就此而言!),您需要考虑该函数如何无法完成它应该做的事情,您将如何能够告诉(通常失败行为有据可查,因此请务必阅读文档),以及如果程序失败,您希望程序做什么。如果文件不存在或无法读取怎么办?如果它包含不是逗号分隔的行,或者不包含预期的字段数?如果在处理文件的过程中内存不足,或者strdup 因为堆内存不足而无法复制字符串,会发生什么情况?如果你不考虑这些问题,或者忘记处理它们,你可能会在一切正常的“幸福情况下”侥幸逃脱,但迟早它会回来咬你——通常是最坏的情况可能的时间。

【讨论】:

  • 您还应该使用tok 指针作为完整答案指出内存泄漏。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-09
  • 2013-11-07
  • 1970-01-01
  • 1970-01-01
  • 2021-07-21
  • 1970-01-01
  • 2013-12-16
相关资源
最近更新 更多