C语法陷阱:C语言的二维数组模拟
2009-08-02 00:00
906 查看
从前面的讨论中,我们不难得出一个推论,*a即数组a中下标为0的元素的引用。例如,我们可以这样写:
这个语句将数组a中下标为0的元素的值设置为84.同样道理,*(a+1)数组a中下标为1的的元素的引用,以此类推,概而言之,*(a+i)即数组中下标为i的元素的引用,这种写法是如此常用,因此被简记为a[i].
正是这一概念让C语言新手难于理解,实际上,由于a+i与i+a的含义一样,因此a[i]和i[a]也具有同样的含义。也许某些汇编语言程序员会发现后一种写法很熟悉,但我们绝对不推荐这种写法。
现在我们可以考虑二维数组了,正如前面所讨论的,它实际上是以数组为元素的数组,尽管我们也可以完全依据指针编写操纵一维数组的程序,这样做在一维情形下并不困难,但是对于二维数组从记法上的便利性来说采用下述形式就几乎是不可替代了。还有,如果我们仅仅使用指针来操纵二维数组,我们将不得不与C语言中最为“晦暗不明”的部分打交道,并常常遭遇到潜伏着的编译器bug。
让我们回过头来再看前面的几个声明:
然后考一考自己,calendar[4]的含义是什么?
因为calendar是一个有着12个数组类型元素的数组,它的每个数组类型元素又是一个有着31个整型数组,所以calendar[4]是 calendar数组的第五个元素,是calendar数组中12个有着31个整型元素的数组之一,因此calendar[4]的行为也就表现一个有着31个整形元素的数组的行为,例如sizeof(calendar[4])的结果是31与sizeof(int)的乘积。
这个语句使指针p指向了数组calendar[4]中下标为0的元素。如果calendar[4]是一个数组,我们当然可以通过下标的形式来指定这个数组中的元素,就像下面这样:
我们确实也可以这样做。还是与前面类似的道理,这个语句可以写成下面这样而表达式的意思保持不变:
这个语句还可以进一步写成:
从这里我们不难发现,用方括号的下标形式很明显地要比指针来表达简便得多。下面我们再看:
这个语句是非法的,因为calendar是一个二维数组,即数组的数组,在此处的上下文中使用calendar名称会将其转化为一个指向数组的指针,而p是一个指向整型变量的指针,这个语句试图将一个类型的指针赋值给另一种类型的指针,所以是非法的。
很显然,我们需要一种声明指向数组的指针的方法,经过了前面对类似问题不厌其烦的讨论,构造出下面的语句应该不需要废多大力气:
这个语句的效果是,声明了*ap是一个拥有三十一个整型元素的数组ap就是一个指向这样的数组的指针,因而我们可以这样写:
这样,monthp将指向数组calendar的第一个元素,也就是数组calendar的12个有着31个元素的数组类型元素之一。
假定在新的一年开始时,我们需要清空calendar数组,用下标形式可以很容易做到:
*a=84;
这个语句将数组a中下标为0的元素的值设置为84.同样道理,*(a+1)数组a中下标为1的的元素的引用,以此类推,概而言之,*(a+i)即数组中下标为i的元素的引用,这种写法是如此常用,因此被简记为a[i].
正是这一概念让C语言新手难于理解,实际上,由于a+i与i+a的含义一样,因此a[i]和i[a]也具有同样的含义。也许某些汇编语言程序员会发现后一种写法很熟悉,但我们绝对不推荐这种写法。
现在我们可以考虑二维数组了,正如前面所讨论的,它实际上是以数组为元素的数组,尽管我们也可以完全依据指针编写操纵一维数组的程序,这样做在一维情形下并不困难,但是对于二维数组从记法上的便利性来说采用下述形式就几乎是不可替代了。还有,如果我们仅仅使用指针来操纵二维数组,我们将不得不与C语言中最为“晦暗不明”的部分打交道,并常常遭遇到潜伏着的编译器bug。
让我们回过头来再看前面的几个声明:
int calendar[12][31]; int *p int i;
然后考一考自己,calendar[4]的含义是什么?
因为calendar是一个有着12个数组类型元素的数组,它的每个数组类型元素又是一个有着31个整型数组,所以calendar[4]是 calendar数组的第五个元素,是calendar数组中12个有着31个整型元素的数组之一,因此calendar[4]的行为也就表现一个有着31个整形元素的数组的行为,例如sizeof(calendar[4])的结果是31与sizeof(int)的乘积。
p=calendar[4];
这个语句使指针p指向了数组calendar[4]中下标为0的元素。如果calendar[4]是一个数组,我们当然可以通过下标的形式来指定这个数组中的元素,就像下面这样:
i = calendar[4][7];
我们确实也可以这样做。还是与前面类似的道理,这个语句可以写成下面这样而表达式的意思保持不变:
i = *(calendar[4]+7);
这个语句还可以进一步写成:
i = *(*(calendar+4)+7);
从这里我们不难发现,用方括号的下标形式很明显地要比指针来表达简便得多。下面我们再看:
p = calendar;
这个语句是非法的,因为calendar是一个二维数组,即数组的数组,在此处的上下文中使用calendar名称会将其转化为一个指向数组的指针,而p是一个指向整型变量的指针,这个语句试图将一个类型的指针赋值给另一种类型的指针,所以是非法的。
很显然,我们需要一种声明指向数组的指针的方法,经过了前面对类似问题不厌其烦的讨论,构造出下面的语句应该不需要废多大力气:
int (*ap)[31];
这个语句的效果是,声明了*ap是一个拥有三十一个整型元素的数组ap就是一个指向这样的数组的指针,因而我们可以这样写:
int(*monthp)[31]; Monthp = calendar;
这样,monthp将指向数组calendar的第一个元素,也就是数组calendar的12个有着31个元素的数组类型元素之一。
假定在新的一年开始时,我们需要清空calendar数组,用下标形式可以很容易做到:
int month; for(month=0;month 上面的代码段如果才用指针应该如何表示呢?我们很容易地把 calendar[month][day]=0; 表示为*(*(calendar+month)+day)=0; 但是真正有关的部分是哪些呢? 如果指针monthp指向一个拥有31个整型元素的数组,而calendar的元素也是一个拥有31个整型元素的数组,因此就像是在其他情况中我们可以使用一个指针遍历一个数组一样,这里我们同样可以使用指针monthp以步进的方式遍历数组calendar:int (*monthp)[31]; for(monthp=calendar;monthp 到目前为止,我们一路行来几乎是“如履薄冰”,而且已经走得很远,在我们跌跤之前,最好趁早悬崖勒马。尽管本节中最后一个例子是合法的ANSI C程序,但是作者还有找到一个能够让该程序顺利通过编译的编译器(译注:现在大多数的c编译器能够接受上面例子中的代码)。上面例子的讨论虽然有些偏离本书的主题,但是这个例子能够很好地揭示出C语言中数组与指针之间的独特的关系,从而更清楚明白地阐述这两个概念。延伸阅读
此文章所在专题列表如下: C语法陷阱:从变量与函数的声明到类型转换符 C语法陷阱:理解(*(void(*)())0)() C语法陷阱:理解如何声明一个数组 C语法陷阱:指针与数组 C语法陷阱:C语言的二维数组模拟 本文地址:https://www.geek-share.com/detail/2460142401.html,欢迎访问原出处。
相关文章推荐
- C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com
- c语言语法陷阱总结
- C语言数组入门之数组的声明与二维数组的模拟
- [语法]C语言中二维数组做输入参数
- C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com
- C语言指针系列 - 一级指针.一维数组,二级指针,二维数组,指针数组,数组指针,函数指针,指针函数
- 【面试题】C语言:模拟实现memcmp,试比较memcmp与strcmp,strncmp的区别
- C语法陷阱:理解(*(void(*)())0)()
- 二维数组作为函数参数传递剖析(C语言)(6.19更新第5种)
- 神奇的C语言九:sizeof埋下的陷阱
- C语言~模拟实现通用冒泡排序
- 【C语言简单说】十九:二维数组循环嵌套(2)
- 用Linux_C语言模拟CP命令,实现文件和文件夹的拷贝
- C语言(思维陷阱)
- JNA—模拟C语言结构体
- C陷阱与缺陷之语法陷阱
- C语言博客作业一二维数组
- C语言博客作业--一二维数组
- 【C语言】 动态开辟二维数组
- C语言博客作业--一二维数组