[英]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 BUFSIZ
为4
您可以将最多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: 你的程序有几个错误:
The |numb|er 1|2345| is |larg|e.
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. 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. 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
的有效参数。 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]
。 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. buffer
and p
(short for pointer ). buffer
和p
( 指针的缩写)。 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.