c-为什么扫描后访问数组的代码会导致分割错误



有些家庭作业我必须用C写一个计算器。我想用scanf输入一些字符串,然后访问它。但当我访问第一个元素时,我遇到了分段错误。

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(){
char input1[30];
scanf("%s",input1);
printf("%s",input1);
char current = input1[0];
int counter = 0;
while(current != ''){
if(isdigit(current) || current == '+' || current == '-' || current == '*' || current == '/'){
counter++;
current = input1[counter];
}else{
printf("invalid inputn");
exit(1);
}
}
return 0;
} 

第3行的printf返回字符串,但在第4行访问它会返回一个分段错误(在gdb中测试(。为什么?

有一些潜在的原因,其中一些已经在评论中提到了(我不讨论这些(。很难说哪一个(或多个(是问题的原因,所以我想迭代它们是有意义的。然而,你可能会注意到,我在这个过程中引用了一些资源。。。信息就在那里,但你不会偶然发现它,直到为时已晚。你的研究方式需要改变,因为这会减缓你的进度。


关于输入/输出动态,只需快速提示

printf("%s",input1);

除非我们包含一个尾随换行符,否则此输出可能会延迟(或"缓冲"(,这可能会让您混淆问题的根源。作为使用尾随换行符的替代方法(我个人更喜欢(,您可以通过在每次相关输出操作后立即调用fflush(stdout)来显式强制写入部分行,或者使用setbuf来完全禁用缓冲。我认为这不太可能是你的问题,但它可能掩盖了你的问题。因此,重要的是要意识到,当使用printf进行调试时,最好包含一个尾随的换行符。。。


main入口点

我看到的第一个潜在罪魁祸首是:

int main()

我不知道为什么我们的教育系统仍然在推行这些支离破碎的课程。我唯一的猜测是,教授们多年前就使用了如今无关紧要的Turbo C,不想跟上技术的发展。我们可以将其进一步简化为一个简单的测试用例,以确定这是否是你的segfault,但正如我所说,很难说这是否真的是你的问题。。。

int main() {
char input1[30];
memset(input1, 'x90', sizeof input1);
return 0; // this is redundant for `main` nowadays, btw
}

为了解释这里发生了什么,我将引用这个页面,一旦你在这里完成,你可能应该去阅读(完整的(:

对于C程序员来说,一个常见的误解是假设如下原型化的函数不需要参数:

int foo();

事实上,这个函数被认为接受了未知数量的参数。在括号中使用关键字void是告诉编译器函数不接受任何参数的正确方法。

简单地说,如果链接器不知道/无法计算出入口点需要多少个参数,那么调用堆栈可能会出现一些奇怪的情况,这种情况会发生在程序的开头或结尾。


关于输入错误、返回值和未初始化访问

#include <assert.h>
#include <stdio.h>
#include <string.h>
int main(void) {
char input1[30];
memset(input1, 'x90', sizeof input1);
scanf("%s",input1); // this is sus a.f.
assert(memchr(input1, '', sizeof input1));
}

在我的测试用例中,我实际上向数组中的每个字节写入了'x90',以表明如果scanf调用失败,您可能会得到一个没有空终止符的数组。如果这是您的问题,那么当您运行这个断言时,它很可能会抛出(正如您从ideone演示中看到的那样(,这表明您的循环访问的垃圾可能超出了input1的范围。关于这一点,我想证明,除非我们也检查他们的返回值,否则我们(大部分(不能依赖scanf和朋友很有可能你的编译器正在警告你这一点,所以另一个教训是要密切注意警告消息,并努力使没有


标准库函数的参数期望

对于许多标准库函数,可能会给出超出可接受域的输入,从而导致不稳定。我在您的程序中也看到了最常见的形式,它可能以向<ctype.h>函数传递无效值的形式存在。在您的情况下,您可以将current的声明更改为unsigned char,但通常的习惯用法是在调用中显式地放置强制转换(如isdigit((unsigned char) current)(,这样我们其他人就可以看到您没有陷入这种常见错误,至少在学习C.时是这样


请注意,在这一点上,我认为你用来学习的任何资源都不起作用,因为你陷入了常见的陷阱。。。请尝试寻找更多信誉良好的资源来学习,这样你就不会陷入更常见的陷阱,以后会浪费更多的时间。如果你正在挣扎,请查看C标签wiki。。。

最新更新