C语言指针教学中的知识点分析与总结C语言是一门重要的计算机基础课程,指针是C语言的精华。
而指针应用范围广、使用灵活等特点时常让初学者感到困惑。
用指针可以访问各种类型的数据,能够实现动态存储分配,提高编程效率,加深对数据存储方式的理解。
本文从指针的基本概念,指针在数组、函数、字符串、动态存储分配等方面的应用入手,剖析指针与各部分基础知识相结合时的教学重点和难点。
利用对比的方法指出初学者在学习指针过程中易混的概念及注意事项,有利于初学者对指针的理解和掌握。
1指针基本概念的理解指针学习首先应掌握其基本概念。
指针即地址、地址即指针。
程序运行过程中,变量、数组、函数等都存放在内存的存储单元中,每个存储单元都有地址。
使用变量、数组、函数既可以直接访问,又可以利用其存储单元地址进行间接访问,这种间接访问便是借助指针来完成的。
1.1对指针类型的理解理解指针概念要从指针类型入手,教师在教学中应着重讲述指针类型的含义,以及与普通变量类型的区别。
指针定义时的类型称为指针的基础类型,理解上应区别于普通变量的类型。
如定义:由上表可以看出,普通变量的数据类型决定了其占用内存单元的字节数以及存放数值的范围。
而指针变量不论其基础类型为何种类型,均占用4 个字节的存储空间。
并且指针变量与普通变量最大的区别在于,指针变量存地址值,而普通变量存数值。
1.2指针运算符的理解1.2.1对取地址符“ &”的理解指针变量定义后应为其赋一个有效地址值,让它指向有效的存储空间。
未赋值的指针变量称为“悬空”指针,使用悬空指针非常危险,可能会导致系统崩溃。
为指针变量赋值时常要用到取地址运算符“ &”。
令初学者常常感到困惑的是分不清赋值号左右两侧的数据类型是否匹配。
图1 所示为指针变量正确的赋值关系。
1.2.2对取内容符“ * ”的理解取内容符“ * ”又称间接运算符。
当指针指向某存储单元后,利用指针访问该存储单元的内容便要用到取内容符。
为帮助初学者更好的理解取内容符,在教学过程中应着重强调以下几个易混淆概念。
1)取内容符不是取指针变量自己的内容,而是取指针变量所指存储单元里的内容。
2)应区分取内容符和指针变量定义时的星号。
前者是一个运算符,后者仅仅是一个标志。
3)“取内容”运算与“取地址”运算互为反向运算。
取内容符“*”可以放在一级指针变量或者二级指针变量前面,但是不可以放在普通变量前面。
对于取内容运算有以下关系:* 二级指针一级地址* 一级指针数值1.2.3对指针加、减运算的理解对指针变量加减运算的学习应区别于普通变量的加减运算。
指针的加减运算是控制指针前移或后移,其移动的具体字节数由指针的基础类型决定。
如定义:char *p1;int *p2;double *p3;则p 1++、p2++、p3++均表示二个指针向后移动了一个单兀。
但由于p1、p2、p3的基础类型不同,决定了它们移动的字节数有所区别,p1 指针后移了1 个字节,p2 指针后移了4 个字节,p3 指针后移了8 个字节。
2指针与数组的关系及应用由于数组兀素在内存中连续存放,因此利用指针对数组操作是非常方便的,只需控制指针前移或者后移便可以指向不同的数组兀素。
2.1指针与一维数组指针与数组这部分学习的难点在于:1)如何表示数组中某个3)如何使用兀素的地址;2)如何将指针指向数组中的指定兀素;下标法”或“指针法”引用数组兀素。
引用一维数组兀素及其地址的方法有以下两种――“下标法”和“指针法” [1]。
如表2 、表3所示。
在教学中,应注意比较这两种方法。
如定义:int a[4]={1,2,3,4}, *p = a;则a 和p 中均存放了数组首地址。
因此对数组元素或者元素地址的引用便可以借助a 或者p 来完成。
1) “下标法”。
初学者可仔细比较以上两个表格中的内容,并加深对“下标法”和“指针法”的理解。
3) 注意区分以下几种表达式的含义。
利用指针操作数组,常常需要对指针作加减运算,以控制指针指向不同的数组元素。
表4 给出几种容易混淆的表达式。
初学者应注意比较每种表达式是对指针作自增运算,还是对指针所指向的内容作自增运算。
假设有定义:int a[5]={1,2,3,4,5};*p=a;表4 几种易混表达式的比较表达式第1 步运算第2 步运算等价表达式*(++p) 指针p 自增1,向后移动指向a[1] 取出p 当前所指a[1] 中的数值“ 2” *++p*(p++) 取出p 当前所指a[0] 中的数值1”指针p自增1,向后移动指向a[1] *p++++(*p) 取出p 当前所指a[0] 中的数值1”对取出的数值作自增运算得到“ 2” ++*p(*p)++ 取出p 当前所指a[0] 中的数值1”对取出的数值作自增运算得到“ 2”2.2指针与二维数组2.2.1二维数组中指针的类型C语言将二维数组名定义为一个行指针常量,行指针是指基础类型为一行元素的指针。
例如有定义:int (*P)[4]; ,表示定义了一个行指针变量P,该指针变量的基础类型为4个int型。
行指针相当于二级指针。
对二维数组元素的引用与一维数组类似,既可以使用“下标法”,也可以使用“指针法”。
如定义:int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};则引用该数组第i 行第j 列元素的方法有以下几种:方法一:a[i][j] 方法二:*(a[i]+j)方法三:*(*(a+i)+j) 方法四:(*(a+i))[j]为了帮助初学者深刻理解并灵活使用以上各种方法引用二维数组元素,首先应建立起二级指针、一级指针、数组元素这三者之间的关系。
如定义:int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};该数组中各元素在内存的存放形式,以及各行地址、元素地址如图3所示。
图3中的a+0、a+1、a+2代表各行元素的行地址,相当于级指针。
而a[0]+0 、a[0]+1 、a[0]+2 、a[0]+3 代表第1行中4个元素的地址,相当于一级指针。
由于二维数组名a 是一个行指针常量,相当于二级指针。
据公式:“二级指针+整数二级指针”,可知“ a+i”二级指针,代表二维数组中第i 行元素的地址。
根据“二级指针取内容降级为一级指针”的关系,可知“a[0] ”等价于“ *a”,相当于一级指针,代表二维数组中第行第1 个元素的地址。
根据公式:“一级指针+整数级指针”,可知“ a[0]+j ”是一级指针,代表该行中第j 列元素的地址。
理解了二级指针、一级指针的表示方法后,便可以利用“下标法”及“指针法”引用二维数组元素,如表 5 所示。
表5 二维数组元素引用的各种方法根据以上分析可知,二维数组每行元素的地址称为行指针,相当于一个二级指针。
因此可以定义一个行指针变量指向二维数组,然后借助该指针变量对二维数组元素进行引用。
例如,有定义:int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};int (*p)[4];定义了一个行指针变量P,其基础类型为4个int型数据,与行指针常量a同类型。
因此可以通过赋值语句“P = a; ”将二维数组第一行的行地址赋值给P。
图4表示行指针与二维数组的指向关系。
图4 所示,行指针变量P 指向二维数组的第一行,“ P+1”指向第二行,“ P+2”指向第三行,于是利用P 引用二维数组元素的方法见表 6。
维数组元素, 定义行指针变量时, 方括号内的常量值应与二维数 组的列长度相等。
2.2.3 指针数组与二维数组二维数组可以看作是由若干个一维数组构成的。
而每一个一 维数组可以由一个与之同类型的一级指针变量进行操作。
因此, 如果定义若干个一级指针变量并让它们分别指向二维数组的各行元素,则对二维数组元素的引用就可以借助这些一级指针变量 来完成。
这些一级指针变量组合在一起便构成了指针数组 例如有定义:int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};int *q[3];指针数组 q 中包含了三个 int 型的指针变量 q[0] 、 q[1] 、 可以通过以下语句将这三个指针变量分别指向二维数组各行的 第一个元素。
初学者应仔细比较行指针与指针数组的特点, 并体会利用它 们操作二维数组时的区别。
3 指针与字符串的关系及应用3.1 指针与单个字符串在教学中 , 应特别强调, 为保证行指针变量能够正确引用二[2] 。
定义了一个指针数组q ,由于二维数组a 有三行元素,因此q[2] ,字符串是连续存放在计算机内存中的若干个字符序列,因而使用指针操作字符串是非常方便的,并且不会造成内存空间的浪费。
初学者学习字符串这部分时,时常感到困惑的是分不清“字符数组”与“字符型指针”在字符串应用中的区别。
以下我们从几个角度帮助初学者理解两者的区别。
1) 从“变量定义并初始化”的角度区分。
char a[10] = "abc"; // 正确的数组定义和初始化char *P = "abc"; // 正确的指针定义和初始化以上是正确的定义语句,定义了一个字符数组a 和一个字符指针变量P,并对它们初始化字符串,二者的区别如表8 所示。
以上赋值语句a="abc"; 错误的原因是,赋值号左侧只能是变量名,而数组名a 是一个地址常量,常量是不能被赋值的。
语句P="abc"; 正确,因为P 是变量,该语句表示将字符串常量"abc" 在内存中的起始地址赋值给指针变量P。
3) 从“输入字符串”的角度区分。
char a[10], *P;gets(a); // 正确的用法gets(P); // 错误的用法gets( ) 函数的功能是从键盘读取一个字符串,并放到一个有效的存储空间里。
“gets(P); ”错误的原因是,指针P 此时是悬空”指针,还未指向任何有效的存储空间。
3.2指针与字符串数组单个字符串可以由一维字符数组或字符指针来操作,同理,字符串数组便可以由二维字符数组或指针数组来操作。
以下对这两种方法进行比较,以帮助初学者理解并掌握“二维数组构造字符串数组”和“指针数组构造字符串数组”的原理及区别。
假设有定义:char a[3][10] = {"China", "America", "Russia"};char *p[3] = {"China", "America", "Russia"};以上定义了二维数组a 构造字符串数组,系统为二维数组a开辟了30 个字节的连续存储空间,向其中存放了三个字符串。