💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
【76.1 二维数组指针的用途。】 前面章节讲了一维指针操作二维数组,本质是通过“类型强制转换”实现的,这种应用局限于某些特定的场合,毕竟一维有1个下标,二维有2个下标,一维和二维在队形感上是有明显差别的,强行用一维指针操作二维数组会破坏了代码原有的队形感,大多数的情况,还是用二维指针操作二维数组。 二维指针主要应用在两个方面,一方面是N个二维数组的“中转站”应用,另一方面是函数接口的应用。比如,当某项目有N个二维数组表格时,要通过某个变量来切换处理某个特定的表格,以便实现“N选一”的功能,此时,二维指针在这N个二维数组之间就起到中转站的作用。又,当某个函数接口想输入或者输出一个二维数组时,就必然要用到二维指针作为函数的接口参数。 【76.2 二维指针的“中转站”应用。】 举一个例子,有3个现有的二维数组,通过某个变量来选择切换,把某个二维数组的数据复制到指定的一个缓存数组中。 code unsigned char table\_1\[3\]\[3\]= //第1个现有的二维数组 { {0x00,0x01,0x02}, {0x10,0x11,0x12}, {0x20,0x21,0x22}, }; code unsigned char table\_2\[3\]\[3\]= //第2个现有的二维数组 { {0xA0,0xA1,0xA2}, {0xB0,0xB1,0xB2}, {0xC0,0xC1,0xC2}, }; code unsigned char table\_3\[3\]\[3\]= //第3个现有的二维数组 { {0xD0,0xD1,0xD2}, {0xE0,0xE1,0xE2}, {0xF0,0xF1,0xF2}, }; unsigned char SaveBuffer\[3\]\[3\]; //指定的一个缓存数组 unsigned char TableSec; //选择变量 const unsigned char (\*pTable)\[3\]; //“中转站”的二维指针 unsigned char R,L; //复制数据时用到的for循环变量 void main() { TableSec=2; //选择第2个现有的二维数组 switch(TableSec) //根据选择变量来切换选择某个现有的二维数组 { case 1: //选择第1个现有二维数组 pTable=table\_1; //二维指针pTable在这里关联指定的数组,起到中转站的作用。 break; case 2: //选择第2个现有二维数组 pTable=table\_2; //二维指针pTable在这里关联指定的数组,起到中转站的作用。 break; case 3: //选择第3个现有二维数组 pTable=table\_2; //二维指针pTable在这里关联指定的数组,起到中转站的作用。 break; } //通过二维指针pTable来复制数据到指定的缓存数组SaveBuffer for(R=0;R<3;R++) //行循环 { for(L=0;L<3;L++) //列循环 { SaveBuffer\[R\]\[L\]=pTable\[R\]\[L\]; //这里能看到,二维指针维护了二维数组的队形感 } } while(1) { } } 【76.3 二维指针在“函数接口”中的应用。】 把上述例子“复制过程”的代码封装成一个函数,实现的功能还是一样,有3个现有的二维数组,通过某个变量来选择切换,把某个二维数组的数据复制到指定的一个缓存数组中。 //函数声明 void CopyBuffer(const unsigned char (\*pTable)\[3\],unsigned char (\*pSaveBuffer)\[3\]); code unsigned char table\_1\[3\]\[3\]= //第1个现有的二维数组 { {0x00,0x01,0x02}, {0x10,0x11,0x12}, {0x20,0x21,0x22}, }; code unsigned char table\_2\[3\]\[3\]= //第2个现有的二维数组 { {0xA0,0xA1,0xA2}, {0xB0,0xB1,0xB2}, {0xC0,0xC1,0xC2}, }; code unsigned char table\_3\[3\]\[3\]= //第3个现有的二维数组 { {0xD0,0xD1,0xD2}, {0xE0,0xE1,0xE2}, {0xF0,0xF1,0xF2}, }; unsigned char SaveBuffer\[3\]\[3\]; //指定的一个缓存数组 unsigned char TableSec; //选择变量 //\*pTable是输入接口带const修饰,\*pSaveBuffer是输出结果的接口无const。 void CopyBuffer(const unsigned char (\*pTable)\[3\],unsigned char (\*pSaveBuffer)\[3\]) { unsigned char R,L; //复制数据时用到的for循环变量 for(R=0;R<3;R++) //行循环 { for(L=0;L<3;L++) //列循环 { pSaveBuffer\[R\]\[L\]=pTable\[R\]\[L\]; //这里能看到,二维指针维护了二维数组的队形感 } } } void main() { TableSec=2; //选择第2个现有的二维数组 switch(TableSec) //根据选择变量来切换选择某个现有的二维数组 { case 1: //选择第1个现有二维数组 CopyBuffer(table\_1,SaveBuffer); //二维指针在这里分别体现了输入和输出接口作用 break; case 2: //选择第2个现有二维数组 CopyBuffer(table\_2,SaveBuffer); //二维指针在这里分别体现了输入和输出接口作用 break; case 3: //选择第3个现有二维数组 CopyBuffer(table\_3,SaveBuffer); //二维指针在这里分别体现了输入和输出接口作用 break; } while(1) { } } 【76.4 二维指针“类型强制转换”的书写格式。】 unsigned char \*pu8,unsigned int \*pu16,unsigned int \*pu32这些指针的书写定义都是很有规则感的,相比之下,二维指针的定义显得缺乏规则感,比如定义的二维指针变量unsigned char (\*pTable)\[3\],不规则在哪?就在于二维指针的变量pTable嵌入到了括号中去,跟符号“\*”捆绑在一起,这时就会冒出一个问题,如果我要强制某个指针变量为二维指针怎么办?下面的例子已经给出了答案。 unsigned char table\[3\]\[3\]= //二维数组 { {0xD0,0xD1,0xD2}, {0xE0,0xE1,0xE2}, {0xF0,0xF1,0xF2}, }; unsigned char (\*pTable)\[3\]; void main() { pTable=(unsigned char (\*)\[3\])table; //这里,强制类型转换用unsigned char (\*)\[3\] } 总结:二维数组的强制类型转换用这种书写格式(unsigned char (\*)\[N\]),这里的N是代表实际项目中某数组的“列”数。 【76.5 例程练习和分析。】 现在编写一个练习程序。 /\*---C语言学习区域的开始。-----------------------------------------------\*/ void CopyBuffer(const unsigned char (\*pTable)\[3\],unsigned char (\*pSaveBuffer)\[3\]); code unsigned char table\_1\[3\]\[3\]= //第1个现有的二维数组 { {0x00,0x01,0x02}, {0x10,0x11,0x12}, {0x20,0x21,0x22}, }; code unsigned char table\_2\[3\]\[3\]= //第2个现有的二维数组 { {0xA0,0xA1,0xA2}, {0xB0,0xB1,0xB2}, {0xC0,0xC1,0xC2}, }; code unsigned char table\_3\[3\]\[3\]= //第3个现有的二维数组 { {0xD0,0xD1,0xD2}, {0xE0,0xE1,0xE2}, {0xF0,0xF1,0xF2}, }; unsigned char SaveBuffer\[3\]\[3\]; //指定的一个缓存数组 unsigned char TableSec; //选择变量 //\*pTable是输入接口带const修饰,\*pSaveBuffer是输出结果的接口无const。 void CopyBuffer(const unsigned char (\*pTable)\[3\],unsigned char (\*pSaveBuffer)\[3\]) { unsigned char R,L; //复制数据时用到的for循环变量 for(R=0;R<3;R++) //行循环 { for(L=0;L<3;L++) //列循环 { pSaveBuffer\[R\]\[L\]=pTable\[R\]\[L\]; //这里能看到,二维指针维护了二维数组的队形感 } } } void main() //主函数 { TableSec=2; //选择第2个现有的二维数组 switch(TableSec) //根据选择变量来切换选择某个现有的二维数组 { case 1: //选择第1个现有二维数组 CopyBuffer(table\_1,SaveBuffer); //二维指针在这里分别体现了输入和输出接口作用 break; case 2: //选择第2个现有二维数组 CopyBuffer(table\_2,SaveBuffer); //二维指针在这里分别体现了输入和输出接口作用 break; case 3: //选择第3个现有二维数组 CopyBuffer(table\_3,SaveBuffer); //二维指针在这里分别体现了输入和输出接口作用 break; } View(SaveBuffer\[0\]\[0\]); //在电脑端观察某个二维数组第0行数据第0个元素的内容 View(SaveBuffer\[0\]\[1\]); //在电脑端观察某个二维数组第0行数据第1个元素的内容 View(SaveBuffer\[0\]\[2\]); //在电脑端观察某个二维数组第0行数据第2个元素的内容 while(1) { } } /\*---C语言学习区域的结束。-----------------------------------------------\*/ 在电脑串口助手软件上观察到的程序执行现象如下: 开始... 第1个数 十进制:160 十六进制:A0 二进制:10100000 第2个数 十进制:161 十六进制:A1 二进制:10100001 第3个数 十进制:162 十六进制:A2 二进制:10100010 分析: SaveBuffer\[0\]\[0\]是十六进制的0xA0,提取了第2个二维数组的第0行第0个数据。 SaveBuffer\[0\]\[1\]是十六进制的0xA1,提取了第2个二维数组的第0行第1个数据。 SaveBuffer\[0\]\[2\]是十六进制的0xA2,提取了第2个二维数组的第0行第2个数据。 【76.6 如何在单片机上练习本章节C语言程序?】 直接复制前面章节中第十一节的模板程序,练习代码时只需要更改“C语言学习区域”的代码就可以了,其它部分的代码不要动。编译后,把程序下载进带串口的51学习板,通过电脑端的串口助手软件就可以观察到不同的变量数值,详细方法请看第十一节内容。