【问题标题】:Why am I getting a segmentation fault?为什么会出现分段错误?
【发布时间】:2011-04-23 04:52:30
【问题描述】:

我正在尝试编写一个程序,该程序将纯文本文件作为参数并对其进行解析,将所有数字加在一起,然后打印出总和。以下是我的代码:

#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 19381. 完成。唷。

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

【问题讨论】:

    标签: c arrays pointers segmentation-fault


    【解决方案1】:

    您没有为缓冲区分配空间。
    指针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&lt;space&gt;

    【讨论】:

    • 嘿,谢谢它现在可以工作了。但如果你不介意多陪我一会儿。如果您在修复后尝试运行程序,由于某种原因,atoi() 将数字 19381 分别解析为 19381。知道为什么会这样吗?
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

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

        条件完全相同的两个连续的if 语句的意义何在? (记录在案:两者都没有else 子句)。

        【讨论】:

        • 不错的收获...+1 超越显而易见 =)
        • 抱歉,打错了。一定是太累了。
        【解决方案5】:

        你已经声明了 char* str,但你还没有为它留出内存。您需要为其分配内存。

        使用 valgrind 可以轻松找到许多与内存相关的错误,例如这个错误。我强烈推荐使用它作为调试工具。

        【讨论】:

          【解决方案6】:
          char *str;
          

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

          char str[MAX_SIZE];
          

          【讨论】:

            【解决方案7】:

            您的程序有几个错误:

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

            这是我的代码:

            #include <ctype.h>
            #include <stdio.h>
            
            static int sumNumbers(const char *filename)
            {
                int sum, num, c;
                FILE *f;
            
                if ((f = fopen(filename, "r")) == NULL) {
                    /* TODO: insert error handling here. */
                }
            
                sum = 0;
                num = 0;
                while ((c = fgetc(f)) != EOF) {
                    if (isdigit(c)) {
                        num = 10 * num + (c - '0');
                    } else if (num != 0) {
                        sum += num;
                        num = 0;
                    }
                }
            
                if (fclose(f) != 0) {
                    /* TODO: insert error handling here. */
                }
            
                return sum;
            }
            
            int main(int argc, char **argv) {
                int i;
            
                for (i = 1; i < argc; i++)
                    printf("%d\t%s\n", sumNumbers(argv[i]), argv[i]);
                return 0;
            }
            

            【讨论】:

            • 感谢您的宝贵反馈!欣赏它! :)
            【解决方案8】:

            这是一个功能,可以完成你的工作:

            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

            【讨论】:

              猜你喜欢
              • 2018-01-07
              • 1970-01-01
              相关资源
              最近更新 更多