Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 为什么即使我';m在一个3大小的数组上分配4个值?_Arrays_C_For Loop_Post Increment_Pre Increment - Fatal编程技术网

Arrays 为什么即使我';m在一个3大小的数组上分配4个值?

Arrays 为什么即使我';m在一个3大小的数组上分配4个值?,arrays,c,for-loop,post-increment,pre-increment,Arrays,C,For Loop,Post Increment,Pre Increment,顺便说一句,我对编码相当陌生:) 基本上,我正在尝试做一个程序,询问学生他有多少分数(div),并计算总分数(nota=grade,im葡萄牙语)请注意,在每次尝试中,我总是输入'3'和div的值,并且我只显示部分代码 至于[正确版本],在我看来一切正常,运行良好 **[CORRECT VERSION]** short unsigned int div, i; printf("Pretende fazer a media de quantas notas?(Máxim

顺便说一句,我对编码相当陌生:)

基本上,我正在尝试做一个程序,询问学生他有多少分数(
div
),并计算总分数(nota=grade,im葡萄牙语)请注意,在每次尝试中,我总是输入'3'和
div的值,并且我只显示部分代码

至于[正确版本],在我看来一切正常,运行良好

**[CORRECT VERSION]**

    short unsigned int div, i;
    printf("Pretende fazer a media de quantas notas?(Máximo é 10): ");
    scanf("%hd", &div);
    float nota[div], media, soma = 0;
    for(i = 0; i < div; i++) { //duvida linhas 25-26
        pergunta:
        printf("A %dª nota foi: ", i+1);
        scanf("%f", &nota[i]);
       if((nota[i] < 0) || (nota[i] >20)) {
        printf("\n(Erro: Por favor insira valores de 0 a 20\n");
        goto pergunta;
但是,将
div
替换为
3
,即使它的值与上一版本中假定的
div
相同,我还是得到了一个分段错误(在一些其他实验中,总线错误

[无div的版本出现正常错误]
短无符号整数div,i;
//printf(“假装是一种媒体”(Máximoé10):”;
//scanf(“%hd”、&div);
float nota[3],media,soma=0;
对于(i=0;i++<3;){//duvida linhas 25-26
佩尔冈塔:
printf(“A%dªnota foi:”,i);
scanf(“%f”、¬a[i]);
如果((nota[i]<0)|(nota[i]>20)){
printf(“\n(Erro:Por favor insira valores de 0 a 20\n”);
后藤佩尔冈塔;

你能解释一下我遗漏了什么吗?为什么即使是[“无意义”版本]也会运行,尽管它与上一个版本几乎相同?

这里有很多要解包的内容,但让我们按顺序来做

首先,不要这样做:

unsigned div;
scanf("%hd", &div);
float nota[div], media, soma = 0;
如果你知道学生可以输入的最大分数,你应该预先定义一个最大分数。或者使用动态分配。更多关于这方面的信息可以在这个StackOverflow中找到。 您正在做的是创建一个VLA可变长度数组。这是在C99标准中添加的,但使用它会降低可移植性,因为并非所有编译器都遵守该标准

其次,您使用的是非惯用for循环。编程中的惯用语是做某些事情的事实标准。我们使用惯用语是因为它减少了出错的机会,并使其他人更容易阅读和维护我们的代码。这就是为什么我们坚持使用惯用语

for(int i = 0, i < n; i++){}
for(inti=0,i
我想你已经意识到了这一点(你称之为“无意义”),但我只是想向那些可能尝试使用类似于(I=0;I++<3;)
的代码的人说明这一点——这将给你留下你不想看到的严重错误和行为

将这两个因素结合在一起,我们可以看到这里发生了什么: 在您的无意义示例中,您使用的是VLA。其工作方式取决于,但我猜,在本例中,编译器会查看变量div的类型-因为它是无符号短,它知道该值在(0-65535)范围内*,因此该值相对较小。因为它是一个较小的值,所以它在堆栈上分配了足够的内存,以容纳一个长度最多为~65k的数组。这意味着您可以“安全”地读写该内存,而不会出现堆栈溢出,因为操作系统已授予您的程序写入内存中65k元素点的权限

在另一种情况下,你对编译器说你的数组将有3个元素长,因此你的程序只从操作系统请求3个元素的空间。操作系统不喜欢你尝试从它没有给你的内存读写,因此你最终会出错

最后说明: 请不要使用


*假设unsigned short的长度为16b,这是最小值-根据系统的不同,长度可能会更长。

由于您正在调用未定义的行为,任何情况都可能发生,包括怀孕或收到$10G支票。数组溢出并不总是会导致崩溃。通常情况下,它会导致覆盖一些不相关的数据变量。第二个和第三个非常不同:在第二种情况下,数组是可变长度数组(VLA),在第三种情况下是一个固定大小的数组。因为VLA是动态分配的,所以它可能是堆栈上最顶层的对象,在覆盖函数的返回值或其他可能导致崩溃的内容之前,它有更多的空间。这看起来像是另一个关于为什么未定义的行为在特定的def中不起作用的问题是这样吗?因为UB不需要帮助您找到错误。s/return value/return address/以上。什么编译器会在堆栈上为12字节可变长度数组分配65k内存?为什么会这样做?VLAs和alloca()不好,它们没有那么坏。
unsigned div;
scanf("%hd", &div);
float nota[div], media, soma = 0;
for(int i = 0, i < n; i++){}