趙帥鋒+胡紹海
(北京交通大學(xué) 計(jì)算機(jī)與信息技術(shù)學(xué)院,北京 100044)
摘 要:指針是C語(yǔ)言教學(xué)中的難點(diǎn)和重點(diǎn),作者提出一種指針教學(xué)方法,即把指針的內(nèi)容貫穿于C語(yǔ)言的整個(gè)教學(xué)過(guò)程中:在第一次課中會(huì)介紹存儲(chǔ)器和地址的概念,在隨后的教學(xué)中,從存儲(chǔ)器和地址的角度解釋所學(xué)內(nèi)容,在指針教學(xué)章節(jié)重點(diǎn)介紹指針用法。
關(guān)鍵詞: C語(yǔ)言;C程序設(shè)計(jì);指針;教學(xué)
1 背 景
指針是C語(yǔ)言的精髓和靈魂,是C語(yǔ)言中最具魅力和最富活力的部分,C語(yǔ)言通過(guò)指針來(lái)實(shí)現(xiàn)訪問(wèn)硬件資源、動(dòng)態(tài)分配和回收內(nèi)存空間、降低函數(shù)調(diào)用中參數(shù)傳遞的開(kāi)銷、減少使用全局變量、實(shí)現(xiàn)函數(shù)回調(diào)等功能。沒(méi)有指針的C語(yǔ)言不可能進(jìn)行任何有實(shí)際意義的編程。
指針也是C語(yǔ)言中最危險(xiǎn)的部分,程序會(huì)因指針使用不當(dāng)而潛藏風(fēng)險(xiǎn),輕則導(dǎo)致程序退出,重則導(dǎo)致系統(tǒng)內(nèi)存泄漏,甚至系統(tǒng)崩潰。
使用C語(yǔ)言編程離不開(kāi)指針,但掌握和熟練使用指針卻很難,對(duì)初學(xué)者尤其如此。指針是C語(yǔ)言教學(xué)中的難點(diǎn)和重點(diǎn),很多教師在教學(xué)中嘗試了多種方法[1-5],取得了不錯(cuò)的效果。作者經(jīng)過(guò)多年C語(yǔ)言教學(xué)實(shí)踐,逐漸摸索出“開(kāi)門(mén)見(jiàn)山”與“循序漸進(jìn)”相結(jié)合的指針教學(xué)方法,把指針教學(xué)融合在C語(yǔ)言教學(xué)的全過(guò)程中。“開(kāi)門(mén)見(jiàn)山”是在課程開(kāi)始,通過(guò)介紹計(jì)算機(jī)體系架構(gòu)和程序運(yùn)行過(guò)程,引入存儲(chǔ)器及地址概念,盡早引入指針;“循序漸進(jìn)”是在之后課堂教學(xué)內(nèi)容的設(shè)計(jì)中,不斷介紹和強(qiáng)化存儲(chǔ)器的概念,加強(qiáng)學(xué)生對(duì)地址的認(rèn)識(shí)。在正式介紹指針教學(xué)內(nèi)容前,這種教學(xué)方法使學(xué)生已經(jīng)建立并熟悉指針概念,對(duì)掌握和使用指針編程很有幫助。
2 指針學(xué)習(xí)困難的原因
學(xué)生在指針學(xué)習(xí)時(shí),普遍感覺(jué)指針概念抽象,難以理解,影響學(xué)習(xí)、掌握和使用。主要原因在于如下3點(diǎn)。
(1)對(duì)學(xué)生而言,程序設(shè)計(jì)是一門(mén)全新類型的課程。其特點(diǎn)是知識(shí)點(diǎn)分散、邏輯性不強(qiáng)。編寫(xiě)代碼既要符合語(yǔ)法規(guī)則,又要考慮邏輯關(guān)系,編碼必須嚴(yán)格遵守語(yǔ)法規(guī)則:一個(gè)看上去微不足道的錯(cuò)誤,比如語(yǔ)句漏寫(xiě)了分號(hào),編譯器會(huì)在其他沒(méi)有錯(cuò)誤的地方報(bào)告很多錯(cuò)誤信息,這使初學(xué)者手足無(wú)措,無(wú)法排錯(cuò);程序有了致命錯(cuò)誤,比如變量沒(méi)有初始化,但編譯器只會(huì)輕描淡寫(xiě)地報(bào)個(gè)告警(warning),程序運(yùn)行時(shí),卻時(shí)對(duì)時(shí)錯(cuò)。這些特征對(duì)于初學(xué)者都是陌生的,他們以往的學(xué)習(xí)方法和經(jīng)驗(yàn)在面對(duì)該課程時(shí)幾乎沒(méi)有任何借鑒作用,這導(dǎo)致他們從課程開(kāi)始就遇到很多困難。
(2)學(xué)生們不了解計(jì)算機(jī)。C語(yǔ)言是伴隨著UNIX操作系統(tǒng)產(chǎn)生的,它的語(yǔ)言特性和計(jì)算機(jī)的構(gòu)成緊密結(jié)合,甚至可以說(shuō),C語(yǔ)言是為對(duì)計(jì)算機(jī)了如指掌的專家設(shè)計(jì)的。而大學(xué)中常把C語(yǔ)言課程安排為程序設(shè)計(jì)的常識(shí)教育,學(xué)生在學(xué)習(xí)C程序設(shè)計(jì)課程前,還沒(méi)有學(xué)過(guò)計(jì)算機(jī)原理等課程,他們可能聽(tīng)說(shuō)過(guò)CPU、內(nèi)存等概念,但并不了解這些概念的確切含義,不了解程序運(yùn)行的過(guò)程,這會(huì)導(dǎo)致指針概念更加抽象,難以理解、掌握并使用。
(3)學(xué)生們通常是在學(xué)習(xí)C語(yǔ)言遇到困難挫折的情況下,接觸和學(xué)習(xí)指針的,這增加了他們的畏懼心理,影響指針內(nèi)容的掌握?;谂d趣,在課程開(kāi)始階段他們專心聽(tīng)講,努力編寫(xiě)和調(diào)試簡(jiǎn)單的程序,但隨著變量、函數(shù)、數(shù)組等內(nèi)容逐漸引入,程序結(jié)構(gòu)越發(fā)復(fù)雜,程序設(shè)計(jì)需要同時(shí)考慮算法,這會(huì)使學(xué)生感覺(jué)到學(xué)習(xí)的壓力和困難,特別是在編譯程序時(shí),排除一個(gè)小小的錯(cuò)誤,都要耗費(fèi)很長(zhǎng)的時(shí)間,這嚴(yán)重影響他們的學(xué)習(xí)熱情和信心。在這種情況下,指針被引入課程中,并且指針概念抽象,又和C中的變量、函數(shù)、數(shù)組、結(jié)構(gòu)等聯(lián)系緊密,這些都放大了指針的學(xué)習(xí)難度,影響學(xué)生的理解和掌握。
針對(duì)如上問(wèn)題,作者逐漸探索并使用了“開(kāi)門(mén)見(jiàn)山”與“循序漸進(jìn)”相結(jié)合的教學(xué)方法。
3 開(kāi)門(mén)見(jiàn)山
所謂開(kāi)門(mén)見(jiàn)山,指在第一次課就介紹存儲(chǔ)器和地址的概念。在介紹“Hello world”之后,即介紹計(jì)算機(jī)的結(jié)構(gòu)、存儲(chǔ)器和地址的概念,隨后介紹“第二個(gè)程序”以加深這些概念的理解。
3.1 計(jì)算機(jī)結(jié)構(gòu)與存儲(chǔ)器
初學(xué)者通過(guò)“Hello world”了解了C語(yǔ)言的代碼風(fēng)格、集成開(kāi)發(fā)環(huán)境和程序編譯、鏈接、執(zhí)行的過(guò)程,隨后介紹計(jì)算機(jī)的“馮·諾依曼”結(jié)構(gòu),向?qū)W生說(shuō)明程序在計(jì)算機(jī)內(nèi)的運(yùn)行過(guò)程。課堂主要介紹如下幾個(gè)方面知識(shí)。
(1)計(jì)算機(jī)構(gòu)成及程序運(yùn)行的方法。如圖1所示,其中外存儲(chǔ)器指硬盤(pán),操作系統(tǒng)、應(yīng)用程序和數(shù)據(jù)都以文件形式保存在硬盤(pán)上,內(nèi)存儲(chǔ)器保存正在運(yùn)行的程序和程序所要操作的數(shù)據(jù),這些程序是由操作系統(tǒng)從硬盤(pán)上裝入到內(nèi)存儲(chǔ)器的。CPU(運(yùn)算器、控制器)用于運(yùn)行程序,CPU從程序所在的存儲(chǔ)器起始位置開(kāi)始,依次讀取指令并執(zhí)行,直到程序結(jié)束。
(2)內(nèi)存儲(chǔ)器是由N個(gè)連續(xù)的存儲(chǔ)單元組成的,每個(gè)單元可以存儲(chǔ)8比特二進(jìn)制數(shù)(稱為一個(gè)字節(jié));N稱為內(nèi)存容量。計(jì)算機(jī)為每個(gè)存儲(chǔ)單元分配唯一的編號(hào),從0開(kāi)始編起,直到N-1,這個(gè)編號(hào)稱為該存儲(chǔ)單元的“地址”,CPU使用編號(hào)(地址)訪問(wèn)這些存儲(chǔ)單元。
(3)內(nèi)存儲(chǔ)器中存儲(chǔ)的既有代碼,也有數(shù)據(jù);構(gòu)成程序的代碼依次存儲(chǔ)在內(nèi)存儲(chǔ)器中;程序要操作的數(shù)據(jù)也保存在內(nèi)存儲(chǔ)器中。
3.2 第二個(gè)程序
第二個(gè)程序展示計(jì)算機(jī)的計(jì)算功能,該程序引入了變量及數(shù)據(jù)類型概念,存儲(chǔ)器和地址在程序代碼中首次出現(xiàn)。代碼如上圖所示。
介紹程序強(qiáng)調(diào)如下幾個(gè)方面的知識(shí)。
(1)計(jì)算機(jī)要計(jì)算兩個(gè)整數(shù)的和,首先需要找兩個(gè)地方來(lái)保存這兩個(gè)整數(shù),這兩個(gè)地方就位于內(nèi)存中;
(2)計(jì)算機(jī)在內(nèi)存中為不同類型的數(shù)據(jù)分配大小不同的存儲(chǔ)空間,“int a,b,r;”要求計(jì)算機(jī)分配三塊內(nèi)存空間,分別用變量“a,b,r”表示,每塊內(nèi)存空間存儲(chǔ)一個(gè)整數(shù),變量的值改變,表示其所代表的存儲(chǔ)空間存儲(chǔ)的內(nèi)容發(fā)生了改變。
(3)scanf(“%d, %d”, &a, &b)表示從標(biāo)準(zhǔn)輸入設(shè)備(鍵盤(pán))上接收用戶輸入的兩個(gè)整數(shù),這兩個(gè)整數(shù)分別保存在“a,b”所代表的內(nèi)存中,內(nèi)存用地址表示,“&a,&b”分別表示取“a,b”的地址,“%d”表示每個(gè)空間要保存的數(shù)的數(shù)據(jù)類型為整數(shù),這確定了每個(gè)空間占據(jù)的字節(jié)個(gè)數(shù)。
(4)scanf()實(shí)現(xiàn)的功能是通過(guò)很多條計(jì)算機(jī)代碼實(shí)現(xiàn)的,這些代碼在程序被裝入內(nèi)存時(shí),也被裝入了內(nèi)存。CPU執(zhí)行函數(shù)就是從這個(gè)函數(shù)的起始代碼開(kāi)始順序執(zhí)行。函數(shù)名scanf就是起始代碼在內(nèi)存中的地址,即:函數(shù)名表示的是函數(shù)代碼塊在內(nèi)存中的開(kāi)始地址。
通過(guò)第二個(gè)函數(shù),初步介紹了數(shù)據(jù)類型、變量、函數(shù)的概念,并從存儲(chǔ)器的角度來(lái)認(rèn)識(shí)這些概念,把概念和地址結(jié)合在一起,使3.1中介紹的存儲(chǔ)器概念具體化,加強(qiáng)對(duì)存儲(chǔ)器及地址的認(rèn)識(shí),在之后每次使用scanf()時(shí),都會(huì)強(qiáng)調(diào)變量、空間、地址的對(duì)應(yīng)關(guān)系,使學(xué)生熟知這些知識(shí)。
4 循序漸進(jìn)
循序漸進(jìn)是指初學(xué)者初步接觸存儲(chǔ)器和地址的概念之后,課程會(huì)繼續(xù)從存儲(chǔ)器和地址的角度解釋所學(xué)內(nèi)容,以加強(qiáng)這些概念及用法。以函數(shù)、數(shù)組、指針、結(jié)構(gòu)為例說(shuō)明。
4.1 函 數(shù)
C語(yǔ)言函數(shù)采用傳值調(diào)用,在函數(shù)中修改形參的值,不會(huì)改變實(shí)參的值,如上圖所示。
程序輸出為:“a=10, b=20”。在解釋上述結(jié)果時(shí),不僅要強(qiáng)調(diào)語(yǔ)法規(guī)則:“函數(shù)內(nèi)不能改變函數(shù)外變量的值”,還要從存儲(chǔ)器的角度解釋。如圖2,main()函數(shù)中兩個(gè)變量“a,b”(比如占據(jù)空間從0x01001000開(kāi)始)和swap()函數(shù)中兩個(gè)變量“a,b”(比如占據(jù)空間從0x01001100開(kāi)始)使用不同的存儲(chǔ)空間,swap()函數(shù)中變量“a,b”的值修改,改變的是0x01001100開(kāi)始的地址空間的值,但沒(méi)有修改main()函數(shù)中變量“a,b”所代表的存儲(chǔ)空間的值,因此main()中“a,b”的值不會(huì)改變。
4.2 數(shù) 組
數(shù)組是C語(yǔ)言的重要內(nèi)容,也是C語(yǔ)言的難點(diǎn)之一,在指針章節(jié)開(kāi)始之前,數(shù)組是和存儲(chǔ)器及地址概念結(jié)合最緊密的內(nèi)容,因此在數(shù)組部分會(huì)更多強(qiáng)調(diào)指針的內(nèi)容。在介紹數(shù)組概念及例子中,主要介紹如下知識(shí)。
(1)數(shù)組是由很多相同類型的變量組成的集合,C語(yǔ)言通過(guò)下標(biāo)改變的方式,來(lái)表示數(shù)組中的這些變量,為寫(xiě)查找和排序算法提供了方便。
(2)數(shù)組中每個(gè)變量在存儲(chǔ)器中要占據(jù)一塊存儲(chǔ)空間,這些變量所占據(jù)的存儲(chǔ)空間是連續(xù)的。比如數(shù)組float a[N](N為常量)表示在計(jì)算機(jī)內(nèi)存中的一塊連續(xù)的存儲(chǔ)器空間,空間大小為:N * sizeof(float)字節(jié)。
(3)數(shù)組名字a是這塊存儲(chǔ)空間的開(kāi)始地址。a[0]表示這N個(gè)變量中的第一個(gè)變量,a和&a[0]相等,a[i]的地址和a+i*sizeof(float)相等。
(4)計(jì)算機(jī)的存儲(chǔ)器是有限的,連續(xù)的空閑存儲(chǔ)空間更有限,因此數(shù)組中變量的個(gè)數(shù)N是有限的。
(5)下標(biāo)i的取值范圍為0~N-1,但如果代碼中出現(xiàn)對(duì)不屬于數(shù)組的空間進(jìn)行讀操作,比如“float b=a[N+1]”,程序可能仍可以運(yùn)行;如果代碼中出現(xiàn)對(duì)不屬于數(shù)組的空間進(jìn)行寫(xiě)操作,比如“a[N+1] = 11.23”,程序可能可以正常運(yùn)行,但通常會(huì)立即崩潰。因此,通過(guò)下標(biāo)訪問(wèn)不屬于程序的空間是不安全的,編程中要嚴(yán)格禁止。
(6)若函數(shù)的參數(shù)定義為數(shù)組,則函數(shù)對(duì)形參數(shù)組內(nèi)變量修改,會(huì)同時(shí)改變實(shí)參數(shù)組變量的值,這是因?yàn)楹瘮?shù)的形參數(shù)組是地址,實(shí)參和形參表示的是同一地址空間,內(nèi)部對(duì)形參數(shù)組的訪問(wèn),就是對(duì)實(shí)參表示空間的訪問(wèn)。
通過(guò)數(shù)組,進(jìn)一步建立變量和存儲(chǔ)空間(連續(xù)存儲(chǔ)空間)、地址的關(guān)系,為指針學(xué)習(xí)進(jìn)一步建立基礎(chǔ)。
4.3 指 針
經(jīng)過(guò)不斷重復(fù)、鋪墊,在指針教學(xué)開(kāi)始時(shí),學(xué)生已經(jīng)熟悉了地址的概念,也更容易理解指針,之后的學(xué)習(xí)重點(diǎn)在于指針的用法,并逐漸習(xí)慣使用指針編程。
指針部分的主要內(nèi)容包括:第一,指向變量的指針及其在函數(shù)參數(shù)傳遞中的作用,函數(shù)的形參定義為指針,可以在函數(shù)內(nèi)部改變函數(shù)外部變量的值,實(shí)現(xiàn)地址調(diào)用;第二,指針與數(shù)組的關(guān)系,引入動(dòng)態(tài)內(nèi)存分配,學(xué)習(xí)C語(yǔ)言的存儲(chǔ)器管理技術(shù);第三,指向函數(shù)的指針,在指針指向的存儲(chǔ)空間中,存儲(chǔ)的是函數(shù)的代碼,函數(shù)名字就是該存儲(chǔ)空間的開(kāi)始地址,初步介紹回調(diào)函數(shù)的概念;第四,指針數(shù)組的定義和使用,支持行和列都可變的二維數(shù)組定義及用法。
4.4 結(jié) 構(gòu)
結(jié)構(gòu)內(nèi)容放在指針內(nèi)容之后介紹,主要是因?yàn)橹羔樋梢允墙Y(jié)構(gòu)的成員變量,如果結(jié)構(gòu)中指針變量指向的數(shù)據(jù)類型和結(jié)構(gòu)相同,則可以生成鏈表。
介紹結(jié)構(gòu)要和存儲(chǔ)空間以及指針的概念緊密結(jié)合。定義結(jié)構(gòu)時(shí),要同時(shí)強(qiáng)調(diào)該結(jié)構(gòu)類型變量所占據(jù)的存儲(chǔ)空間,如以上結(jié)構(gòu)定義圖。結(jié)構(gòu)變量的存儲(chǔ)結(jié)構(gòu)如圖3所示,從中可以看到:①結(jié)構(gòu)型變量中的變量,在存儲(chǔ)器中的存儲(chǔ)順序和結(jié)構(gòu)中變量定義的順序相同;②基本變量、數(shù)組等占據(jù)的空間和其單獨(dú)定義時(shí)占據(jù)的空間可能不同,與編譯選項(xiàng)有關(guān)(是否設(shè)置了對(duì)齊要求);③指針變量(pNext)占據(jù)的空間大小固定,與指針?biāo)赶虻臄?shù)據(jù)類型沒(méi)有關(guān)系。
結(jié)構(gòu)定義是否合法,主要看是否能夠計(jì)算出結(jié)構(gòu)變量所占據(jù)的存儲(chǔ)器空間。結(jié)構(gòu)里面不能聲明同一個(gè)結(jié)構(gòu)類型的變量,該遞歸定義會(huì)導(dǎo)致結(jié)構(gòu)變量所占據(jù)的空間無(wú)窮大,但可以定義指向該結(jié)構(gòu)類型的指針,因?yàn)橹羔槾笮」潭ā?/p>
結(jié)構(gòu)變量和普通變量一樣,變量賦值操作本質(zhì)上是存儲(chǔ)器復(fù)制。比如:Student a, b; a=b;是把b變量所占據(jù)的存儲(chǔ)空間的內(nèi)容,全部復(fù)制到a變量所占據(jù)的存儲(chǔ)空間中。如果結(jié)構(gòu)中定義了數(shù)組,則實(shí)現(xiàn)了數(shù)組的賦值操作,而數(shù)組自己是不支持賦值操作的。但對(duì)于指針變量的復(fù)制,會(huì)導(dǎo)致a.pNext和b.pNext相等,這卻不是程序員想要的結(jié)果,需要特別關(guān)注。
5 結(jié) 語(yǔ)
C程序設(shè)計(jì)語(yǔ)言離不開(kāi)指針,學(xué)習(xí)和掌握指針用法又非常艱難,因此在C語(yǔ)言教學(xué)中要精心安排教學(xué)內(nèi)容,并探索各種指針教學(xué)方法。本文介紹了 “開(kāi)門(mén)見(jiàn)山”與“循序漸進(jìn)”相結(jié)合的指針教學(xué)方法,其特點(diǎn)是把指針教學(xué)貫穿在C語(yǔ)言的全部教學(xué)過(guò)程中,強(qiáng)調(diào)指針和C語(yǔ)言的密切關(guān)系,淡化指針的神秘感,幾年的教學(xué)實(shí)踐證明,該方法具有較好的效果。
作者簡(jiǎn)介:趙帥鋒,男,講師,研究方向?yàn)樾盘?hào)與信息處理、通信、嵌入式系統(tǒng)等,shfzhao@bjtu.edu.cn;
胡紹海(通信作者),男,教授,研究方向?yàn)樾盘?hào)與信息處理、多媒體通信等,shhu@bjtu.edu.cn。
參考文獻(xiàn):
[1]李冰, 胡海峰. 關(guān)于C語(yǔ)言指針教學(xué)的探討[J]. 科技信息, 2009(23): 521.
[2]吳瓊. C語(yǔ)言指針教學(xué)方法研究[J]. 鄂州大學(xué)學(xué)報(bào), 2009,16(2): 68-70.
[3]孫麗麗. C語(yǔ)言指針教學(xué)方法探討[J]. 黑龍江科技信息, 2008(11): 128.
[4]黃晨. C語(yǔ)言指針教學(xué)的研究與探討[J]. 科技信息, 2010(22): 231-232.
[5]吳斌. C語(yǔ)言指針教學(xué)[J]. 安徽職業(yè)技術(shù)學(xué)院學(xué)報(bào), 2004(3): 67-69.
(編輯:史志偉)