国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

指針教學內(nèi)容改革之一

2009-03-17 09:14王恒濱
計算機教育 2009年3期
關(guān)鍵詞:指針C語言教學內(nèi)容

文章編號:1672-5913(2009)02-0077-05

摘 要:C語言指針教學內(nèi)容組織近乎千篇一律,除相關(guān)概念至今未見在教材中求精外,理論基礎(chǔ)的介紹既不精準又不一致更不直觀,大體停留在羅列各種使用情形上。本文選取了已投入教學實踐并取得良好效果的自編講義中的一段,以展示教改成果。其中的字面指針能使介紹直觀化。

關(guān)鍵詞:教學內(nèi)容;C語言;指針

中圖分類號:G642

文獻標識碼:B

1 基本指針類型

C語言中,指針是一種特殊類型的整型值,所以也說成是指針值。指針與地址不同,地址是反映計算機存儲介質(zhì)邏輯構(gòu)造的物理概念。存儲介質(zhì)由字節(jié)組成,每個字節(jié)都有一定的序號(如0,1,2,3,…,100,101,…,1000,1001,……),這些連續(xù)的序號就是它們的物理地址。地址作為字節(jié)的序號,用整數(shù)就能表示。

然而僅僅地址并不能反映該地址處的若干字節(jié)是由什么類型的變量或數(shù)組所用,正像僅憑“長安大街100號”并不能指明該處是大商場還是小店鋪,乃至是圍有幾棟樓的居民小區(qū)。為了描述“是由什么所用”這層含義,引入了指針概念,并給出了指針類型及其表達方法。

有了指針類型,指針就能由整型值地址轉(zhuǎn)化而成,在程序需要指針時有計可施。

指針類型并不像結(jié)構(gòu)體類型,需要專門做出類型聲明,而只需在已有的類型名上添加運算符就能表達,甚至像數(shù)組類型之類,只需添加運算符[]和其中的整型常量值。

盡管有些指針類型的表達可能非常復雜,但這里僅討論表達簡潔的基本指針類型,即在已有的非數(shù)組類型后跟隨星號。例如:

short * char * struct tag *

(假設(shè)struct tag是已聲明的結(jié)構(gòu)體類型,且全文有效)。

如果想把程序中出現(xiàn)的整數(shù)2000看成是存儲介質(zhì)序號2000字節(jié)的地址,就必須配合使用指針類型。例如:

① (short *)2000

② (char *)2000

③ (struct tag *)2000

都是合理的,參照-2000是字面負整數(shù)的說法,它們都可以認為是字面指針。此時,其中的2000代表地址,不過它們還有另一層含義,那就是地址2000處的若干字節(jié),在①看來是用兩個字節(jié)為short型變量所用;在②看來是用一個字節(jié)為char型變量所用,等。

1.1 指針

指針是整型值配上指針類型,此時的整型值代表地址。例如,假設(shè)k是整型變量,則

(short *)k (long *)(2*k+1)

(char *)2000 (struct tag *)3000

的結(jié)果都是指針。若k的值為1000,那么(short *)k與(long *)(2*k+1)分別等于

(short *)1000 與 (long *)2001

為了敘述方便,可以稱:(1)指針類型星號前的類型為基類型,(2)類型后的整型值為指針地址,如下表:

1.2 指針變量

這種類型的變量可以用來存儲指針,定義指針變量要用指針類型來完成。以下寫出的都是指針變量的定義。

short * p1; char * p2;

struct tag * p3;

之后,p1、p2、p3便都是指針變量名。

使用賦值運算可以讓指針變量存儲指針,但類型應(yīng)當一致。例如

p1 = (short *)k; p2 = (char *)2000;

p3 = (struct tag *)2000;

都是正確的(k的意義同上文)。

用指針變量來存儲指針,不過是存儲了指針地址,指針類型的信息全憑這個指針變量的類型體現(xiàn)。例如,p2存儲的是2000,由于它是char * 型的指針變量,所以它的值為:

(char *)2000

指針變量對應(yīng)內(nèi)存的字節(jié)數(shù),由編程環(huán)境中設(shè)置的模式?jīng)Q定,small模式等為2字節(jié),large模式等為4字節(jié)。

定義指針變量的方法,可以動態(tài)地描述成:在已有變量定義的基礎(chǔ)上,在變量名前加星號。例如

int p1, v, p2; => int *p1, v, *p2;

那么,p1,p2變成為指針變量。

注意,在星號的前后增減空格不會影響語義。

1.3 輸出指針

凡是能夠輸出整型值的格式輸出,都可以輸出指針的指針地址。但不能忘記指針是在2字節(jié)的small模式下還是在4字節(jié)的large模式下。

