简体   繁体   English

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

[英]Why am I getting a segmentation fault?

I'm trying to write a program that takes in a plaintext file as it's argument and parses through it, adding all the numbers together and then print out the sum. 我正在尝试编写一个程序,它接收一个明文文件作为它的参数并解析它,将所有数字加在一起,然后打印出总和。 The following is my code: 以下是我的代码:

#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;
}

And the text file I'm using is: 我正在使用的文本文件是:

This a rather boring text file with some random numbers scattered throughout it. 这是一个相当无聊的文本文件,其中散布着一些随机数字。

Here is one: 87 and here is another: 3 这是一个:87,这是另一个:3

and finally two last numbers: 12 19381. Done. 最后两个数字:12 19381.完成。 Phew. 唷。

When I compile and try to run it, I get a segmentation fault. 当我编译并尝试运行它时,我得到一个分段错误。

You've not allocated space for the buffer. 您没有为缓冲区分配空间。
The pointer str is just a dangling pointer. 指针str只是一个悬空指针。 So your program effectively dumps the data read from the file into memory location which you don't own, leading to the segmentation fault. 因此,您的程序有效地将从文件读取的数据转储到您不拥有的内存位置,从而导致分段错误。

You need: 你需要:

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

or just: 要不就:

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.

EDIT: 编辑:

There is another bug in: 还有另一个错误:

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

The 2nd argument should be BUFSIZ not sizeof BUFSIZ . 第二个参数应该是BUFSIZ而不是sizeof BUFSIZ

Why? 为什么?

Because the 2nd argument is the maximum number of characters to be read into the buffer including the null-character. 因为第二个参数是要读入缓冲区的最大字符数,包括空字符。 Since sizeof BUFSIZ is 4 you can read max upto 3 char into the buffer. 由于sizeof BUFSIZ4您可以将最多3字符读取到缓冲区中。 That is reason why 19381 was being read as 193 and then 81<space> . 这就是为什么19381被读为193然后81<space>

You haven't allocated any memory to populate str . 你还没有分配任何内存来填充str fgets takes as its first argument a buffer, not an unassigned pointer. fgets将第一个参数作为缓冲区,而不是未分配的指针。

Instead of char *str; 而不是char *str; you need to define a reasonably sized buffer, say, char str[BUFSIZ]; 你需要定义一个合理大小的缓冲区,比如char str[BUFSIZ];

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

A number of people have already addressed the problem you asked about, but I've got a question in return. 很多人已经解决了你问的问题,但我有一个问题作为回报。 What exactly do you think this accomplishes: 您认为这完成了什么:

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

What's supposed to be the point of two successive if statements with the exact same condition? 什么应该是具有完全相同条件的两个连续if语句的要点? (Note for the record: neither one has an else clause). (注意记录:两个都没有else子句)。

You have declared char* str, but you have not set aside memory for it just yet. 你已经声明了char * str,但你还没有为它预留内存。 You will need to malloc memory for it. 你需要malloc内存。

Many memory related errors such as this one can be easily found with valgrind. 使用valgrind可以很容易地找到许多与内存相关的错误,例如这个错误。 I'd highly recommend using it as a debugging tool. 我强烈建议将它用作调试工具。

char *str;

str has no memory allocated for it. str没有为它分配内存。 Either use malloc() to allocate some memory for it, or declared it with a predefined size. 使用malloc()为其分配一些内存,或者使用预定义的大小声明它。

char str[MAX_SIZE];

Your program has several bugs: 你的程序有几个错误:

  • It does not handle long lines correctly. 它无法正确处理长行。 When you read a buffer of some size it may happen that some number starts at the end of the buffer and continues at the beginning of the next buffer. 当您读取某个大小的缓冲区时,可能会发生某些数字从缓冲区末尾开始并在下一个缓冲区的开头继续。 For example, if you have a buffer of size 4, there might be the input The |numb|er 1|2345| is |larg|e. 例如,如果您有一个大小为4的缓冲区,则可能有输入The |numb|er 1|2345| is |larg|e. The |numb|er 1|2345| is |larg|e. , where the vertical lines indicate the buffer's contents. ,垂直线表示缓冲区的内容。 You would then count the 1 and the 2345 separately. 然后你将分别计算1和2345。
  • It calls isdigit with a char as argument. 它使用char作为参数调用isdigit As soon as you read any "large" character (greater than SCHAR_MAX ) the behavior is undefined . 一旦读取任何“大”字符(大于SCHAR_MAX ), 行为就是未定义的 Your program might crash or produce incorrect results or do whatever it wants to do. 您的程序可能会崩溃或产生不正确的结果或做任何想做的事情。 To fix this, you must first cast the value to an unsigned char , for example isdigit((unsigned char) *str) . 要解决此问题,必须先将值转换为unsigned char ,例如isdigit((unsigned char) *str) Or, as in my code, you can feed it the value from the fgetc function, which is guaranteed to be a valid argument for isdigit . 或者,就像在我的代码中一样,您可以从fgetc函数中提供值,该函数保证是isdigit的有效参数。
  • You use a function that requires a buffer ( fgets ) but you fail to allocate the buffer. 您使用需要缓冲区( fgets )的函数,但无法分配缓冲区。 As others noted, the easiest way to get a buffer is to declare a local variable char buffer[BUFSIZ] . 正如其他人所指出的,获取缓冲区的最简单方法是声明一个局部变量char buffer[BUFSIZ]
  • You use the str variable for two purposes: To hold the address of the buffer (which should remain constant over the whole execution time) and the pointer for analyzing the text (which changes during the execution). 您可以将str变量用于两个目的:保存缓冲区的地址(在整个执行时间内应保持不变)和用于分析文本的指针(在执行期间更改)。 Make these two variables. 制作这两个变量。 I would call them buffer and p (short for pointer ). 我会称它们为bufferp指针的缩写)。

Here is my code: 这是我的代码:

#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;
}

Here is a function, that does your job: 这是一个功能,它可以完成你的工作:

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;
}

This doesn't includes error handling, but works quite well. 这不包括错误处理,但效果很好。 For your file, output will be 对于您的文件,输出将是

The sum of all the numbers in the file is : 19483 文件中所有数字的总和是:19483

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM