为什么我的循环在 c 中无法正常工作?

  • 本文关键字:常工作 工作 循环 c
  • 更新时间 :
  • 英文 :


这是我的代码。它应该首先扫描两个数字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]);
}
}

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

int n = 0;
int x[n];

试图声明一个大小为0的可变长度数组,这已经是未定义的行为。

即使这是可能的(有一个零元素空间的VLA),

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

…也会是未定义行为。

让我试着解释考虑x86_64架构和gcc7.5x编译器的代码行为。

这个答案和这个问题的答案提供了x86在不同架构上堆栈增长的方向,它是向下的,这意味着堆栈将从高内存增长到低内存地址(0xFF—>0 x00)

如果我们稍微修改一下代码,在运行时打印变量的地址和值,如下所示:

#include <stdio.h>
int main()
{
int m = 0;
int n = 0;
int x[n];

printf("Size of int: %dn", sizeof(int));
printf("Address ofnm: %pnn: %pnx: %pn", &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: %pn", &x[i]);
}
for(int j = 0; j < n; j++)
{
printf("x[%d]: %dn", x[j]);
}
printf("m: %d n: %dn", 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回答说这将导致未定义行为的原因。

我希望我能提供一些澄清。

相关内容

  • 没有找到相关文章

最新更新