指针数组和数组指针
1.前言
数组
- 数组有自己的特定类型,由元素类型和数组大小共同决定
- 数组名的值是指针常量,也是数组第一个元素的地址
- 当数组名作为sizeof操作符或单目操作符&的操作数时,不用指针常量表示
arrary[2]
等价于*(2 + (arrary))
等价于*(arrary + 2)
等价于2[arrary]
- 数组在个函数传参时会被弱化为指针
指针
- 指针本质上是一个变量
- 指针需要占用一定的内存空间(4个字节)
- 指针用于保存内存地址的值
- 只有当两个指针指向同一个数组中的元素,指针相减(只能加减)才有意义,为指针所指元素下表差,否则结果未定义
- 指针进行关系运算(
> < >= <=
)前提是指向同一个数组中的元素
数组与指针的异同
- 数组声明时编译器自动分配一片连续的内存空间
- 指针声明时只分配了用于容纳指针的4个字节的空间
- 在作为函数参数时,数组参数和指针参数等价
- 数组名在多数情况下可以看做常量指针,值不可改变
- 指针本质是变量,保存的值被看做内存中的地址
2.指针数组
说明:
- 指针数组是一个普通的数组
- 指针数组中的每一个元素为一个指针
- 指针数组的定义:
type* pArray[n];
type*
为数组中每个元素的类型pArray
为数组名- n 为数组大小
示例:
int lookup_keyword(const char* key, const char* table[], const int size) { /*定义常指针接收传过来的字符串,定义常指针数组接收main中的指针数组(在函数参数中数组会被弱化为指针), 定义常变量接收数组大小*/ /*第二个参数就相当于定义一个数组,数组中存放的是char*类型的数据*/ int ret = -1; //定义返回值 int i = 0; for(i = 0; i < size; ++i) { if(strcmp(key, table[i]) == 0) { //循环比较数组中的字符串是否匹配 ret = i; break; } } return ret; } //宏定义计算数组的大小 #define DIM(a) (sizeof(a)/sizeof(*a)) int main() { //定义一个指针数组,存放char*类型的数据(keyword还是一个数组) const char* keyword[] = { "do", "for", "if", "register", "return", "switch", "while", "case", "static" }; //调用函数测试 printf("%d\n", lookup_keyword("return", keyword, DIM(keyword))); printf("%d\n", lookup_keyword("main", keyword, DIM(keyword))); return 0; }
- 注:在理解中主要还是把指针数组的本质(本质是一个数组,不过里面存放的是指针类型的数据)搞清楚
3.数组指针
说明:
- 数组指针用于指向一个数组
- 数组名是数组首元素的起始地址,但不是数组的起始地址
- 可以通过取地址符&作用于数组名得到数组的起始地址
- 数组指针的定义:
ArrayType* pointer
- 也可以直接定义:
type (*pointer)[n]
(不推荐)
pointer
为数组指针变量名type
为指向数组的类型- n 为指向数组的大小
示例:
typedef int(INT)[5]; //定义int类型大小为5的数组类型(INT为类型名) typedef float(FLOAT)[10]; typedef char(CHAR)[9]; int main() { INT a1; //定义数组a1 float fArrary[10]; FLOAT *pf = &fArrary; //定义数组指针pf,指向fArrary的地址 CHAR cArrary; char(*pc)[9] = &cArrary; //直接定义数组指针pc,大小为9,指向cArrary的地址 char(*pcv)[4] = cArrary; /*直接定义数组指针pcv,大小为4,指向cArrary的地址(系统会出现warning) (原因数组指针pcv指向的应该是大小为4的数组)*/ int i = 0; printf("%d, %d\n", sizeof(INT), sizeof(a1)); //查看定义的类型有多大 for(i = 0; i < 10; ++i) { /*循环给pf指向的数组赋值*/ (*pf)[i] = i; } for(i = 0; i < 10; ++i) { /*循环打印fArrary数组中的值,应该和上面赋值的一样*/ printf("%f\n", fArrary[i]); } //打印cArrary的地址,pc+1应该是cArrary首地址向后9个字节的地址,pcv+1应该是cArrary首地址向后4个字节的地址 printf("%0x, %0x, %0x\n", &cArrary, pc+1, pcv+1); return 0; }
4.参考
- 《C和指针》