APP下载

开门见山与循序渐进:一种C语言指针教学方法

2017-05-12赵帅锋胡绍海

计算机教育 2017年4期
关键词:教學指针C语言

赵帅锋+胡绍海

(北京交通大学 计算机与信息技术学院,北京 100044)

摘 要:指针是C语言教学中的难点和重点,作者提出一种指针教学方法,即把指针的内容贯穿于C语言的整个教学过程中:在第一次课中会介绍存储器和地址的概念,在随后的教学中,从存储器和地址的角度解释所学内容,在指针教学章节重点介绍指针用法。

关键词: C语言;C程序设计;指针;教學

1 背 景

指针是C语言的精髓和灵魂,是C语言中最具魅力和最富活力的部分,C语言通过指针来实现访问硬件资源、动态分配和回收内存空间、降低函数调用中参数传递的开销、减少使用全局变量、实现函数回调等功能。没有指针的C语言不可能进行任何有实际意义的编程。

指针也是C语言中最危险的部分,程序会因指针使用不当而潜藏风险,轻则导致程序退出,重则导致系统内存泄漏,甚至系统崩溃。

使用C语言编程离不开指针,但掌握和熟练使用指针却很难,对初学者尤其如此。指针是C语言教学中的难点和重点,很多教师在教学中尝试了多种方法[1-5],取得了不错的效果。作者经过多年C语言教学实践,逐渐摸索出“开门见山”与“循序渐进”相结合的指针教学方法,把指针教学融合在C语言教学的全过程中。“开门见山”是在课程开始,通过介绍计算机体系架构和程序运行过程,引入存储器及地址概念,尽早引入指针;“循序渐进”是在之后课堂教学内容的设计中,不断介绍和强化存储器的概念,加强学生对地址的认识。在正式介绍指针教学内容前,这种教学方法使学生已经建立并熟悉指针概念,对掌握和使用指针编程很有帮助。

2 指针学习困难的原因

学生在指针学习时,普遍感觉指针概念抽象,难以理解,影响学习、掌握和使用。主要原因在于如下3点。

(1)对学生而言,程序设计是一门全新类型的课程。其特点是知识点分散、逻辑性不强。编写代码既要符合语法规则,又要考虑逻辑关系,编码必须严格遵守语法规则:一个看上去微不足道的错误,比如语句漏写了分号,编译器会在其他没有错误的地方报告很多错误信息,这使初学者手足无措,无法排错;程序有了致命错误,比如变量没有初始化,但编译器只会轻描淡写地报个告警(warning),程序运行时,却时对时错。这些特征对于初学者都是陌生的,他们以往的学习方法和经验在面对该课程时几乎没有任何借鉴作用,这导致他们从课程开始就遇到很多困难。

(2)学生们不了解计算机。C语言是伴随着UNIX操作系统产生的,它的语言特性和计算机的构成紧密结合,甚至可以说,C语言是为对计算机了如指掌的专家设计的。而大学中常把C语言课程安排为程序设计的常识教育,学生在学习C程序设计课程前,还没有学过计算机原理等课程,他们可能听说过CPU、内存等概念,但并不了解这些概念的确切含义,不了解程序运行的过程,这会导致指针概念更加抽象,难以理解、掌握并使用。

(3)学生们通常是在学习C语言遇到困难挫折的情况下,接触和学习指针的,这增加了他们的畏惧心理,影响指针内容的掌握。基于兴趣,在课程开始阶段他们专心听讲,努力编写和调试简单的程序,但随着变量、函数、数组等内容逐渐引入,程序结构越发复杂,程序设计需要同时考虑算法,这会使学生感觉到学习的压力和困难,特别是在编译程序时,排除一个小小的错误,都要耗费很长的时间,这严重影响他们的学习热情和信心。在这种情况下,指针被引入课程中,并且指针概念抽象,又和C中的变量、函数、数组、结构等联系紧密,这些都放大了指针的学习难度,影响学生的理解和掌握。

针对如上问题,作者逐渐探索并使用了“开门见山”与“循序渐进”相结合的教学方法。

3 开门见山

所谓开门见山,指在第一次课就介绍存储器和地址的概念。在介绍“Hello world”之后,即介绍计算机的结构、存储器和地址的概念,随后介绍“第二个程序”以加深这些概念的理解。

3.1 计算机结构与存储器

初学者通过“Hello world”了解了C语言的代码风格、集成开发环境和程序编译、链接、执行的过程,随后介绍计算机的“冯·诺依曼”结构,向学生说明程序在计算机内的运行过程。课堂主要介绍如下几个方面知识。

