一场由插入排序引发的血案--从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:第二次打印这个结果说明了一个问题,问题出在(int)(sizeof(a)/sizeof(int))这句话上,于是我试着打印了一下这句话的结果:
Message from InsertionSort:1 Message from InsertionSort:2
Message from InsertionSort:3
Message from InsertionSort:6
Message from InsertionSort:40
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终于得到了正确的结果!
相关文章推荐
- sizeof ()求指针和数组时的不同
- sizeof(数组名)和sizeof(指针名)的结果是不同的
- C语言中sizeof对数组和对指针操作的不同,以及sizeof中表达式赋值问题
- sizeof ()求指针和数组时的不同
- sizeof(数组名)和sizeof(指针)
- 一场版本升级引发的性能血案 - 之数据历险
- 别人不会给你说的---C语言中数组名和指针的区别 及 sizeof用法
- PHP队列--选举引发的一场血案
- 内存的堆分配和栈分配 & 字符数组,字符指针,Sizeof总结
- 从“数组和指针sizeof的区别”分析
- 【运维囧事】NTP服务器引发的一场血案
- 数组名和指针的区别 sizeof
- 【转】字符数组,字符指针,Sizeof总结
- 初始化:普通数组 vs 指针数组 => sizeof, memset
- 字符数组,字符指针,stren和sizeof的区别
- 计算结构体、数组、指针的sizeof
- 一场Socket四次握手引发的血案
- sizeof(数组名)和sizeof(指针)
- 一场Socket四次握手引发的血案
- SwipeRefreshLayout 引发的一场血案