为什么我会出现分段错误?

时间:2010-10-09 15:07:01

标签: c arrays pointers segmentation-fault

我正在尝试编写一个程序,它接收一个明文文件作为它的参数并解析它,将所有数字加在一起然后打印出总和。以下是我的代码:

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

static int sumNumbers(char filename[])
{
    int sum = 0;
    FILE *file = fopen(filename, "r");
    char *str;

    while (fgets(str, sizeof BUFSIZ, file))
    {
        while (*str != '\0')
        {
            if (isdigit(*str))
            {
                sum += atoi(str);
                str++;
                while (isdigit(*str))
                    str++;
                continue;
            }
            str++;
        }
    }

    fclose(file);

    return sum;
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        fprintf(stderr, "Please enter the filename as the argument.\n");
        exit(EXIT_FAILURE);
    }
    else
    {
        printf("The sum of all the numbers in the file is : %d\n", sumNumbers(argv[1]));
        exit(EXIT_SUCCESS);
    }

    return 0;
}

我正在使用的文本文件是:

  

这是一个相当无聊的文本文件   一些随机数分散   贯穿始终。

     

这是一个:87,这是另一个:3

     

最后两个数字:12   1938年。完成。呼。

当我编译并尝试运行它时,我遇到了分段错误。

8 个答案:

答案 0 :(得分:14)

你没有为缓冲区分配空间。
指针str只是一个悬空指针。因此,您的程序有效地将从文件读取的数据转储到您不拥有的内存位置,从而导致分段错误。

你需要:

char *str;
str = malloc(BUFSIZ); // this is missing..also free() the mem once done using it.

或只是:

char str[BUFSIZ]; // but then you can't do str++, you'll have to use another 
                  // pointer say char *ptr = str; and use it in place of str.

编辑:

还有另一个错误:

while (fgets(str, sizeof BUFSIZ, file))

第二个参数应该是BUFSIZ而不是sizeof BUFSIZ

<强>为什么吗

因为第二个参数是要读入缓冲区的最大字符数,包括空字符。由于sizeof BUFSIZ4,因此您可以将最多3个字符读入缓冲区。这就是为什么19381被视为193然后81<space>的原因。

答案 1 :(得分:3)

您尚未分配任何内存来填充strfgets将第一个参数作为缓冲区,而不是未指定的指针。

您需要定义合理大小的缓冲区,而不是char *str;,而不是char str[BUFSIZ];

答案 2 :(得分:2)

因为您没有为缓冲区分配空间。

答案 3 :(得分:2)

很多人已经解决了你问过的问题,但我有一个问题作为回报。你认为这完成了什么:

        if (isdigit(*str))
        {
            if (isdigit(*str))
            {
                sum += atoi(str);
                str++;
                while (isdigit(*str))
                    str++;
                continue;
            }
        }

具有完全相同条件的两个连续if语句应该是什么意思? (注意记录:两者都没有else条款。)

答案 4 :(得分:1)

你已经声明了char * str,但是你还没有为它预留内存。你将需要malloc内存。

使用valgrind可以轻松找到许多与内存相关的错误,例如此错误。我强烈建议将它用作调试工具。

答案 5 :(得分:1)

char *str;

str没有分配内存。使用malloc()为其分配一些内存,或者使用预定义的大小声明它。

char str[MAX_SIZE];

答案 6 :(得分:1)

你的程序有几个错误:

  • 它无法正确处理长行。当您读取某个大小的缓冲区时,可能会发生某些数字从缓冲区末尾开始并在下一个缓冲区的开头继续。例如,如果您有一个大小为4的缓冲区,则可能有输入The |numb|er 1|2345| is |larg|e.,其中垂直线表示缓冲区的内容。然后,您将分别计算1和2345。
  • 以[{1}}为参数调用isdigit。只要您阅读任何“大”字符(大于char),行为就会未定义。您的程序可能会崩溃或产生不正确的结果或做任何想做的事情。要解决此问题,您必须先将值转换为SCHAR_MAX,例如unsigned char。或者,与我的代码一样,您可以从isdigit((unsigned char) *str)函数中提取值,该函数可以保证是fgetc的有效参数。
  • 您使用需要缓冲区(isdigit)的函数,但无法分配缓冲区。正如其他人所指出的,获取缓冲区的最简单方法是声明局部变量fgets
  • 您将char buffer[BUFSIZ]变量用于两个目的:保存缓冲区的地址(在整个执行时间内应保持不变)和用于分析文本的指针(在执行期间会发生变化)。制作这两个变量。我会称他们为strbuffer指针的缩写)。

这是我的代码:

p

答案 7 :(得分:0)

这是一个完成工作的功能:

static int sumNumbers(char* filename) {
    int sum = 0;
    FILE *file = fopen(filename, "r");
    char buf[BUFSIZ], *str;

    while (fgets(buf, BUFSIZ, file))
    {
            str=buf;
            while (*str)
            {
                    if (isdigit(*str))
                    {
                            sum += strtol(str, &str, 10);
                    }
                    str++;
            }
    }
    fclose(file);
    return sum;
}

这不包括错误处理,但效果很好。对于您的文件,输出将是

文件中所有数字的总和为:19483