陳冰川
提前介入法在C語言指針教學中的應用
陳冰川
(廣東財經大學,廣東 廣州 510320)
C語言程序設計是所有計算機及其相關專業課程中的一門重要基礎課,而指針又是該課程的重點及難點,也是其他語言中理解引用型變量的基礎。文章分析了指針成為課程難點的原因,并在教學中采用了提前介入法,在整個教學過程中,提前將與指針有關的知識有機地融入到不同章節,使學生在整個學習過程中逐步深化指針的概念,并了解其特點和作用,最終在指針一章時再進行梳理總結。通過教學實踐發現,教學中采用提前介入法,使學生對于指針的理解和掌握程度得到提升,起到了較好的實踐效果。
C語言;指針;編程語言教學
C 語言程序設計在計算機程序設計語言中占有重要的一席之地,它以語法簡潔緊湊、程序精煉、運算符和數據結構豐富、編程靈活、可移植性好而著稱[1]。而指針是其精髓和靈魂,是 C 語言中最具魅力和最富活力的部分[2],同時也是公認的教學難點[3]。C 語言通過指針來實現訪問硬件資源、動態分配和回收內存空間、降低函數調用中參數傳遞的開銷、減少使用全局變量、實現函數回調等功能。沒有指針的 C 語言不可能進行任何有實際意義的編程[2]。而且指針的思想并不是只在C語言中有意義,在JAVA、Python等語言中雖然取消了指針,但是其“引用型”變量的很多性質和應用與指針變量非常相似,掌握好了指針的概念,對于后續其他語言的學習同樣具有重要意義。但是在實際教學實踐中發現,高校學生尤其是低年級學生或是非計算機類學生,在對計算機相關基礎沒有了解的情況下,對于指針的理解和使用是具有一定困難的,因此有必要采取措施對指針的教學進行改進,提升學生對其的理解與掌握程度。
按照目前的教學規律,指針內容往往是放在比較靠后的階段進行介紹的,由于前面如數據存儲方式、變量、數組、函數等內容并不涉及指針,后面章節再談起指針,會使學生產生知識認知上的錯位和斷層。如果在講授以上內容時,提前加入與指針相關的概念,到了指針一章時將會使學生作為一個體系去理解,接受度將會大為提高。
基于以上目的,筆者結合自身學習和教學的經驗提出了提前介入的教學方法,用于在C語言程序設計教學中,即在C語言教學過程中,每一章根據其特點,從不同側面適當地引入指針的概念、使用方式和基本原理。該方法已經應用于實踐并取得了較好的成果。
筆者教學使用的教材為清華大學出版社出版,由譚浩強主編的《C語言程序設計》(第三版),根據教材的章節特點逐步引入指針的定義、內存存儲方式、基本原理、使用方法等。由于指針相關知識為教材一章的內容,如果在某節課涉及過多,會導致無法按時完成教學任務,也會為學生的學習帶來負擔,因此在每章提前介入指針概念時,基本原則是:適當涉及、點到即止、不求全懂、只留印象。
提前介入的方法主要目的是讓學生在正式進行指針一章的學習時,對于指針已經有一個初步的認識,并且了解了指針引入的目的,能夠帶來的好處,它和變量、變量地址之間的關系等。到了正式進行指針一章的講授時,學生就能夠比較自然地掌握和了解指針的特點和用法。
本文以譚浩強主編的清華出版社出版的《C語言程序設計(第3版)》為基礎,分別以數據的存儲與運算、順序結構、利用數組處理批量數據和函數實現模塊化程序設計四章為基礎,介紹如何在這些章節中引入指針的概念以及講授的重點。
本章的主要內容是介紹數據在內存中如何存儲,以及按照不同數據類型(包括整型、實型和字符型)介紹變量、常量的不同存儲方式和表現形式,最后介紹算數表達式和相關的C語言表達式。本章關鍵是對于變量和常量的理解和掌握,而指針對于變量的存儲模式具有促進作用,因此本章可自然地引入指針和指針變量的概念。
首先,在本章第一節“數據在計算機中是怎樣存儲的”中,強化計算機按字節存儲,字節的編號就是地址,地址能夠指出數據存儲的位置便于查找,由此可引出地址還叫做“指針”,讓學生對于內存存儲有一個初步概念,了解到通過地址或指針就可以找到要存儲(讀取)數據的位置。
然后,在本章第二節“整型數據的運算與分析”中,介紹什么是變量時將變量名、變量地址、存儲單元和變量值,通過校園的某棟樓的名稱(如:第一教學樓)、所在校內地址(如某區某棟)、大樓本身和樓內的學生分別做一一對應,深化學生對于變量名、變量地址的理解。在此基礎上,講授賦值的過程,即編譯系統根據變量名所代表的地址,找到存儲單元,將所賦之值存入。
(1)引導學生思考,如果定義了一個整型變量x其對應的地址為100000,還有另外一個變量p(此處忽略如何定義)保存了變量x的地址100000,請學生設想如果想給100000的地址對應的存儲單元中存儲一個整型常量10,如何處理。
(2)進一步引導學生了解可以通過x=10進行賦值,即告訴系統將10存儲到變量x對應的地址中。
(3)再進一步提示學生p也存儲了x的地址,如何告知系統將10存儲到p所保存的地址對應的存儲空間呢?注意p=10是錯誤的,按照x=10的處理規則會發現這樣的語句只會將10存儲到p對應的地址(而不是存儲的地址)中。
(4)最后告訴學生,c語言通過符號“*p”來代表訪問p保存的地址空間,而變量p就像一個“指針”指向了x對應的內存空間,因此p就是后面將要學習到的“指針變量”即:用來存儲指針(地址)的變量。如果想要將x的地址賦值到p變量中,由于編程期間是無法了解該變量在運行時被分配的地址,不能直接給p賦值100000,只能通過p=&x的方法賦值,進而介紹取地址的符號。
到此基本將指針和指針變量,以及它的作用講清楚了。但是由于不是系統地進行講授,為了保證學生學習的完整性,此處一般會強調并總結,無論學生聽懂與否,都沒有關系,只要了解了地址還叫指針,用來存儲地址的變量就叫做指針變量即可,以后還會繼續涉及相關內容。
本章主要介紹算法和最基本的編程結構順序結構,同時介紹了賦值語句和輸入輸出語句。因此本章將會在講授賦值語句和格式輸入輸出語句時提前介入指針的相關概念。
(1)賦值語句。
在賦值語句的講授過程中,在講授了賦值語句的預算順序以及作用后,可再次向學生提示,當一個整型變量x在賦值號左右兩邊所代表的含義之間的細微區別:在左邊表示將賦值號右面的表達式的值賦值到x所代表的內存存儲空間中,而在右邊則表示將x所代表的的內存儲空間的值賦值到賦值號左邊的變量中。一個表示x對應的存儲空間,另一個表示x對應的存儲空間的值。在這樣的解釋前提下再次提出上一章提及的指針內容:
①請學生思考:如果有一個變量p用來存儲x的地址,如果想向x賦值10,如果允許表達式p=10在c語言中運行,會帶來什么結果?能否達到向x所代表的地址的存儲空間寫入10?
②告訴學生按照賦值語句的賦值規則,上述結果只會給p對應的存儲空間賦值10,而不會賦值到x對應的存儲空間中,因此需要使用“*p=10”的方法進行賦值。此處再次提醒學生對于指針的含義以及*p的含義。
通過以上的講授既讓學生進一步了解賦值語句的作用,也使學生對于指針的操作與應用有了進一步的認識。
(2)格式輸入輸出語句。
在格式輸入輸出函數的講授中,最容易出錯的就是在scanf函數中變量參數要加取地址的符號&,此處可以再次引入指針相關的介紹。相關講解內容如下:
①講授scanf(“%d”,&x)函數的作用,是將輸入的整型值存儲到x對應地址的存儲單元中。
②簡單告知學生當變量作為函數參數時相當于把變量值傳入函數,并未傳入具體地址,從而導致函數無法獲取變量的值。
③為了能夠將地址傳入函數,則需要提供一個操作符用于返回變量的地址,c語言用“&”表示取地址的操作。
④在上機實驗課時,可以讓學生通過輸出語句輸出x的值和&x的值,同時指導學生如何通過開發環境查看變量所在的內存,以及存儲的數據。
通過上述內容的講述,既使學生了解了輸出函數的本質和變量在內存中存儲的方式,還能夠進一步了解去地址符號的作用,訓練了學生上機調試代碼的能力。
由于選擇結構和循環結構兩章主要是介紹程序結構,與內存存儲和變量關系不大,這兩章不再引入指針相關知識,將學生的精力全部放到這兩章容易錯誤的知識點上,如邏輯表達式的運算,循環的邊界條件等。而到了本章主要介紹數組時,就可以再次將指針相關的知識介入,加深學生的理解。本章主要從數組的定義,以及內存存儲方式進行指針相關知識的介入。
(1)一維數組定義。
在講授到一維數組定義時,在講解了一維數組的定義后編譯系統會根據定義的數組長度在內存中申請連續的相應大小的空間后,再次講解指針的概念。
①首先讓學生理解地址的概念,其實就是一塊連續存儲空間的首地址,其他地址根據數組的類型,依次獲取相關元素。進而讓學生考慮對于單個變量的情況,當變量為整型為4個字節時,所謂的變量地址其實也是類似的為這四個連續存儲空間的首地址,程序在讀取數據時是根據首地址依次讀取四個字節的內容,獲取變量的值。
②強調每一個數組元素都可以當做一個變量看待,即都對應了相應的內存單元,用整型數組舉例。例如:
int a[10];
假設整型占有4個字節,讓學生自己推算第i個元素的地址,即第i個元素的地址其實是a+4i。上機時通過內存查看和通過語句:
printf(“%d”,&a[i]);
查看數組每一個變量的地址的方式,加深數組元素地址的印象。
③介紹數組名代表了數組的首地址,同時擴展告訴學生,這里的數組名是一個指針常量,引導學生回憶常量本身是不可以被賦值的。
④再次提前講指針變量p是可以被賦值的例如int x; p=&x; 或者int a[10]; p=a;第一個賦值表示將x的地址存入指針變量p中,而第二個賦值表示將數組a的首地址存入指針變量p中。此處的表達方式再次說明a本身就是一個指針,所以賦值時無需增加取地址符號“&”。
⑤再次提醒學生由于p是指針變量可以被賦值,而數組名a是指針常量,不可以被賦值,即以下代碼是錯誤的:
int a[10],b[10];
a=b; //a是指針常量不可以被賦值
⑥告訴學生以下賦值都是正確的,并且p與q的值是相同的,進一步讓學生了解數組名就是數組的首地址,即:假設p和q都是指針變量,int a[10]; p=a; q=&a[0];
此處不可過于延展,否則將會使學生陷入過深,忽略了本章的重要內容。至此不僅使學生了解到了數組名指向數組的首地址,也再次回憶了變量與常量的區別,同時涉及了第八章指針部分的指向數組的指針的內容。
(2)二維數組的定義。
在二維數組的講授中,關鍵要突出每一維的含義,以及各自代表的意義。具體講授內容如下:
①講授邏輯上大家認為的二維數組就是一個二維表,而實際內存存儲只是簡單的連續空間的存儲。例如,int a[2][3]邏輯存儲是2行3列,而實際存儲就6個連續的內存空間,同樣讓學生自己推出每個元素地址的計算公式:a+4*2i+4j。上機實驗課通過內存查看進一步理解二維數組的存儲模式。
②讓學生考慮a,a[0]和&a[0][0]之間的關系,都是指向首地址,此處不宜多講,因為涉及指針變量加一的值相對難懂,為了防止學生陷入過深,此處提到即可。
通過此章關于指針相關的內容的提前講授,讓學生對于指針在數組中的應用有了一個初步認識,為第八章數組與指針一節做好鋪墊。
本章主要是介紹C語言的函數的定義、聲明和使用,并通過變量的周期和生存期說明變量在函數中的特性。結合本章內容,可以簡要地講解指針作為函數參數的內容。
(1)函數的定義,在本節中主要提示學生代碼要運行同樣需要載入內存,也同樣要有地址,而函數名實際上就是函數指令存儲的首地址也叫“函數入口”。
(2)函數的嵌套調用,本節主要通過板書將每個函數畫作一個獨立的空間,當該函數被調用時,動態地在其空間內將函數中的變量,以及形參申請空間,并重點說明將實參的值賦值到形參對應的空間中。當該函數調用結束后,直接擦除剛剛申請的變量,直觀地讓學生體會到,函數內部的變量的值除了通過return語句,無法被傳遞至函數之外;也認識到函數參數之間是通過值傳遞,而無法通過在函數內改變實參的值。
(3)數組作為函數參數,主要講解數組名作為參數,數組名與變量名的關系。
①讓學生回憶一個函數如何返回一個值,并讓學生思考如果有多個值需要返回需要如何處理?進而告知C語言中有幾種返回方式,一是接下來要學習的多個全局變量可以把函數中的若干值返回;第二是后面章節要學的通過返回結構體返回多個值;最后是通過指針將地址告訴函數,將結果直接存儲在相應內存中,從而起到返回若干值的效果。
②理解函數形參test(int a[10])和調用函數中數組定義int a[10]樣子一樣,但是意義完全不同,作為形參的類似數組定義的a實際上是一個指針變量,說明是一個指向由10個元素組成的整型數組的首地址的指針變量,而在調用程序中定義的則是一個指針常量指代數組的首地址,通過值傳遞將常量的值傳給了指針變量。此處點到即止不宜講得過深,由于并未系統地進行講授,過于深入容易讓學生混亂,只需了解到它們是有區別的即可。
③進一步解釋為什么通過數組名作為函數的參數可以將值帶出函數(本節前已經讓學生了解了函數內部的值是不能被函數以外的代碼訪問的)。由于數組名代表了數組所在的地址(如②所述),而函數用數組名作為參數,也就是在函數中指明了值需要保存的位置,直接將數值保存至函數之外了。
通過上述的講解讓學生進一步了解了指針在函數參數中所起的作用,并加深了為什么函數無法改變實參的值的原理。對于第八章講解“指針變量作為函數參數”一節打下鋪墊。
通過以上課程對于指針的提前介入,根據課程實際內容可以發現對于指針的提前介入不僅可以讓學生能夠提前接觸到指針的概念,便于后續的學習,而且還可以加深對應章節的一些原理的認識,更能夠掌握C語言的精髓。如果只是在指針一章,再將前面的內容重復補充,很難讓學生有一個清楚的認識,因為大學生的學習規律與中學不同,課后復習的習慣在減弱,如果在課堂授課時沒有第一時間講清楚,相當一部分學生將會在后續的學習中淡忘,效果將大打折扣,因此在學習相關知識時應提前提及,在真正學習相關內容時,學生更容易接受和理解。
指針作為C語言的一個重要特征和精髓,其實貫穿了整個C語言的知識之中,如果不提前接觸,對于很多原理只能是死記硬背,難以融會貫通,因此本文提出了提前介入法,進行C語言中的指針知識點的教學,不僅使學生更深刻地認識到了當前所學知識的原理,也對于后續指針章節的學習有了更深的理解。實踐證明(4個學期以上的實踐教學),發現到了指針一章的講解時,學生的理解和接受程度提高了很多。
在以后的教學中,需要再深化此種教學,在不影響當前課程內容理解的同時,更深入地讓學生提前了解指針,真正地掌握指針,對于C語言的應用更加得心應手,并會進一步研究提前介入法在其他課程和知識講授中的應用與實踐。
[1]張憶文,C 語言指針教學難點透析[J]. 計算機教育,2017(1): 155-161.
[2] 趙帥鋒,胡紹海. 開門見山與循序漸進: 一種 C 語言指針教學方法[J]. 計算機教育,2017(4): 112-120
[3] 王立柱. 數據結構與算法[M]. 北京: 華章出版社,2013.
Application of Advance Intervention Method in C Language Pointer Teaching
C programming language is an important basic course in all computer science and related professional courses, and the pointer is the keynote and difficulty of this course, and it is also the basis for understanding referential variables in other languages. This paper analyzes the reasons why the pointer has become a difficult point of the course, and adopts the advance intervention method in teaching. In the whole teaching process, organically integrate the knowledge related to the pointer into different chapters in advance, so that in the whole learning process students can gradually know the concept of the pointer, understand its characteristics and functions, and finally comb and summarize when teaching the chapter of the pointer. Through the teaching practice, it is found that the advance intervention method in teaching has improved the students' understanding and mastery of the pointer, and has played a good practical effect.
C language; pointer; programming language teaching
G642
A
1008-1151(2022)12-0128-03
2022-10-10
廣東省教育廳特色項目(2017KTSCX074)。
陳冰川(1975-),男,四川達州人,廣東財經大學講師,研究方向為軟件工程、人工智能。