数组是一个内存连续的整体,指针的值是另外一个变量的地址,两者的操作是有区别的。
数组名可以看作一个指针常量(但在sizeof的情况下是不成立的)
。可以查看以下例子进行比较:
// 定义
int array[10]; // 合法
int array[10] = {0, 1, 2}; // 合法
int *p; // 合法,编译通过,但是是野指针,注意赋值,否则运行时可能出错
int *p = NULL; // 合法
// 大小(32位机器)
sizeof(array); // 40
sizeof(p); // 4
// 转换
int *p = array; // 合法,数组名array就是个地址,等价于&array[0]
int *p = &array; // 非法,数组名array就是个地址
int *p = array + 1; // 合法,得到的是&array[1]
int *p = (int*)(&array + 1);// 合法,偏移整个数组,指向数组尾部的下个单元,要小心操作
p = array; // 合法,p是用来存放地址,数组名就是该数组的起始地址
array = p; // 非法,数组地址不可以改变
p = &array[0]; // 合法,array[0]存放的是值不是地址,所以p是要取址
*p = array[0]; // 合法,*p是存放值,可以直接赋值
// 赋值
p[1] = 1; // 合法,指针可以类似数组一样使用,前提是指针p所指向的地址是分配内存了的
array[1] = 1; // 合法,基本用法
*p = 2; // 合法,基本用法
*array = 2; // 合法,既然数组名是地址,那么加上*就可以装值,等价于array[0] = 2;
// 偏移
p++; // 合法,指针指向下一个地址
array++; // 非法,数组地址不可以改变
*p++ = 1; // 合法,给p指向的地址赋值,注意优先级: ++ 高于 *
*(array++) = 1; // 非法,数组地址不可以改变
(*p)++; // 合法,指针指向地址的值加1
(*array)++; // 合法,数组名是地址,等价于array[0]++;
*(p + 1) = 2; // 合法,给p指向的下一个地址赋值,前提是指针p所指向的地址是分配内存了的
*(array + 1) = 2; // 合法,数组名是地址,只要不修改array本身的值(地址)即可
定义字符串
char str[] = "Hello";
char *p = "Hello";
str[1] = 'E';
p[1] = 'E'; // 存储在常量区(只读),编译时不会报错,运行时出错
函数传参
数组和指针作为函数形参时,作用都是传递一个地址,而不是拷贝一个数组进去,所以参数可以写成a[]或*a,因为都只是传递一个地址。而数组作为形参传递进去之后是可以进行a++的,这个和数组变量不一样,另外,不能对传进来的参数进行sizeof计算字符串长度,因为传递进来的是一个地址。
也只有在作为函数形参时,一级指针和一维数组是完全等价的,二级指针和二维数组可就不一样了。
例如:
// 32位机器上运行
int test(char arr[100], char *p)
{
printf("size: %d\n", sizeof(arr)); // 一直都是4,传的是地址
printf("size: %d\n", sizeof(p));
}
版权声明:本文为weixin_44498318原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。