我在面试问题中遇到了第一个问题。但我想对这个问题做一个正确的解释。我在家里尝试这个,其他一些混乱也在上升。
#include <stdio.h>
int main()
{
int arr[4]={10,20,30,40};
int i;
for(i=0;i<=4;i++)
printf("%d,",arr[i]);
printf("\n");
return 0;
}
OUTPUT
10,20,30,40,4,
最后一个输出是4.但是它没有数组索引。我认为在内存变量中我出现在数组元素之后。所以我得到了这个答案。
但我再次对此感到困惑
#include <stdio.h>
int main()
{
char arr[4]={10,20,30,40};
int i;
for(i=0;i<=4;i++)
printf("%d,",arr[i]);
printf("\n");
return 0;
}
OUTPUT
10,20,30,40,0,
再次与下面的内容相混淆
#include <stdio.h>
int main()
{
int arr[4]={10,20,30,40};
char i;
for(i=0;i<=4;i++)
printf("%d,",arr[i]);
printf("\n");
return 0;
}
OUTPUT
10,20,30,40,74743796,
任何人都可以解释为什么输出会出现这种变化?
我使用的是intel cpu,Ubuntu os,Gcc complier ..
如果编译器特定或体系结构具体,那么请在答案中提及。
答案 0 :(得分:1)
这称为Undefined Behavior。由于您正在访问其范围之外的数组,因此任何都可能发生,并且结果不必(也不会有意义)。
答案 1 :(得分:1)
您不应该访问超出范围的数组内存。越界数组访问的值可以是任何东西 - 它没有预期值,并且它具有未定义的行为。看起来您期望在数组之后在本地创建的char和int变量位于数组变量之后的内存中。即使是这种情况,你也没有初始化这些变量,因此它们的价值可能是任何东西。只是不要访问超出范围的内存,当然也不要试图预测访问它的结果。
答案 2 :(得分:0)
您正在处理的是未定义的行为。
在第一种情况下,恰好将i
变量放在堆栈上的arr
数组之后,因此超出了触及{{1}的数组的边界变量。 i
和i
的类型相同(arr
),因此将int
打印出来就好像它是数组的一部分一样正常。
在第二种情况下,您尝试访问i
,就好像它是i
变量一样,所以您只能得到零的一部分。
请记住,编译器可以自由地重新排列堆栈上的变量,因此任何假设char
变量应该紧跟在之后(即使按照该顺序声明)是不正确的。
对于编译器,i
和arr
只是两个独立的局部变量。 i
的大小不保留在内存中的任何位置:arr
只是一块带有起始地址的内存。您可以通过静态arr
运算符在编译时检查其大小。
答案 3 :(得分:0)
要清楚,您所看到的内容被归类为“未定义的行为”,但您的答案中有足够的信息可以了解正在发生的事情。
首先,我们可以从您关于机器架构的问题中看到一些细节。
关于CPU
关于操作系统
关于编译器
int
的大小为32位char
的大小为8位char
放入更大的块中,而不是加速运行时间所有这些事情结合在一起,最终得到了你所看到的结果。视觉演示最适合展示从这里发生的事情。
在循环结束时,堆栈如下所示:
| 10 | 0 | 0 | 0 | a[0]
| 20 | 0 | 0 | 0 | a[1]
| 30 | 0 | 0 | 0 | a[2]
| 40 | 0 | 0 | 0 | a[3]
| 4 | 0 | 0 | 0 | i (a[4])
i
的值与a[4]
应该在同一位置。因此a[4]
与i
具有相同的价值。
i
的外观取决于很多变量。但似乎这是最有意义的布局。
| 10 | 0 | 0 | 0 | a[0]
| 20 | 0 | 0 | 0 | a[1]
| 30 | 0 | 0 | 0 | a[2]
| 40 | 0 | 0 | 0 | a[3]
| X | X | X | 4 | i (a[4])
这反映在您看到的打印值中。小端二进制文件中的74743796
是
11110100 01111111 01110100 00000100
最后一个字节有4
。当您在代码中引用i
时,上下文将作为char并且仅使用最后一个字节。当您引用a[4]
时,上下文为int
,并且使用了所有四个字节。
这很重要,因为它表明编译器将字符推入最后一个字节并用垃圾填充其余字符。
基于其他两个,我希望内存如下
| X | X | X | 10 | a[0]
| X | X | X | 20 | a[1]
| X | X | X | 30 | a[2]
| X | X | X | 40 | a[3]
| 4 | 0 | 0 | 0 | i (a[4])
魔法与最后的记忆线发挥作用。当它作为int
访问时,它会正常处理。但是,当它作为char
访问时,编译器假定前三个字节是填充并返回最后一个字节,或0