指向字符串的一维指针数组,char* pea[10]
- 上述声明,pea是一个具有10个元素的数组,每个元素的类型是一个指向字符(或者字符串)的指针,从声明中无法得知是单个字符还是字符串
- 用于实现多维数组的指针数组有很多名字,如“Iliffe向量”、“display”或“dope向量”
- 这种数组必须用指向为字符串而分配的内存的指针进行初始化,可以在编译时用一个常量初始值,也可以在运行时动态malloc初始化,for循环为每一个元素malloc可以,直接为整个数组malloc也可以,只不过后者还需要使用一个循环来用指针指向这块内存的各个区域。前者的好处是可以逐个释放内存,后者的优点是内存是连续的
squash[i][j]
- 当你看到squash[i][j]时,不知道squash是怎样声明的,和函数内部不知道传入的变量是数组还是指针一样,都是因为左值的数组名被编译器当作指针
int squash[23][12];//数组
int *squash[23];//Iliffe向量
int **squash;//2级指针
int (*squash)[12];//指针,指向int[12]
- 尽管都写作squash[i][j],但是在不同的情况下访问的实际类型是不同的。
- quash[i][j]被编译器翻译为*(*(quash+i)+j),访问方式很不相同,如下:
Iliffe向量,在锯齿状数组上使用指针
- char carrot[50][256];虽然不是每次都会用到256个字符,但是最大长度是256,所以很大一部分空间被浪费了
- char* carrot[50];每个数组元素指向的长度不一,节省了内存
- 初始化锯齿状数组有两种方式,共享字符串,或者拷贝字符串
char *turnip[UMPTEEN];
char my_string[]="your message here";
//共享
turnip[i] = &my_string[0];
//拷贝
turnip[j] = malloc(strlen(my_string)+1);
strcpy(turnip[j],my_string);
- 尽量不要选择拷贝整个字符串的方法,缺点是空间耗费,而且可能使得字符串分配在内存的不同页面中,影响性能
数组和指针参数的匹配
数组名被改写成指针的规则不是递归定义的,数组的数组会被改写成数组的指针而不是指针的指针
实参 | 所匹配的形式参数 | ||
---|---|---|---|
数组的数组 | char c[8][10]; | char(*)[10] | 数组指针 |
指针数组 | char *C[15]; | char**c; | 指针的指针 |
数组指针 | char(*c)[64]; | char(*c)[64]; | 不改变 |
指针的指针 | char **c; | char**c; | 不改变 |
因此main函数的入参argv**和argv*[]都是合法的
下面列举了所有有效的代码组合:
void my_func1(int fruit[2][3][5]);
void my_func2(int fruit[][3][5]);
void my_func3(int (*fruit)[3][5]);
int apricot[2][3][5];
my_func1(apricot);
my_func2(apricot);
my_func3(apricot);
int (*p)[3][5] = apricot;
my_func1(p);
my_func2(p);
my_func3(p);
int (*q)[2][3][5] = &apriot;
my_func1(*q);
my_func2(*q);
my_func3(*q);
- 3个函数都接受同样类型的参数,就是一个[2][3][5]int型的三维数组或一个指向[3][5]int型二维数组的指针
- 3个变量apricot,p,*q都匹配所有3个函数的参数声明
Reference
C专家编程