(1)计算机构成及程序运行的方法。如图1所示,其中外存储器指硬盘,操作系统、应用程序和数据都以文件形式保存在硬盘上,内存储器保存正在运行的程序和程序所要操作的数据,这些程序是由操作系统从硬盘上装入到内存储器的。CPU(运算器、控制器)用于运行程序,CPU从程序所在的存储器起始位置开始,依次读取指令并执行,直到程序结束。

(2)内存储器是由N个连续的存储单元组成的,每个单元可以存储8比特二进制数(称为一个字节);N称为内存容量。计算机为每个存储单元分配唯一的编号,从0开始编起,直到N-1,这个编号称为该存储单元的“地址”,CPU使用编号(地址)访问这些存储单元。

(3)内存储器中存储的既有代码,也有数据;构成程序的代码依次存储在内存储器中;程序要操作的数据也保存在内存储器中。

3.2 第二个程序

第二个程序展示计算机的计算功能,该程序引入了变量及数据类型概念,存储器和地址在程序代码中首次出现。代码如上图所示。

介绍程序强调如下几个方面的知识。

(1)计算机要计算两个整数的和,首先需要找两个地方来保存这两个整数,这两个地方就位于内存中;

(2)计算机在内存中为不同类型的数据分配大小不同的存储空间,“int a,b,r;”要求计算机分配三块内存空间,分别用变量“a,b,r”表示,每块内存空间存储一个整数,变量的值改变,表示其所代表的存储空间存储的内容发生了改变。

(3)scanf(“%d, %d”, &a, &b)表示从标准输入设备(键盘)上接收用户输入的两个整数,这两个整数分别保存在“a,b”所代表的内存中,内存用地址表示,“&a,&b”分别表示取“a,b”的地址,“%d”表示每个空间要保存的数的数据类型为整数,这确定了每个空间占据的字节个数。

(4)scanf()实现的功能是通过很多条计算机代码实现的,这些代码在程序被装入内存时,也被装入了内存。CPU执行函数就是从这个函数的起始代码开始顺序执行。函数名scanf就是起始代码在内存中的地址,即:函数名表示的是函数代码块在内存中的开始地址。

通过第二个函数,初步介绍了数据类型、变量、函数的概念,并从存储器的角度来认识这些概念,把概念和地址结合在一起,使3.1中介绍的存储器概念具体化,加强对存储器及地址的认识,在之后每次使用scanf()时,都会强调变量、空间、地址的对应关系,使学生熟知这些知识。

4 循序渐进

循序渐进是指初学者初步接触存储器和地址的概念之后,课程会继续从存储器和地址的角度解释所学内容,以加强这些概念及用法。以函数、数组、指针、结构为例说明。

4.1 函 数

C语言函数采用传值调用,在函数中修改形参的值,不会改变实参的值,如上图所示。

程序输出为:“a=10, b=20”。在解释上述结果时,不仅要强调语法规则:“函数内不能改变函数外变量的值”,还要从存储器的角度解释。如图2,main()函数中两个变量“a,b”(比如占据空间从0x01001000开始)和swap()函数中两个变量“a,b”(比如占据空间从0x01001100开始)使用不同的存储空间,swap()函数中变量“a,b”的值修改,改变的是0x01001100开始的地址空间的值,但没有修改main()函数中变量“a,b”所代表的存储空间的值,因此main()中“a,b”的值不会改变。

4.2 数 组

数组是C语言的重要内容,也是C语言的难点之一,在指针章节开始之前,数组是和存储器及地址概念结合最紧密的内容,因此在数组部分会更多强调指针的内容。在介绍数组概念及例子中,主要介绍如下知识。

(1)数组是由很多相同类型的变量组成的集合,C语言通过下标改变的方式,来表示数组中的这些变量,为写查找和排序算法提供了方便。

(2)数组中每个变量在存储器中要占据一块存储空间,这些变量所占据的存储空间是连续的。比如数组float a[N](N为常量)表示在计算机内存中的一块连续的存储器空间,空间大小为:N * sizeof(float)字节。

(3)数组名字a是这块存储空间的开始地址。a[0]表示这N个变量中的第一个变量,a和&a[0]相等,a[i]的地址和a+i*sizeof(float)相等。

(4)计算机的存储器是有限的,连续的空闲存储空间更有限,因此数组中变量的个数N是有限的。

