为什么我的循环在c中不能正常工作?

bmvo0sr5  于 2023-04-29  发布在  其他
关注(0)|答案(2)|浏览(137)

这是我的代码。首先要扫描2个数字m和n。然后扫描一个数字数组,即x[n]。第二行扫描的数字数应为n。但它不能正常工作。

#include <stdio.h>

int main()
{
    int m = 0;
    int n = 0;
    int x[n];
    scanf("%d", &m);
    scanf("%d", &n);
    for(int i = 0 ;i < n;i++)
    {
        scanf("%d", &x[i]);
    }
}

它只扫描1个数字并跳出循环。我们应该有(i)s从0到n-1;

px9o7tmv

px9o7tmv1#

int n = 0;
int x[n];

这试图声明一个大小为零的可变长度数组,这已经是未定义的行为。
即使这(有一个零元素空间的VLA)在某种程度上是可能的,

scanf("%d", &x[i]);

...也是未定义的行为。

5f0d552i

5f0d552i2#

让我试着解释一下考虑x86_64架构和gcc7.5x编译器的代码行为。
This answerthis answer的问题提供了堆栈在不同架构上的增长方向,对于x86来说,它是向下的,这意味着堆栈将从高内存地址增长到低内存地址(0xFF --〉0x 00)
如果我们稍微修改你的代码,在运行时打印变量的地址和值,如图所示:

#include <stdio.h>

int main()
{
    int m = 0;
    int n = 0;
    int x[n];
    
    printf("Size of int: %d\n", sizeof(int));
    printf("Address of\nm: %p\nn: %p\nx: %p\n", &m, &n, &x);
    printf("Enter a value of m: ");
    scanf("%d", &m);
    printf("Enter a value of n: ");
    scanf("%d", &n);
    
    for(int i = 0; i < n; i++)
    {
        scanf("%d", &x[i]);
        printf("Addr: %p\n", &x[i]);
    }
    for(int j = 0; j < n; j++)
    {
        printf("x[%d]: %d\n", x[j]);
    }
    printf("m: %d n: %d\n", m, n);
}

x86上编译并运行上述代码后,我们可以注意到局部变量的地址是按降序分配的,如下所示,用于一个代码执行会话:

Address of
m: 0x7ffdfb2b1704
n: 0x7ffdfb2b1700
x: 0x7ffdfb2b16f0

如果你注意到nx的地址不同,它们是16-Bytes,理想情况下它们应该在堆栈上是4-bytes
但是,由于int x[n]被声明为0整数数组,因此理想情况下,它应该占用4字节的内存,即使底层编译器和体系结构机制将其视为4整数数组,并将其转换为
4 integers * sizof(int) = 16-bytes
查看代码的进一步执行输出,我们可以看到,随着代码的进一步执行,地址0x7ffdfb2b1700处的n的值被覆盖。
请注意,代码对于n < 5的值将正常工作,因为对于n = 4的值,循环将在n = 3处终止,在这种情况下,n的值将不会被覆盖,因为循环迭代为(n * sizeof(int)) ==> 3 * 4 = 12-bytes

Enter a value of m: 1
Enter a value of n: 10
1
Addr: 0x7ffdfb2b16f0
2
Addr: 0x7ffdfb2b16f4
3
Addr: 0x7ffdfb2b16f8
4
Addr: 0x7ffdfb2b16fc
5
Addr: 0x7ffdfb2b1700  <--- address of variable `n` getting overwritten with new value
x[1]: 0
x[2]: 1
x[3]: 2
x[4]: 3
x[5]: 4
m: 1 n: 5

这就是为什么@DevSolar回答说这将导致未定义的行为。
我希望我能够提供一些澄清。

相关问题