为什么在这个C程序中发生了分段错误?

时间:2017-05-15 14:29:40

标签: c arrays file segmentation-fault

我做了一个简单的C程序来读取.txt文件中的数据并将其打印到屏幕上。

FILE *fp = fopen("words.txt", "r");

char buffer[3];

while (fscanf(fp, "%s", buffer) != EOF)
printf(" %s\n ", buffer);

printf("\n");

word.txt里面写着123。现在,我运行程序时得到的输出是

123
Segmentation fault

为什么会出现分段错误以及它意味着什么?

4 个答案:

答案 0 :(得分:0)

C printf()scanf()fscanf(),实际上大多数字符串功能都适用于 null终止字符串

  

在计算机编程中,以null结尾的字符串是一个字符串,存储为包含字符的数组,并以空字符('\0'结尾,在ASCII中称为NUL)。

因此,当您的输入包含3个字符时,您还必须为空字符保留空间。 在您的示例中,缓冲区应至少为4。

为防止用户错误,您始终可以使用以下方法限制输入的大小:

char buffer[16]; // An array of 16 for example
scanf("%15s", buffer); // Must also reserve space for the null

请注意,由于Segmentation fault函数尝试将fscanf()写入缓冲区的第4个字符,因此<{1}} 。 这只会覆盖堆栈中的一些局部变量。

错误很可能是由于将NULL写入存储指向文件的指针的内存位置(NULL),在下一次迭代时产生FILE *fp,当我们再次尝试从文件中读取时。

为了说明这一点,这就是你的堆栈的样子:

Segmentation fault

| buffer[0] | buffer[1] | buffer[2] | fp | fp | fp | fp | ... 尝试将fscanf()写入缓冲区,因此它从缓冲区的开头开始,并分别将1,2,3放在位置0,1,2中。但"123\0"个字符恰好放在NULL的一部分位置,从而破坏了指针。

答案 1 :(得分:0)

你的字符串缓冲区需要有'\ 0'字符的空格,表示字符串的结尾:字符串“123”实际上是['1','2','3','\ 0'] 。 fscanf会自动添加'\ 0'。

答案 2 :(得分:0)

您的具体问题是 nul-terminateded 字符数组。

换句话说,意味着3个字符串需要存储4个字节char缓冲区:

------------------
| 1 | 2 | 3 | \0 |
------------------

所以

char buffer[3];

必须是

char buffer[4];

BTW这不是一个完全正确的解决方案,因为你必须声明你的数组足够大,以包含可以在文件中检索的最长字符串。

答案 3 :(得分:0)

这是因为NULL字符\0你的字符串长度不是3个字符,但实际上是4个字符长。你的缓冲区太小了

只是一个建议,使用fscanf并不是我认为最好的解决方案

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

int main()
{
  FILE *f = fopen("words.txt", "rb");
  fseek(f, 0, SEEK_END);
  long fsize = ftell(f);
  fseek(f, 0, SEEK_SET);  //same as rewind(f);                                  

  char *string = malloc(fsize + 1);
  fread(string, fsize, 1, f);
  fclose(f);

  string[fsize] = 0;
  printf("%s\n", string);
}

使用fread是一个更好的解决方案