一、数组名的运算与指针并不是完全相同。
这是最明显的例子,指针支持自增、自减运算,但是数组名并不支持自增、自减运算。其实这么做的原因也很简单,由于数组是一片连续的空间,需要一个类似于指针的东西指向这一片连续空间的首地址。由于在整个内存中对于某个个数组只有唯一的数组名,假如可以对数组名进行自增、自减运算,那么当我们下一次使用这个数组名时并不知道这个数组名是否是指向的该片连续内存的首地址,这时就会导致内存管理的混乱。因此严禁对数组名进行自增、自减操作。
二、把数组名当作参数传递给函数时数组名会退化成真正的指针。
考虑下面代码及其输出:
/*
* 输出:
* arr: 40
* ptr: 8
* ptr2: 8
* int*: 8
* func: 8
*/
#include <iostream>
using namespace std;
void func(int arrCpy[]) {
printf("func: %lu\n",sizeof(arrCpy));
}
int main() {
int arr[10];
int (*ptr)[10] = &arr;
int *ptr2 = arr;
printf("arr: %lu\n",sizeof(arr));
printf("ptr: %lu\n",sizeof(ptr));
printf("ptr2: %lu\n",sizeof(ptr2));
printf("int*: %lu\n",sizeof(int*));
func(arr);
return 0;
}
我们来逐行分析:
1、对于sizeof(arr),如果arr真的是一个指针,那么sizeof的输出应该是指针长度8(我的电脑是mac,长度由sizeof(int*)得出),而并不是整个数组的长度40。
2、对于ptr和ptr2来说,ptr是一个指针数组,ptr2是一个普通的int指针。对于&arr这个语句,编译器会自动将它转换为&arr[0]来获取 第一个元素的首地址。如果在并未对ptr和ptr2进行操作之前进行打印,你会发现数组指针的值竟然就是首个元素的地址!貌似ptr与ptr2没有任何区别啊???
//输出:
//ptr address: efbff5a0
//ptr2 address: efbff5a0
printf("ptr address: %x\n",ptr+1);
printf("ptr2 address: %x\n",ptr2+1);
但是如果分别对ptr和ptr2加1之后再输出地址这个问题的答案就出来了~
//输出:
//ptr address: efbff5c8
//ptr2 address: efbff5a4
printf("ptr address: %x\n",ptr+1);
printf("ptr2 address: %x\n",ptr2+1);
读者可以自己算一下这两个16进制换成十进制相差多少。这里我算出来了,两者正好相差36!而整个数组的长度正好是40且一个单元的长度为4。所以我们得出结论:数组指针指向的是整个数组,在对数组指针进行+1操作后该指针会直接指向数组整个连续的内存看空间的下一个地址(也就是ptr越过了arr这个数组的所有的10个内存单元)。而ptr2就是一个普通的整形数组,+1只会指向下一个内存单元(arr[1])。
3、第三个例子是重中之重!函数里的sizeof(arrCpy)为什么输出的是指针长度不是数组长度???我明明是传入的数组啊!这是就是因为把数组名当作参数传递给函数时数组名会退化成真正的指针!所以这牵扯出来了一个与memeset函数有关的问题:
//输出:
//-1 -1 0 0 0 0 0 0 -272632344 32766
void init(int* arrCpy) {
memset(arrCpy, -1, sizeof(arrCpy));
for(int i = 0; i< 10;++i) {
cout << arrCpy[i] << endl;
}
}
为啥只用前两个元素初始化成功了??原因很简单,当数组名退化为指针后,长度与一个int型指针长度一致,为8个字节。而一个int正好是4个字节且该数组存储的元素全部为int型。因此4*2=8只有前两个元素被=初始化了。
一般来说,并不建议传参进行memset初始化,因为如果是新手的话这些问题根本发现不了会产生迷之的错误。如果非要在函数中使用memset初始化数组,那么memset的最后一项一定要写为sizeof(type)*num的形式:
//输出:
//-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
void init(int* arrCpy) {
memset(arrCpy, -1, sizeof(int)*10);
for(int i = 0; i< 10;++i) {
cout << arrCpy[i] << endl;
}
}
只有这样才能成功的对数组进行初始化。