%p格式的printf()專門用來輸出指針的指針地址。不同的是,它能自動察覺程序完成時的編程環(huán)境是什么模式,以便相應(yīng)地采取類似%x格式或%lx格式的輸出,但相比之下輸出形式略有差異:

●small模式時,輸出地址的4位十六進制數(shù)字。

●large模式時,輸出地址的8位十六進制數(shù)字,且兩個4位之間用冒號隔開。

例如,

printf("%p", (int *)30);

在small模式下,將輸出001e;在large模式下,將輸出0000:001e

1.4 直接代表指針

1.4.1一維數(shù)組名代表指針

C語言的一維數(shù)組名和變量名,在語義上存在著本質(zhì)區(qū)別。盡管它們都唯一地對應(yīng)一塊內(nèi)存,并且內(nèi)存塊的首字節(jié)地址正是這種對應(yīng)的確切反映。然而,在程序中簡單地使用變量名意味著要向那塊內(nèi)存儲存數(shù)據(jù)或要從中取得數(shù)據(jù);簡單地使用一維數(shù)組名卻意味著僅僅要利用那塊內(nèi)存的首字節(jié)地址形成的有相同基類型的指針。亦即,指針的基類型就是數(shù)組的基類型。由于內(nèi)存塊的位置是確定的,所以經(jīng)??吹降恼f法類似于:數(shù)組名是指針常量。

可以用printf("%p", 數(shù)組名);來輸出數(shù)組對應(yīng)內(nèi)存塊的首字節(jié)地址。這從一個側(cè)面表明,盡管數(shù)組的內(nèi)存是系統(tǒng)分配的,但我們還是可以知道它在什么地方。

1.4.2 字符串常量代表指針

在程序中,經(jīng)??梢钥吹竭@樣的寫法:

p = "e:\turboc2\student.dat";

其中,p是char* 型的指針變量。實際上,系統(tǒng)要為這樣的字符串常量專門開辟一塊內(nèi)存來存儲它包含的字符??墒?,它在程序中留下的可供直接使用的只有char* 型的指針,指針地址就是那塊內(nèi)存的首字節(jié)地址,所以才要用一個指針變量來保存,以便之后隨時可用。

在此額外提一句,整型常量的存儲位置很隱蔽,但幸好沒必要知道。表達式計算的中間結(jié)果存儲在什么地方也是隱蔽的。

有了以上兩點認識,就可以這樣說,%s格式的輸出部分可以是指針值,只要指針地址處的若干字節(jié)存儲了恰當?shù)淖址V劣谠谳敵霾糠痔帉懙氖亲址A窟€是數(shù)組名,都無關(guān)緊要。

2 基本指針的運算

指針能參與的運算很有限。除賦值運算以外,還有其他七個種類。前四個種類分別是“*”、“[ ]”、“&”和強制指針類型轉(zhuǎn)換運算。

2.1 指針的指針運算

* —— 除了用來構(gòu)成指針類型之外,還可以出現(xiàn)在指針前,與指針一起構(gòu)成一個基類型的變量?!?指針”變量的內(nèi)存就是指針地址處的若干字節(jié)。它是單目運算符。

例如,*(int *)2000是一個int型的變量,這個表達式的值是這個變量的值,而不是2000。

再如,若an是int[100]型數(shù)組名,*an就為int型的變量,也就是an的第0號元素an[0]。

再如,*"Hello"是一個char型的變量,其中存儲的是字符'H'。

2.2 指針的下標運算

[ ] —— 除用來構(gòu)成數(shù)組類型之外,當其間包含有整型值并出現(xiàn)在指針后,將與指針結(jié)合成一個基類型的變量?!爸羔榌整型值]”變量就是“*(指針+整型值)”變量。它是雙目運算,需要一個指針和一個整型值。例如:

((int*)2000)[4] <=> *((int*)2000 + 4)

是一個int型的變量。

再如,若a是int[100]型數(shù)組名,那么

a[4] <=> *(a + 4)

是一個int型的變量,也就是a的第4號元素。請不必為先有雞——指針a與4做[ ]運算為a[4],還是先有蛋——數(shù)組a的第4號元素為a[4]所困,只需記?。合聵俗兞烤褪亲隽讼聵诉\算所得的變量。再如

"Hello"[4] <=> *("Hello"+4)

是一個char型的變量,存儲的是字符'o'。

2.3 指針的求取運算

& —— 是取指針運算符。把它置于變量前,算出的是該變量的指針,這個指針以變量的類型為基類型,以變量內(nèi)存的首字節(jié)地址為其指針地址。

例如,有如下變量定義,并假設(shè)它們的內(nèi)存首字節(jié)地址分別為:1000,1002,1003

short v1; char v2; struct tag v3;

那么,&v1、&v2、&v3的值分別為:

