您的位置:首页 > 其它

一场由插入排序引发的血案--从sizeof看int型数组和int型指针的不同

2016-11-07 11:20 323 查看

1. 前言

闲来无事想温习一下排序算法,于是从插入排序开始做,自己写了一段c程序来实现将一个数组按照从大到小的顺序排序,代码如下:
void InsertionSort(int a[])
{
int i=0,j=0,tmp=0;
for(i = 1; i < (int)(sizeof(a)/sizeof(int)); ++i)
{
if(a[i] > a[i-1])
{
tmp = a[i];
j = i;
for(;j > 0 && tmp > a[j-1]; --j)
{
a[j] = a[j-1];
}
a[j] = tmp;
}
}
}
这个函数的形式参数只有数组,至于数组的元素个数就使用sizeof运算符来求(当然,这里对于数组的要求必须是形如:int a[3]={2,4,6}这样的数组,如果是类似于:int b[100]={2,4,6}的数组,sizeof运算符就不能解决求数组元素个数的问题啦)。我的实验平台是macOS Sierra,cpu:2.7 GHz Intel Core
i5,Xcode Version 8.0 (8A218a)。下面是我在main函数中的测试代码:
int i = 0;
int a[5] = {1,2,3,6,40};
InsertionSort(a);
printf("The result of InsertionSort(a) is:\n");
for(i = 0; i < (int)(sizeof(a)/sizeof(int)); ++i)
{
printf("%d ",a[i]);
}
printf("\n");
在测试代码中,我给定一个长度为5的数组(1,2,3,6,40),然后使用插入排序算法,使其按照从大到小的规则排序,因此我期望的结果是(40,6,3,2,1),但是运行之后的结果却出乎我的意料:
The result of InsertionSort(a) is:
2 1 3 6 40
从结果上来看,程序好像只进行了一次插入排序,可是为什么会导致这种情况呢?

2. 问题探究

为了一探究竟,我决定做一些测试,看看问题究竟出在哪里。
排序是由InsertionSort函数完成的,因此我将目标锁定在传入的数组和排序的次数(也就是:(int)(sizeof(a)/sizeof(int)))。首先,我们要确认传入的数组是不是完整,因此,我在原函数中加进了一段遍历代码,看是否能够成功遍历:
for(i = 0; i < (int)(sizeof(a)/sizeof(int)); ++i)
{
printf("Message from InsertionSort:%d \n",a[i]);
}
运行的结果如下:
Message from InsertionSort:1
Message from InsertionSort:2
这和我的预期不一样啊,为什么不是(1,2,3,6,40)呢?难道是数组出了什么问题?于是我决定再试着遍历一下,不过这次不使用(int)(sizeof(a)/sizeof(int)),因为数组长度已知,第二次遍历直接用数字5来替代:
printf("Message from InsertionSort:第二次打印\n");
for(i = 0; i < 5; ++i)
{
printf("Message from InsertionSort:%d \n",a[i]);
}
这次的结果正常了:
Message from InsertionSort:第二次打印
Message from InsertionSort:1 Message from InsertionSort:2
Message from InsertionSort:3
Message from InsertionSort:6
Message from InsertionSort:40
这个结果说明了一个问题,问题出在(int)(sizeof(a)/sizeof(int))这句话上,于是我试着打印了一下这句话的结果:
printf("Message from InsertionSort:(int)(sizeof(a)/sizeof(int))=%d\n",(int)(sizeof(a)/sizeof(int)));
下面的结果证明了为什么只进行了一次插入排序:
Message from InsertionSort:(int)(sizeof(a)/sizeof(int))=2
(int)(sizeof(a)/sizeof(int))这句话的值为2,参看上面的插入排序实现很容易明白循环为何只进行了一次,但是话说回来,这句话为什么会等于2呢?预感是sizeof(a)出了问题,于是我又打印了一下sizeof(a):

printf("Message from InsertionSort:(int)sizeof(a)=%d\n",(int)sizeof(a));
结果告诉了我为啥上面那句话是2了:
Message from InsertionSort:(int)sizeof(a)=8
分析到此结束,现在我明白了排序出错的原因:传入函数的数组名,被当做了一个int*类型的变量,因此导致在进行sizeof运算时输出了一个int*变量的长度。这里我有一个疑问,在c语言中,将一个数组作为形式参数传入函数的时候,它难道会自动转化为一个指针?关于这个问题我至今没想明白,如果有大神懂得的话还望不吝赐教~

3. 启发

搞清楚上面的问题,我又做了一个实验:在main函数中,我分别定义一个int型数组a和一个int*型的变量b,然后使b也指向a,这时,再使用sizeof运算符计算a和b的长度,看结果如何,main 函数中的测试代码如下:
int a[5] = {1,2,3,6,40};
int* b = a;
printf("sizof(a)=%d\n",(int)sizeof(a));
printf("sizof(a)/sizeof(int)=%d\n",(int)(sizeof(a)/sizeof(int)));
printf("sizeof(b)=%d\n",(int)(sizeof(b)));
结果如下:
sizeof(a)=20
sizeof(a)/sizeof(int)=5
sizeof(b)=8
从这个结果来看,在 main函数中,系统似乎针对数组和指针做了区分,在对数组进行sizeof运算的时候就会得到整个数组所占的内存空间的长度,而对一个指针进行sizeof运算时只会得到指针变量的长度,也许这正是数组和指针的区别之一吧。

4. 后记

关于数组和指针的研究就到此为止了,我决定修改我的插入排序函数,将数组的长度作为参数传到函数里去:
void InsertionSort2(int a[],int length)
{
int i=0,j=0,tmp=0;
for(i = 1; i < length; ++i)
{
if(a[i] > a[i-1])
{
tmp = a[i];
j = i;
for(;j > 0 && tmp > a[j-1]; --j)
{
a[j] = a[j-1];
}
a[j] = tmp;
}
}
}
在main函数中调用排序函数时,要先将正确的数组长度算出来,然后再传入函数,以下是main函数的测试代码:
int a[5] = {1,2,3,6,40};
InsertionSort2(a,(int)(sizeof(a)/sizeof(int)));
printf("The result of InsertionSort2(a) is:\n");
for(i = 0; i < (int)(sizeof(a)/sizeof(int)); ++i)
{
printf("%d ",a[i]);
}
再运行之后,我们可以看看结果:
The result of InsertionSort2(a) is:
40 6 3 2 1
终于得到了正确的结果!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: