我的一位 friend 将此代码发送给我,说它无法按预期工作:
#include<stdio.h>
void main()
{
int a [10] ={23, 100, 20, 30, 25, 45, 40, 55, 43, 42};
int sizeOfInput = sizeof(a)/sizeof(int);
int b, outer, inner, c;
printf("Size is : %d \n", sizeOfInput);
printf("Values before bubble sort are : \n");
for ( b = 0; b < sizeOfInput; b++)
printf("%d\n", a[b]);
printf("End of values before bubble sort... \n");
for ( outer = sizeOfInput; outer > 0; outer-- )
{
for ( inner = 0 ; inner < outer ; inner++)
{
printf ( "Comparing positions: %d and %d\n",inner,inner+1);
if ( a[inner] > a[inner + 1] )
{
int tmp = a[inner];
a[inner] = a [inner+1];
a[inner+1] = tmp;
}
}
printf ( "Bubble sort total array size after inner loop is %d :\n",sizeOfInput);
printf ( "Bubble sort sizeOfInput after inner loop is %d :\n",sizeOfInput);
}
printf ( "Bubble sort total array size at the end is %d :\n",sizeOfInput);
for ( c = 0 ; c < sizeOfInput; c++)
printf("Element: %d\n", a[c]);
}
我正在使用Micosoft Visual Studio命令行工具在Windows XP计算机上进行编译。
cl /EHsc bubblesort01.c
我的 friend 在恐龙机器上获得了正确的输出(在那里使用TCC编译了代码)。
我的输出是意外的。介于两者之间的数组神秘地增大了。
如果您更改代码,以便将变量
sizeOfInput
更改为sizeOfInputt
,它将提供预期的结果!在Microsoft Visual C++ Developer Center上进行的搜索不会为“sizeOfInput”提供任何结果。
我不是C/C++专家,并且很想知道为什么会发生这种情况-任何C/C++专家都可以对此有所了解吗?
不相关的说明:我认真考虑过将整个代码重写为使用quicksort或merge sort,然后再将其发布到此处。但是,毕竟这不是Stooge排序...
编辑:我知道代码是不正确的(它读取超出最后一个元素),但是我很好奇为什么变量名会有所作为。
最佳答案
像interjay's answer mentioned一样,一旦您进入未定义的行为,所有的赌注都将关闭。但是,当您说仅重命名变量会更改程序的行为时,我对正在发生的事情(未定义或未定义)感到好奇。
首先,我不相信重命名该变量会改变编译器的输出(在所有其他条件相同的情况下),但是可以肯定的是-当我尝试使用它时,我惊讶地发现您所描述的确切。
因此,我让编译器转储了它针对源文件的每个版本生成的代码的程序集,并进行了比较。这是我在编译器说明中找到的关于如何布局局部变量的内容:
***** test.sizeOfInput.cod
_c$ = -56 ; size = 4
_b$ = -52 ; size = 4
_inner$ = -48 ; size = 4
_a$ = -44 ; size = 40
>>> _sizeOfInput$ = -4 ; size = 4
_main PROC
***** test.sizeOfInputt.cod
_c$ = -56 ; size = 4
>>> _sizeOfInputt$ = -52 ; size = 4
_b$ = -48 ; size = 4
_inner$ = -44 ; size = 4
_a$ = -40 ; size = 40
_main PROC
*****
您会注意到,当变量名为
sizeOfInput
时,编译器将其放置在比数组a
高的地址处(刚好在数组的末尾),而当变量被命名为sizeOfInputt
时,将其放置在比数组a
而不是刚过去数组的末尾。这意味着在具有名为sizeOfInput
的变量的构建中,修改a[10]
时发生的未定义行为正在更改sizeOfInput
的值。在使用名称sizeOfInputt
的构建中,由于该变量不在数组的末尾,因此对a[10]
的写入会浪费其他内容。至于为什么当一个人的名字以明显无关紧要的方式改变时,编译器为什么会以不同的方式布置变量-我不知道。
但这是一个很好的例子,说明了为什么不应该依靠局部变量(或几乎任何变量,尽管可以依靠struct元素的布局顺序)的布局,以及为什么涉及未定义的行为,“可以在我的计算机上运行”,并不表示它可以正常工作。