c语言进阶——多维数组本质及指针数组的应用分析

多维数组的本质
一维数组int a[10]在做函数参数时会退化为指针int *a,但是二维指针做函数参数时却不能写成二级指针,那么二维数组的本质到底是什么,可以通过代码来验证。

int a[3][5], i=0, j=0; //定义一个3*5的二维数组 int tmp = 1; for (i=0; i<3; i++) { for (j=0; j<5; j++) { a[i][j] = tmp++; } } printf("a %d , a+1:%d ", a, a+1); //输出数组首元素地址和步长 printf("&a %d , &a+1:%d ", &a, &a+1); //输出数组地址和步长 //输出结果 //数组首元素地址与数组地址相同 //a的步长为20个字节,&a的步长为15*4 = 60个字节

得出结论:
多维数组名的本质是数组指针,步长为多维数组一维的长度
c语言进阶——多维数组本质及指针数组的应用分析
文章图片

多维数组做函数参数的技术推演
1、C语言中只会以机械式的值拷贝的方式传递参数(实参把值传给形参)
int fun(char a[20]) { printf("%d",sizeof(a)); } //输出结果为4字节(32位)

原因1:高效
原因2:C语言处理a[n]的时候,它没有办法知道n是几,数组发生了退化,变为了指针。
2、二维数组的退化问题
二维数组可以看做一维数组的数组,因此二维数组中的第一维可以省略。
void f(int a[5]) ====》void f(int a[]); ===》 void f(int* a);
void g(int a[3][3])====》 void g(int a[][3]); ====》 void g(int (*a)[3]);
3、数组与指针的等价关系
数组参数等效的指针参数一维数组 char a[30]指针 char* 指针数组 char *a[30]指针的指针 char **a 二维数组 char a[10][30]数组的指针 char(*a)[30]

指针数组的应用场景
在实际的应用开发中,指针数组主要有菜单和命令行两种应用场景
【c语言进阶——多维数组本质及指针数组的应用分析】1、菜单应用
//求关键字在表中的位置 //一个入口 多个出口 int searcheKeyTable(const char* table[], const int size, const char* key, int *pos) { int rv = 0; int i = 0; int inum = 0; if (table==NULL || key==NULL || pos==NULL) { rv = -1; printf("func searcheKeyTable:%d", rv); return rv; }//间接的证明数组做函数参数的回退 //这里inum的值为1,因为数组会发生回退,编译器并不知道n是多少,当做char **table来看,属于指针类型四个字节 inum = (sizeof(table)/sizeof(*table)); for(i=0; iif( strcmp(key, table[i]) == 0 ) { *pos = i; //break; return rv; } }//没有找到返回-1 if (i == size) { *pos = -1; } return rv; }#define DIM(a) (sizeof(a)/sizeof(*a))int main() { int inum = 0; int pos = 0; int a[10]; int i = 0; //指针数组 char*c_keyword[] = { "while", "case", "static", "do" }; searcheKeyTable( c_keyword, DIM(c_keyword),"do", &pos); //宏定义部分展开为 sizeof(c_keyword)/sizeof(*c_keyword),计算的是指针数组的长度 //*c_keyword等价于c_keyword[0]表达式为4*4/4 = 4 printf("pos:%d\n", pos); searcheKeyTable( c_keyword, DIM(c_keyword), "static", &pos); printf("pos:%d\n", pos); system("pause"); return ; }

2、main函数命令行应用
我们经常发现在main函数中会存在int argc, char* argv[]这样的函数参数,那么这些函数参数时从哪里传递并分配内存的吗,答案是操作系统。如果我们使用命令行工具来运行程序,就可以传入这些参数。
int main(int argc, char* argv[], char**env) { int i = 0; printf("******************* Begin argv *******************\n"); for(i=0; iprintf("%s\n", argv[i]); } printf("******************* End argv *******************\n"); printf("******************* Begin env *******************\n"); for(i=0; env[i]!=NULL; i++)//为什么可以正常运行? { printf("%s\n", env[i]); }printf("******************* End env*******************\n"); }

这里并没有传入env的个数,但是循环依然不会发生中断,原因是main函数会自动在字符数组后面自动加上结束标志(NULL 0 ‘\0’)

    推荐阅读