APP下载

深入浅出理解C语言指针与二维数组

2019-09-24黄宝贵禹中元

电脑知识与技术 2019年19期
关键词:数组张三指针

黄宝贵 禹中元

摘要:指针是C语言的特色,也是C语言的灵魂与精华,熟练使用指针可以提高编程效率。指针与数组具有密切的关系,使用指针访问数组可以优化程序代码,提高程序的执行效率。但是,由于二维数组结构复杂,初学者难以理解其中的概念,指针与二维数组之间的关系比较模糊,增加了使用指针访问二维数组元素的难度。该文结合生活中的示例深入浅出地解析指针与二维数组之间的关系,使用多种类型的指针访问二维数组,并指出其中的难点及容易混淆之处。

关键词:C语言;地址;指针;二维数组;元素访问

中图分类号:TP312     文献标识码:A

文章编号:1009-3044(2019)19-0082-03

Abstract: Pointers are the most important characteristic and regarded as the soul and the best feature of the C programming language. The efficiency of C programs is improved significantly if pointers are good used in them. Pointers and arrays are closely related and they usually lead to more compact and efficient code. However, it is difficult to the abecedarians to understand the concept of pointers and two dimensional arrays because of their complicated structure. The obscure relationship between the point and array increases the hardness of visiting the elements of array by using pointers. The relationship between the point and array is analyzed with a simple way in this paper. The elements of a two dimensional array can be visited by several different type pointers. Moreover, some key and easily confused problems are listed in this paper.

Key words: C programming language; address; pointer; two dimensional array; element visited

1 背景

教授我們C语言的老师曾经说过:没有真正掌握指针的使用,就不能说已经学好C语言!由此可见指针在C语言中的重要地位。事实上,指针是C语言最重要的特色,是C语言的精华。指针概念繁多,使用非常灵活,这也导致我们在初学C语言时难以掌握其概念及使用方法。指针与数组具有密切的关系,指针通常与数组放在一起讨论与学习[1]。任何使用数组下标访问的表达式都可以使用指针来代替。但是,由于二维数组结构相对复杂,加之指针的灵活多变性,用指针访问二维数组的元素有多种方法,是我们学习的难点。下面,结合我们体育课上同学们站队的情形,详细讨论用一级指针,二级指针,指向一维数组的指针及指针数组来访问二维数组元素的具体操作过程。

我们班有20名同学,每一位同学都有一个编号,用整数[i]表示,[i∈[0,19]]。我是体育委员,我的编号是0。站队时,每5位同学站成一排,一共站4排。因为数组下标从0开始计数,为了后续叙述方便,我们规定最前面一排称为第0排,往后分别是第1排,第2排,第3排。第0排的同学的编号从左到右分别是[0,1,2,3,4];第1排的同学的编号从左到右分别是[5,6,7,8,9];……,依次类推。每一排的第一位同学所在的位置称为这排同学站队的地址,其后的同学的地址由排头同学的地址决定。我是体育委员,我所站立的位置决定了我们班所有同学站队的地址。假设张三同学编号是13,他站在第2排第3个位置。那么,体育老师要想找到张三同学,该怎么做呢?

以上问题用二维数组建立一个如下数学模型。二维数组a[4][5],a[0][0]=0,a[0][1]=1,…,a[0][4]=4,a[1][0]=5,…,a[1][4]=9,…,a[2][3]=13,…,a[3][4]=19。数组a可用二维表1表示。事实上,根据数组在计算机内存中的表示方法,这20个元素在计算机内存中按先行后列的方式进行存储[2]。

2 用指向整型的指针访问

体育老师只知道我所站立的位置,他必须首先找到我的位置,因为我决定了全班同学所站队列的位置。然后,从我开始向左依次走过每一位同学,走过第0排的5位同学后再从第1排的排头开始依次走过5位同学,然后再从第2排的排头开始依次走过3位同学,这时体育老师就走到了张三同学的位置,找到了张三同学。这种情况下,体育老师每次只面对一个同学,体育老师每走一步只走过一位同学,而张三的前面有13位同学,体育老师需要走13步才能到达张三的位置。可以把体育老师理解为指向某位同学的指针(指针即地址[3],是同一概念的两种说法),老师每走过一位同学,该指针值加1。那么,值13又是怎么得到的呢?a[2][3]元素在第2行,第3列(再次注意到,从0开始计数)。它的前面还有2个整行(第0行和第1行),每行有5个元素。而张三所在的行上,a[2][3]之前还有3个元素。所以a[2][3]之前总共有2*5+3=13个元素。用C语言描述如下。其中,(1):表示代码的行标。下同。

(1):int *p;   //p是指向int型数据的指针

(2):p = &a[0][0];  //指针p赋值为a[0][0]的地址,即p指向元素a[0][0]

(3):p = p + (2*5+3);  //p指针右移13步,指向元素a[2][3]

(4):*p ;    //指针解引用,得到指针所指向的内容,即张三的编号13

