【问题标题】:memory allocate string for fgets with null terminating char为具有空终止字符的 fget 分配内存字符串
【发布时间】:2014-08-17 20:52:25
【问题描述】:

如果这个问题看起来“简单”,但我无法在任何地方找到答案,我真的很抱歉。 我尝试使用 fgets() 从文件中读取一行。 为了确保不浪费空间,首先我找到了行的长度:

do
    {
        c= getc(file);
        words++;
    }while (c!=EOF && c!='\n');

然后我为确切的字数分配内存:

char* line = (char*)malloc(sizeof(char)*(words));

然后,我使用 fgets() 将行读取到行缓冲区。 但问题是,这是有效的。 但我一直认为你也应该为空终止字符分配内存。 那么这里发生了什么?

【问题讨论】:

  • 附带说明:转换malloc() 的返回值是有害的,sizeof(char) 始终为 1。所以最后一行正确的是:char *line = malloc(words + 1);
  • 附加说明,words 作为变量计数字节的名称有点让人分心。
  • 以及您的原因:许多系统分配的数量超过了您的要求。系统只是保证它不会分配小于所需大小,而不是它不会分配更多(严格来说,对于过度使用的系统,实际上没有任何保证)。
  • 是的,没错,我这样做是出于某种原因并没有更改它(我说的是变量名)
  • 请注意,对getc() 的调用读取一行;随后对fgets() 的调用读取下一行——除非有你没有向我们展示的记录和重置输入流上的读取位置的代码(并且并非所有文件类型都是可搜索的——命名的管道和终端,但两个不是)。我建议使用 POSIX getline(),因为它可以根据需要自动分配空间。

标签: c string null fgets


【解决方案1】:

确实需要为空终止符分配空间。这有效的事实并不意味着它总是会(至少在 C 中)。

另外,fgets 还返回 \n 字符。所以你需要两个额外的字符。一种用于\n,另一种用于\0

我会推荐这种方法:

char buffer [1024];
if ( fgets (buffer, 1024, f) != NULL ) {
   // so something with buffer
}

【讨论】:

  • 我不需要额外的两个,你可以看到我已经数过了\n
  • 但我仍然对它为什么起作用感兴趣。而且我不想用这种方法浪费空间。
  • 如果你担心空间,你可以比 1024 小得多。但除非你在一个非常有限的环境中工作,否则空间/时间的权衡可能应该在这里进行。
  • @user3050072 它不起作用。它假装在工作。这是未定义的行为。 “未定义”表示“未定义”而不是“定义为崩溃”。另外,为什么对太空如此认真? 1024 字节不会受到伤害...您是否测量过这个特定的空间量会导致性能瓶颈?如果没有,请不要担心。
  • fgets (buffer, 1024, f) 可以,但建议fgets (buffer, sizeof buffer, f) 更好。为正确的方法 +1。
【解决方案2】:

它的工作纯属运气。在分配的内存结束后写入是未定义的行为。这不是瞬间崩溃。它可能会立即崩溃,或者稍后会崩溃,或者它可能工作得很好。这完全取决于覆盖的大小以及紧随其后的内存的用途。它经常是填充或当前未使用的空间,因此可以正常工作。你不能指望这一点。正确的答案是 malloc 比需要多 2 个字符(1 个用于终止符,1 个用于 fgets 将复制的 \n)。

【讨论】:

  • 对于 malloc 的内存,它要么是填充,要么是下一个 malloc 块的开始,导致以后 malloc 崩溃。 malloc 的一些调试版本(例如 Visual Studio 中用于调试构建的版本)在分配的内存之前和之后放置可识别的保护字节,并检查它们是否已被覆盖,以便提供更多信息的诊断。
猜你喜欢
  • 2010-12-07
  • 2011-06-04
  • 2021-11-28
  • 2011-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-27
相关资源
最近更新 更多