【问题标题】:getline() in C creating an infinite loop and skipping first word?C中的getline()创建一个无限循环并跳过第一个单词?
【发布时间】:2020-07-20 00:16:51
【问题描述】:

我是 C 的初学者,我正在尝试创建一个简单的待办事项列表程序。我正在尝试在 while 循环中使用 getline ,正如我在另一个堆栈溢出答案中看到的那样,我以为我理解了它,但它只是创建了一个无限循环。此外,由于某种原因,它似乎跳过了第一个单词。到目前为止,这是我的代码:

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

FILE *list;
int i = 0;
int item = 0;
char items[10];
char chars[1000];
char * line = NULL;
size_t len = 0;
ssize_t read;

int main() {
  list = fopen("/Users/bendavies/Documents/C/list.txt", "r");
  int letterCount = fscanf(list,"%s",chars);

  printf("Welcome to the to-do list. It can hold up to 10 items.\n");

  printf("%d\n", letterCount);

  if (letterCount == -1) {
    printf("The list currently has no items!\n");
  } else {
      while ((read = getline(&line, &len, list)) != 1) {
        item += 1;
        printf("%d. %s", item, line);
      }
    }
    fclose(list);

  return 0;
}

我目前通过以下 list.txt 获得的输出:

Eat food
Drink water
Breath air

是:

1.  food
2. Drink water
3. Breath air
4. 18446744073709551615
5. 18446744073709551615

等等等等。

提前感谢您! :)

【问题讨论】:

  • 考虑将(read = getline(&amp;line, &amp;len, list)) != 1 更改为(read = getline(&amp;line, &amp;len, list)) != -1,我认为fscanf 正在读取第一个单词,而您先生并没有提供完整的输出。
  • 风格指南:创建全局变量作为最后的手段。它们有时是必需的,但代码中的任何一个都不应该是全局的。当它们在函数之外时,将它们设为static,除非有另一个源文件也需要访问它们(也可以使用函数)。当一个变量或函数必须在多个文件中访问时,创建一个头文件来声明它们,并将头文件包含在定义变量和函数的文件以及使用它们的文件中。然后您会注意到itemschars 是未使用的变量。你也必须初始化item
  • 如果您确保没有泄漏,请记住在循环后free(line);。即使第一次调用最终检测到 EOF,getline() 分配内存也是很正常的。

标签: c getline


【解决方案1】:

但这只是在创建一个无限循环。

这行代码:while ((read = getline(&amp;line, &amp;len, list)) != 1)

除非一行包含1 字符(只是一个换行符),否则它将是一个无限循环。当文件被完全读取时,POSIX getline() 函数将返回 -1(不是 EOF,即使 EOF 通常为 -1)。所以将该行更改为:

while ((read = getline(&line, &len, list)) != -1)

但是,我没有看到您在该循环中使用 read 的值,所以这样会更好:

  • 修复 1: while (getline(&amp;line, &amp;len, list) != -1)

在那个循环中,我看到:printf("%d. %s", item, line);

您可能会发现不包含换行符的 getline() 的非常旧的实现,在这种情况下,如果您希望在单独的行中输出,则需要放置 \n

  • 修复 2: printf("%d. %s\n", item, line);

但是,如果您使用更现代的实现,它将根据 POSIX 规范保留换行符。

此外,如果文件中的最后一个“行”没有以换行符终止,您可能仍想添加一个。在这种情况下,您可以保留读取长度并使用它来检测行尾是否有换行符。

由于某种原因,它似乎跳过了第一个单词

因为int letterCount = fscanf(list,"%s",chars);

fscanf 读取文件的第一个单词。现在文件指针位于该位置(第一个单词的结尾),将从该位置进一步读取文件。

因此,在从文件中读取第一个单词后,将文件指针重新定位到文件的开头:

  • 修复 3:

    int letterCount = fscanf(list,"%s",chars);
    fseek(list, 0, SEEK_SET); // <-- this will reposition the file pointer as required
    

【讨论】:

  • 请注意,当 POSIX getline() 到达输入末尾时,它返回 -1,而不是 EOF。我不知道为什么——这很愚蠢。但就是这样。
  • EOF 将是负数——实际上,它总是 -1,但理论上,有人可以创建一个符合(POSIX 和 C)的系统,其中 EOF-256——和getline() 仍会返回 -1,而不是 EOF
  • 请注意,您的“修复 2”将给出双倍行距输出,因为 getline() 在每个输入行的末尾都包含换行符。返回值可用于检查那里是否有换行符;最后一行输入可能不会以换行符结尾。此外,代码应该(但不)在因打开文件失败而崩溃之前检查文件是否已成功打开。
  • 我也修复了这个问题 - 如果您修复的不是您自己的材料,则需要更长的时间。
  • YW — 但对于标记为 c 的问题的回答并不少见。我做了很多“互动”。 :D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-12
相关资源
最近更新 更多