您的位置:首页 > 编程语言 > C语言/C++

C++函数参数为数组时的解析

2015-07-19 22:26 197 查看
会提到这个问题是因为前几天自己随手写了个简单的插入排序函数。刚开始的时候自己打算让该函数接受一个数组作为参数,经过函数的排序后使得数组中的元素按非递减顺序排列。所以按照这个想法自己写下了如下的函数
#include<stddef.h>
/*
*插入排序,算法导论中的解释很好:可以将排序过程看做是摸牌,每次从桌面上拿最上面一张牌
*然后插入到左手里面,左手中的牌是已经排序好了的。那么将牌放到合适的位置即是与左右从右到左
*的每一张牌进行对比,直到找到一个合适的位置将牌插入。初始时候是手里只有一张牌,到桌面上的牌全部
*摸完的时候即是排序完成的时候
*/
template <class T> void insertionSort(T* A){
size_t size = sizeof(A) / sizeof(*A);//求得数组大小
for (int j = 1; j < size; j++){
T key = A[j];//从桌面上摸的第一张牌,即数组的第二个元素
size_t i = j - 1;//手里从左到右的最后一张牌
while (i>0 && A[i] > key){
A[i + 1] = A[i];//为该张牌找到合适的位置
--i;
}//此处避免了只有一个元素的情况,因为&&当i小于0时也不会出现A[-1]的情况
A[i + 1] = key;
}
}

想法很简单,数组和指针本就没有严格的区分。在传入一个数组后计算其元素的个数,然后按照插入排序的算法进行计算即可。想法很美好,但是结果却不令人满意,我发现在该算法进行后排序的结果并没有改变。

当时脑子里第一个跳出来的想法是:函数的参数是否进行了拷贝,也就是函数里面操作的不是原数组。但是细下心来一想,这里自己传入的是一个指针,也就是内存的地址。而在函数中的操作对象则都是对地址解引用后的对象,所以不管这个地址是否发生了拷贝,函数的操作都会作用到最初的对象上,所以这个想法行不通。

既然一定会对原数组产生影响,那么函数中出现了错误的结果就只有一种情况了,那便是for循环没有被执行!于是我尝试着打印了一下size的数值,发现为1!问题果然出现在这儿。而对于一个数组A来说,下面语句用来求数组大小是没有问题的,因为数组的大小一定等于总的空间除以每一个元素所占的空间。size_t size = sizeof(A) / sizeof(*A);//求得数组大小
看到这儿我突然恍然大悟过来,既然*A代表的是数组的第一个元素(也正是这个原因,可以让我们用上述的式子来求解数组的大小),那么传入函数中的参数便只是该数组的第一个内存位置,即第一个元素的位置。为了验证这个想法,我在函数里打印了*A的内容,不出所料。
所以可以得到的结论是,在上面的函数中我自以为将整个数组都传给了函数,但实际上函数只获得了该数组的起始地址,所以才会出现错误,单纯的将数组作为参数传给函数,将丢失函数的大小信息。所以要让函数正常的工作还必须给出数组的size。改进后的函数是这样子的

#include<stddef.h>
/*
*插入排序,算法导论中的解释很好:可以将排序过程看做是摸牌,每次从桌面上拿最上面一张牌
*然后插入到左手里面,左手中的牌是已经排序好了的。那么将牌放到合适的位置即是与左右从右到左
*的每一张牌进行对比,直到找到一个合适的位置将牌插入。初始时候是手里只有一张牌,到桌面上的牌全部
*摸完的时候即是排序完成的时候
*/
template <class T> void insertionSort(T* A, size_t size){
for (int j = 1; j < size; j++){
T key = A[j];//从桌面上摸的第一张牌,即数组的第二个元素
size_t i = j - 1;//手里从左到右的最后一张牌
while (i>0 && A[i] > key){
A[i + 1] = A[i];//为该张牌找到合适的位置
--i;
}//此处避免了只有一个元素的情况,因为&&当i小于0时也不会出现A[-1]的情况
A[i + 1] = key;
}
} 这里增加了数组的size信息,在调用函数前计算好后作为参数传入。新版的函数经过测验能够正常的工作。
这其实是一个很小的问题,但是也暴露出来很多的细节,包括自己的功底不足等等,还需继续努力。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ 形参 数组 指针