事实上,第2行代码可以写成:p = a[0],但不可以写成 p = a。&a[0][0]表示元素a[0][0]的地址,即指向a[0][0]的指针。根据一维数组元素及指针的关系,如果把a[0][0]看作为b[0]的形式,则b就是a[0]。而b[0]的指针就是b+0,即b。所以,a[0][0]的指针可以理解为指针a[0]+0即a[0]。所以,第2行代码写成p = a[0]也是正确的。但是,如果p = a,则*p=*a,而*a=*(a+0)=a[0]。根据指针p的定义,*p应该是指针p所指向的内容,是个整数。但,a[0]不是整数,是指针。

3 用指向一维数组的指针访问

体育老师忽然发现,既然已经知道张三同学在第2排,那么不需要从第1个同学开始依次走过前13名同学。体育老师可以从第0排开始直接越过2排走到第2排的排头位置。在这种情况下,体育老师的“眼界”变宽,他一眼能看到一排同学,一排同学可看作是个一维数组。这样,体育老师每走一步就跨过一排同学。而张三在第2排中位于下标为3的位置。用C语言描述如下。

1):int (*p)[5]; //p是指向具有5个元素的一维数组的指针。

2):p = a;   //指针指向二维数组的首地址。

3):p = p + 2; //指针p指向第2行数组

4):(*p)[3];  // *p是p指向的内容,即一维数组,而下标为3的元素就是张三的编号

第2行代码不能写成:p = a[0]或者p=&a[0][0]。因为,如果p=a[0],则*p=*(a[0])。而*p是指向数组的指针,*(a[0])=*(a[0]+0)=a[0][0]是个整数。同理,p=&a[0][0]也是错的。

4 用二维数组名作为指针访问

体育老师生病,由我代替他上课。作为班级体育委员,我(数组名a)当然代表的是全部同学啦。我把同学们分成4个小组,每一排作为一个小组,队形不能乱!每一排可以看作一维数组。这样,我们班就可以看作4个一维数组了。每一排的排头同学直接向我负责,由排头同学帮我找到这一排中的其他同学。这样,可以把二维数组a折分为4个一维数组[4]。如图1所示。这4个一维数组的名字分别是a[0],a[1],a[2],a[3]。而一维数组的名字又代表数组的首地址,即a[0]是指向a[0][0]的指针。而且,a[0]+1,a[0]+2,a[0]+3和a[0]+4分别是指向元素a[0][1],a[0][2],a[0][3]和a[0][4]的指针。称它们为列指针。显然,a[0],a[1],a[2]和a[3]又是数组a的4个元素。数组名a是指向该数组的指针,而且a+1,a+2,a+3分别是指向元素a[1],a[2]和a[3]的指针。称它们为行指针。

5 用指针数组访问

体育老师不需要知道全班同学站队的位置,只需要知道每一排的排头位置,把这些位置记在心里,然后根据这些位置就可以找到每一排中的任意一位同学了。根据第4小节的分析,a[0],a[1],a[2]和a[3]是4个地址(指针),分别表示4行一维数组的地址。可以定义一个有4个元素的数组,每个元素值都是指针,用它存储a[0],a[1],a[2]和a[3]的值。这种数组称为指针数组。C语句序列如下。

(1):int *p[4]; //定义数组p,有4个元素,每个元素是指向int型的指针

(2):int i;  //定义int型变量

(3):for(i = 0; i < 4; i++) p[i] = a[i]; //把a[0],a[1],a[2]和a[3]的值存储到数组p中

(4):*(p[2]+3); //元素a[2][3],即张三

第3行的命令不能简写为p=a。因为,p是指针数组的名字,而数组名是常量,不能直接进行赋值运算。

6 结束语

指针的概念繁多,定义形式有多种,不同的定义形式表达不同的含义,有些定义形式相近但意义有很大的差别。如,int (*p)[5] (数组指针,p是指向一维数组的指针)、int *p[5] (指针数组,p是由5个元素组成的数组,每个元素是指向整型数据的指针),int (*p)(float x) (函数指针,p是指向函数的指针),int *p(float x) (返回指针值的函数,p是函数名)等。这些形似义异的定义使得指针的使用非常复杂,给初学者带来极大的困难。指针及二维数组的关系密切,二维数组元素的访问可以用指针完成。而且,有多种实现方法,每种方法在具体使用中有许多需要注意的问题,在学习的时候要注意其区别。

参考文献:

[1] Kernighan B W, Ritchie D M. The C Programming Language(C程序設计语言)[M]. 2版. 徐宝文, 李志, 译. 北京: 机械工业出版社, 2012.

[2] 张龙波. 浅析C指针和一维、二维数组之间的关系[J]. 电脑知识与技术, 2017, 13(28): 71-72.

[3] 张忆文. C语言指针教学难点透析[J]. 计算机教育, 2017(1): 155-156.

[4] 谭浩强. C程序设计[M]. 4版. 北京: 清华大学出版社, 2010.

[5] 段红义. C语言指针教学中常见错误分析[J]. 电脑知识与技术, 2017, 13(4): 77-78.

【通联编辑:谢媛媛】

猜你喜欢

数组张三指针
JAVA稀疏矩阵算法
试拳
JAVA玩转数学之二维数组排序
郊游
更高效用好 Excel的数组公式
为什么表的指针都按照顺时针方向转动
寻找勾股数组的历程
浅析C语言指针
失踪
失踪