(5)下标i的取值范围为0~N-1,但如果代码中出现对不属于数组的空间进行读操作,比如“float b=a[N+1]”,程序可能仍可以运行;如果代码中出现对不属于数组的空间进行写操作,比如“a[N+1] = 11.23”,程序可能可以正常运行,但通常会立即崩溃。因此,通过下标访问不属于程序的空间是不安全的,编程中要严格禁止。

(6)若函数的参数定义为数组,则函数对形参数组内变量修改,会同时改变实参数组变量的值,这是因为函数的形参数组是地址,实参和形参表示的是同一地址空间,内部对形参数组的访问,就是对实参表示空间的访问。

通过数组,进一步建立变量和存储空间(连续存储空间)、地址的关系,为指针学习进一步建立基础。

4.3 指 针

经过不断重复、铺垫,在指针教学开始时,学生已经熟悉了地址的概念,也更容易理解指针,之后的学习重点在于指针的用法,并逐渐习惯使用指针编程。

指针部分的主要内容包括:第一,指向变量的指针及其在函数参数传递中的作用,函数的形参定义为指针,可以在函数内部改变函数外部变量的值,实现地址调用;第二,指针与数组的关系,引入动态内存分配,学习C语言的存储器管理技术;第三,指向函数的指针,在指针指向的存储空间中,存储的是函数的代码,函数名字就是该存储空间的开始地址,初步介绍回调函数的概念;第四,指针数组的定义和使用,支持行和列都可变的二维数组定义及用法。

4.4 结 构

结构内容放在指针内容之后介绍,主要是因为指针可以是结构的成员变量,如果结构中指针变量指向的数据类型和结构相同,则可以生成链表。

介绍结构要和存储空间以及指针的概念紧密结合。定义结构时,要同时强调该结构类型变量所占据的存储空间,如以上结构定义图。结构变量的存储结构如图3所示,从中可以看到:①结构型变量中的变量,在存储器中的存储顺序和结构中变量定义的顺序相同;②基本变量、数组等占据的空间和其单独定义时占据的空间可能不同,与编译选项有关(是否设置了对齐要求);③指针变量(pNext)占据的空间大小固定,与指针所指向的数据类型没有关系。

结构定义是否合法,主要看是否能够计算出结构变量所占据的存储器空间。结构里面不能声明同一个结構类型的变量,该递归定义会导致结构变量所占据的空间无穷大,但可以定义指向该结构类型的指针,因为指针大小固定。

结构变量和普通变量一样,变量赋值操作本质上是存储器复制。比如:Student a, b; a=b;是把b变量所占据的存储空间的内容,全部复制到a变量所占据的存储空间中。如果结构中定义了数组,则实现了数组的赋值操作,而数组自己是不支持赋值操作的。但对于指针变量的复制,会导致a.pNext和b.pNext相等,这却不是程序员想要的结果,需要特别关注。

5 结 语

C程序设计语言离不开指针,学习和掌握指针用法又非常艰难,因此在C语言教学中要精心安排教学内容,并探索各种指针教学方法。本文介绍了 “开门见山”与“循序渐进”相结合的指针教学方法,其特点是把指针教学贯穿在C语言的全部教学过程中,强调指针和C语言的密切关系,淡化指针的神秘感,几年的教学实践证明,该方法具有较好的效果。

作者简介:赵帅锋,男,讲师,研究方向为信号与信息处理、通信、嵌入式系统等,shfzhao@bjtu.edu.cn;

胡绍海(通信作者),男,教授,研究方向为信号与信息处理、多媒体通信等,shhu@bjtu.edu.cn。

参考文献:

[1]李冰, 胡海峰. 关于C语言指针教学的探讨[J]. 科技信息, 2009(23): 521.

[2]吴琼. C语言指针教学方法研究[J]. 鄂州大学学报, 2009,16(2): 68-70.

[3]孙丽丽. C语言指针教学方法探讨[J]. 黑龙江科技信息, 2008(11): 128.

[4]黄晨. C语言指针教学的研究与探讨[J]. 科技信息, 2010(22): 231-232.

[5]吴斌. C语言指针教学[J]. 安徽职业技术学院学报, 2004(3): 67-69.

(编辑:史志伟)

猜你喜欢

教學指针C语言
外研版Book1 Module 3 My First Ride on a Train P2 Reading and Vocabulary By Zhang lijun
“C语言程序设计”课程混合教学探索
Unit4.let’s eat教学反思
27《鱼游到纸上》
郊游
基于C语言的计算机软件编程技术探究
中职C语言单片机课堂教学中的趣味性探讨
为什么表的指针都按照顺时针方向转动
计算机原理中C语言的应用价值
参变分离之后