(short *)1000 (char *)1002

(struct tag *)1003

2.4 強制指針類型轉(zhuǎn)換運算

(指針類型)——跟其他強制類型轉(zhuǎn)換運算符的構(gòu)成一樣,比如(short *)、(char *)……都是這樣的運算符。把它們置于z指針或整型值之前,結(jié)果就是所要類型的指針。例如

(int *)"Hello"

就能從char*型的指針轉(zhuǎn)換成int*型的指針,指針地址不變。再如,曾經(jīng)寫出的指針

(short *)k (long *)(2*k+1)

(char *)2000 (struct tag *)3000

其實分別為:

對k的值做了(short *)運算

對2*k+1的值做了(long *)運算

對2000做了(char *)運算

對3000做了(struct tag *)運算

作為類比

-k,-(2*k+1),-2000

分別為:對k、2*k+1和字面整數(shù)2000的值做了求負運算,等。

后三個種類分別是加減運算、關(guān)系運算和邏輯運算

2.5 指針的加減運算

i) 指針增減值:指針作為第一運算對象和整型值相加減。結(jié)果仍為同類型的指針,但指針地址加減了整型值的倍數(shù),具體幾倍要看基類型對應(yīng)幾個字節(jié)。例如

(short *)2000+10等于(short *)(2000+10*2) 即(short *)2020

ii) 兩指針相減:類型相同的指針可以相減。結(jié)果的類型,若small模式為short,若large模式為long,得到的整型值等于指針地址之差除以基類型的字節(jié)數(shù)。例如

(long *)2000 – (long *)1800

=> (2000 – 1800) / 4 => 50

所以計算結(jié)果,或是50或是50L。

數(shù)組的兩個元素的指針與它倆的下標之間的關(guān)系,用這類運算確定極為方便。

比如a是任意數(shù)組,i和j是兩個下標,那么

&a[i] + j - i = &a[j]

&a[j] - &a[i] = j - i

特別地

a + i = &a[i] &a[i] - a = i

2.6 指針的比較運算

相同類型的指針可做比較運算。計算結(jié)果不是0就是1。比較僅僅使用指針地址。例如,

(int *)3 > (int *)2

的結(jié)果為1。

如果使用減法,把(int *)3 – (int *)2的結(jié)果為0作為(int*)3等于(int*)2的依據(jù),就犯錯誤了!特別地,整數(shù)0可以跟任何類型的指針做比較。

2.7 指針的邏輯運算

不同類型的指針以及整型值之間,可以做邏輯運算,計算結(jié)果非0即1。指針的邏輯“真”、“假”僅以指針地址是否為0作為依據(jù)。

例如,假設(shè)有int* pi, v; char* pc;并且都存儲了適當?shù)闹怠D敲?/p>

pi && v || pc

是正確的表達式。若它們存儲的分別為(int*)0、10、(char*)20,則上式的計算過程為:

((int*)0 && 10) || pc => 0 || (char*)20 => 1

即結(jié)果為“真”。

指針運算和下標運算表明,C語言中存在著純屬表達式形式的變量。使用上,這種表達式的整體相當于變量名。

正是基于指針能夠通過運算得到變量這一事實,便有了較直觀的說法:指針指向變量。甚至用箭頭來圖示“指向”,方法如下圖所示。其中假設(shè)a是一維數(shù)組、v是變量,p和q是指針變量,分別存儲了指針&v和a(言下之意,p、q有適合的指針類型)。

注:箭頭起始方框內(nèi)是存儲的指針,方框外給出的是變量名或相當于變量名的表達式。

必須心中有數(shù),盡管指針值是多少并不會妨礙用指針運算或下標運算得到變量,然而這樣得到的變量,其內(nèi)存是否靠得住并沒有論及。這和《建筑施工手冊》僅介紹了房屋建造的方法,至于私搭亂建將產(chǎn)生什么后果并未涉及一樣。都需另立專題說明。

2.8 指針類型的自動轉(zhuǎn)換

1) 值,任何類型的指針值,甚至整型值,都可以作為賦值表達式的右端,最后將自動轉(zhuǎn)化為賦值運算符左端指針變量的類型。

2) 減,硬讓不同類型的指針做減法時,減號右邊的指針將自動轉(zhuǎn)化為左邊的指針類型。

3) 較,指針也可以硬性地和任何其他類型的指針,甚至整型值做比較,而利用的僅僅是指針地址或整型值。

盡管以上三條行得通,但編譯系統(tǒng)還是有可能給出警告信息,以表明那么做是不希望的。作為例子,特給出以下3個式子的計算。

(short*)50 – 10

=> (short*)(50 – 10*2)

=> (short*)30

(short*)50 – (char*)10

=> (short*)50 – (short*)10

