【问题标题】:Segmentation fault in C get lineC获取行中的分段错误
【发布时间】:2016-06-04 17:04:01
【问题描述】:

我需要读取一个文件,为此我使用函数 getline。以下是来自该网站的示例:http://crasseux.com/books/ctutorial/getline.html,为了能够打开文件,我对其进行了调整。

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


int main()
  {
  int bytes_read;
  unsigned long nbytes = 100;
  char *my_string;
  char *filename;
  char *line;
  FILE *fd = NULL;


  puts ("enter filename");

  filename = (char *) malloc (nbytes + 1);

  bytes_read = getline (&filename, &nbytes, stdin);

  fd = fopen(filename, "r");

  bytes_read = getline (&line, &nbytes, fd);

  puts (line);

  puts ("Please enter a line of text.");

  /* These 2 lines are the heart of the program. */
  my_string = (char *) malloc (nbytes + 1);
  bytes_read = getline (&my_string, &nbytes, stdin);

  if (bytes_read == -1)
    {
      puts ("ERROR!");
    }
  else
    {
      puts ("You typed:");
      puts (my_string);
    }

  return 0;
}

当我运行程序时,我得到一个分段错误 11,我不知道我做错了什么。提前谢谢你。

【问题讨论】:

  • 始终检查您是否成功打开了文件。您没有从 get line 返回的字符串中删除换行符,因此您可能没有打开名称末尾带有换行符的文件。
  • 此外,通常使用fd 表示文件描述符(int 类型),fp 表示文件指针(流——FILE * 类型)。

标签: c segmentation-fault getline


【解决方案1】:

您从标准输入读取的filename 对于文件文件参数是错误的。例如,filename get str value from stdin is 'a.txt\n',当输入a.txt

因此,添加一条将 '\n' 修改为 '\0' 的语句将解决问题。即在bytes_read = getline (&amp;filename, &amp;nbytes, stdin); 语句的正下方添加filename[bytes_read - 1] = '\0'; 语句。

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


int main()
  {
  int bytes_read;
  unsigned long nbytes = 100;
  char *my_string;
  char *filename;
  char *line;
  FILE *fd = NULL;


  puts ("enter filename");

  filename = (char *) malloc (nbytes + 1);

  bytes_read = getline (&filename, &nbytes, stdin);

  filename[bytes_read - 1] = '\0';

  fd = fopen(filename, "r");

  bytes_read = getline (&line, &nbytes, fd);

  puts (line);

  puts ("Please enter a line of text.");

  /* These 2 lines are the heart of the program. */
  my_string = (char *) malloc (nbytes + 1);
  bytes_read = getline (&my_string, &nbytes, stdin);

  if (bytes_read == -1)
    {
      puts ("ERROR!");
    }
  else
    {
      puts ("You typed:");
      puts (my_string);
    }

  return 0;
}

【讨论】:

  • 所以“bug”实际上是省略了错误检查。
  • 如果您只按 Ctrl-D 而不是输入名称后按 Enter,此解决方案将失败。
  • 无论如何fgets()ish \n 是我错过的一个很好的收获。 :-)
  • 您想在从 unsigned 中提取之前测试 bytes_read0
  • 感谢 getline 使用的详细说明。此外,此代码绝不应投入生产环境。
【解决方案2】:

要么

  • 使line 指向一些有效内存,nbytes 指向内存大小

  • 或将line 设置为NULL 并将nbytes 设置为0

来自man getline

ssize_t getline(char **lineptr, size_t *n, FILE *stream);

getline() 从流中读取整行,将包含文本的缓冲区的地址存储到 *lineptr 中。缓冲区以 null 结尾,并包含换行符(如果找到)。

如果在调用前 *lineptr 设置为 NULL 并且 *n 设置为 0,那么 getline() 将分配一个缓冲区来存储该行。

另外,getline() 期望 size_t 作为第二个参数,而不是 unsigned long

另外^2 没有必要再分配 1 个字节然后传递给getline。分配n字节并传递n,无需传递n - 1


并且总是在使用它们返回的结果之前向相关的系统调用添加错误检查,例如malloc()fopen()

【讨论】:

  • 嗨@alk,这不是导致段错误的原因,尽管应该检查 getline 调用参数。这个答案太笼统了。
  • 此调用肯定会调用 UB,并且从第二次调用 getline() 开始,任何东西都可以调用,包括分段违规。另外我觉得这根本不是“general”,而是指出了所示代码中的一个非常具体的错误。 @lulyon
  • 即使这是错误的,我认为错误在 get line(&filename, &nbytes, stdin) 因为当我输入文件名时错误是正确的。
  • @alk 具体的错误原因是在 getline 调用之前,文件名错误。
  • @lulyon:filename 怎么了?这不是猜谜游戏。
猜你喜欢
  • 2021-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-14
  • 2011-08-15
  • 1970-01-01
  • 2012-10-10
相关资源
最近更新 更多