多维数组的本质
一维数组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个字节
得出结论:
多维数组名的本质是数组指针,步长为多维数组一维的长度
文章图片
多维数组做函数参数的技术推演
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’)
推荐阅读
- C语言进阶|【C语言进阶7——数组和指针的练习(1) - 学习sizeof 和 strlen,看完这一篇就够了】
- C语言进阶|【C语言进阶6——指针的进阶(3)-总结数组和指针】
- C语言进阶|【C语言进阶】从入门到入土(数据的存储)
- C语言进阶|【C语言进阶2——数据的存储(2)- 整形提升】
- C语言进阶|【C语言进阶1——数据的存储(1)】
- C语言进阶|C语言进阶(自定义类型)
- C语言进阶|【这些题我一拿到手就会】C指针和数组试题详解(上)
- C语言进阶|人人都看得懂的C语言进阶系列之数据存储
- C语言进阶|【详解C语言指针】我真的让C指针给我唱征服了~乌拉