=> (50 – 10)/2 => 20

(char*)50 – (short*)10

=> (char*)50 – (char*)10

=> (50 – 10)/1 => 40

3 相關(guān)運算的優(yōu)先級與結(jié)合性

這里僅討論前四個種類的運算符:*、[ ]、&和強制指針類型轉(zhuǎn)換運算符。

其中,“[]”的優(yōu)先級最高,且結(jié)合性從左到右;“*”、“&”以及“(指針類型)”運算符的優(yōu)先級次之,等同于其他單目運算符,且它們的結(jié)合性也相同,都是從右到左。順便提一下,具備這種結(jié)合性的雙目運算符只有賦值運算符“=”。

C語言對表達式的計算求解依賴于運算符的優(yōu)先級和結(jié)合性。作為練習,在此給出7例,并做了適度推導。

1) (long*)(short *)2000 = (long *)2000

因 (short *)2000 的指針地址為2000,配上最后運算生效的強制類型轉(zhuǎn)化運算符 (long*),必然等于右側(cè)。

2) (short *)2000 + 10

≠ (short *)(2000 + 10)

因 (short *)2000 + 10 = (short *)2020 而 (short *) (2000 +10) = (short *)2010

3) *((short *)2000 + 5)

<≠> *(short *)2000 + 5

因 *( (short *)2000 + 5 ) <=>

*( (short *)2010 )

再由于“(short *)”與指針運算符“*”的優(yōu)先級相同,結(jié)合性“從右到左”,所以括號可以去掉,即為:

* (short *)2010

此乃變量,可以給它存儲值或從中得到值。而

*(short *)2000+5

=> (*(short *)2000) + 5 => 變量 + 5

只能算得一個值

【引申】如果把指針 (short *)2000用指針變量p替換,相當于

*(p + 5) <≠> *p + 5

4) (long *)(2*k+1) ≠> (long *)2*k+1

因“(long *)”的優(yōu)先級高于乘法運算符“*”,故

(long *)2*k+1 => ((long *)2)*k+1

=> 指針* k + 1,

可是指針不能做乘法運算。

5) ((short *)2000)[5]

≠> (short *)2000[5]

因“[ ]”的優(yōu)先級高于“(int *)”,故

(int *)2000[5] => (int *)( 2000[5] )

可是整型值與整型值之間不能做下標運算。

6) &*(int *)2000 = (int *)2000

因 &*(int *)2000 => & (* (int *)2000)

而變量 * (int *)2000 的首地址為2000,基類型為int,取指針的結(jié)果必然為:(int *)2000

【引申】如果把指針 (int *)2000用指針變量p替換,相當于

&*p = p

7) *&*(int *)2000 <=> *(int *)2000

因 *&*(int *)2000 <=>

*(&* (int *)2000) <=> *( (int *)2000)

<=> * (int *)2000

【引申】如果把變量 *(int *)2000用變量v替換,相當于

*&v <=> v

從后兩例可見,“&”與“*”是一對互逆運算符。

補充說明:1)嚴格地說,C語言沒有字面負整數(shù);2)本文僅就Turbo C 2.0開發(fā)環(huán)境而言。

參考文獻:

[1] 王恒濱,閆東升. 關(guān)于C語言指針定義的討論[J]. 遼寧財專學報,2004.

[2] 傅育熙等譯. 程序設(shè)計語言:設(shè)計與實現(xiàn)(第四版)[M]. 北京:電子工業(yè)出版社,2001.

[3] 金戈,湯凌等譯. 代碼大全(第二版)[M]. 北京:電子工業(yè)出版社,2006.

猜你喜歡
指針C語言教學內(nèi)容
新冠疫情期間小學信息技術(shù)在線教學內(nèi)容的選擇和實踐
“C語言程序設(shè)計”課程混合教學探索
郊游
基于C語言的計算機軟件編程技術(shù)探究
中職C語言單片機課堂教學中的趣味性探討
為什么表的指針都按照順時針方向轉(zhuǎn)動
計算機原理中C語言的應(yīng)用價值
等差數(shù)列教學內(nèi)容的深化探究
淺析C語言指針
梧州市| 和田县| 东乡| 武宁县| 尚义县| 巢湖市| 阳高县| 上饶市| 本溪| 永嘉县| 仁化县| 喀什市| 天祝| 屏东市| 大同市| 依兰县| 阜阳市| 青川县| 新和县| 邮箱| 盈江县| 临夏县| 壤塘县| 榕江县| 新津县| 肇州县| 阿尔山市| 察雅县| 虹口区| 花莲市| 牡丹江市| 定日县| 北票市| 苍梧县| 隆林| 松原市| 兴宁市| 滦南县| 朝阳县| 麻阳| 平塘县|