• 
    

    
    

      99热精品在线国产_美女午夜性视频免费_国产精品国产高清国产av_av欧美777_自拍偷自拍亚洲精品老妇_亚洲熟女精品中文字幕_www日本黄色视频网_国产精品野战在线观看 ?

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

      2009-03-17 09:14:32王恒濱
      計(jì)算機(jī)教育 2009年3期
      關(guān)鍵詞:指針教學(xué)內(nèi)容

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

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

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

      中圖分類號(hào):G642

      文獻(xiàn)標(biāo)識(shí)碼:B

      1 基本指針類型

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

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

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

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

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

      short * char * struct tag *

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

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

      ① (short *)2000

      ② (char *)2000

      ③ (struct tag *)2000

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

      1.1 指針

      指針是整型值配上指針類型,此時(shí)的整型值代表地址。例如,假設(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)指針類型星號(hào)前的類型為基類型,(2)類型后的整型值為指針地址,如下表:

      1.2 指針變量

      這種類型的變量可以用來(lái)存儲(chǔ)指針,定義指針變量要用指針類型來(lái)完成。以下寫出的都是指針變量的定義。

      short * p1; char * p2;

      struct tag * p3;

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

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

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

      p3 = (struct tag *)2000;

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

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

      (char *)2000

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

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

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

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

      注意,在星號(hào)的前后增減空格不會(huì)影響語(yǔ)義。

      1.3 輸出指針

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

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

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

      ●large模式時(shí),輸出地址的8位十六進(jìn)制數(shù)字,且兩個(gè)4位之間用冒號(hào)隔開。

      例如,

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

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

      1.4 直接代表指針

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

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

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

      1.4.2 字符串常量代表指針

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

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

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

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

      有了以上兩點(diǎn)認(rèn)識(shí),就可以這樣說(shuō),%s格式的輸出部分可以是指針值,只要指針地址處的若干字節(jié)存儲(chǔ)了恰當(dāng)?shù)淖址?。至于在輸出部分處寫的是字符串常量還是數(shù)組名,都無(wú)關(guān)緊要。

      2 基本指針的運(yùn)算

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

      2.1 指針的指針運(yùn)算

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

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

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

      再如,*"Hello"是一個(gè)char型的變量,其中存儲(chǔ)的是字符'H'。

      2.2 指針的下標(biāo)運(yùn)算

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

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

      是一個(gè)int型的變量。

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

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

      是一個(gè)int型的變量,也就是a的第4號(hào)元素。請(qǐng)不必為先有雞——指針a與4做[ ]運(yùn)算為a[4],還是先有蛋——數(shù)組a的第4號(hào)元素為a[4]所困,只需記?。合聵?biāo)變量就是做了下標(biāo)運(yùn)算所得的變量。再如

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

      是一個(gè)char型的變量,存儲(chǔ)的是字符'o'。

      2.3 指針的求取運(yùn)算

      & —— 是取指針運(yùn)算符。把它置于變量前,算出的是該變量的指針,這個(gè)指針以變量的類型為基類型,以變量?jī)?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 強(qiáng)制指針類型轉(zhuǎn)換運(yùn)算

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

      (int *)"Hello"

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

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

      (char *)2000 (struct tag *)3000

      其實(shí)分別為:

      對(duì)k的值做了(short *)運(yùn)算

      對(duì)2*k+1的值做了(long *)運(yùn)算

      對(duì)2000做了(char *)運(yùn)算

      對(duì)3000做了(struct tag *)運(yùn)算

      作為類比

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

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

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

      2.5 指針的加減運(yùn)算

      i) 指針增減值:指針作為第一運(yùn)算對(duì)象和整型值相加減。結(jié)果仍為同類型的指針,但指針地址加減了整型值的倍數(shù),具體幾倍要看基類型對(duì)應(yīng)幾個(gè)字節(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

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

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

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

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

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

      特別地

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

      2.6 指針的比較運(yùn)算

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

      (int *)3 > (int *)2

      的結(jié)果為1。

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

      2.7 指針的邏輯運(yùn)算

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

      例如,假設(shè)有int* pi, v; char* pc;并且都存儲(chǔ)了適當(dāng)?shù)闹?。那?/p>

      pi && v || pc

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

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

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

      指針運(yùn)算和下標(biāo)運(yùn)算表明,C語(yǔ)言中存在著純屬表達(dá)式形式的變量。使用上,這種表達(dá)式的整體相當(dāng)于變量名。

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

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

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

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

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

      2) 減,硬讓不同類型的指針做減法時(shí),減號(hào)右邊的指針將自動(dòng)轉(zhuǎn)化為左邊的指針類型。

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

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

      (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ùn)算的優(yōu)先級(jí)與結(jié)合性

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

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

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

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

      因 (short *)2000 的指針地址為2000,配上最后運(yùn)算生效的強(qiáng)制類型轉(zhuǎn)化運(yù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ùn)算符“*”的優(yōu)先級(jí)相同,結(jié)合性“從右到左”,所以括號(hào)可以去掉,即為:

      * (short *)2010

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

      *(short *)2000+5

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

      只能算得一個(gè)值

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

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

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

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

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

      => 指針* k + 1,

      可是指針不能做乘法運(yùn)算。

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

      ≠> (short *)2000[5]

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

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

      可是整型值與整型值之間不能做下標(biāo)運(yùn)算。

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

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

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

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

      &*p = p

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

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

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

      <=> * (int *)2000

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

      *&v <=> v

      從后兩例可見(jiàn),“&”與“*”是一對(duì)互逆運(yùn)算符。

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

      參考文獻(xiàn):

      [1] 王恒濱,閆東升. 關(guān)于C語(yǔ)言指針定義的討論[J]. 遼寧財(cái)專學(xué)報(bào),2004.

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

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

      猜你喜歡
      指針教學(xué)內(nèi)容
      垂懸指針檢測(cè)與防御方法*
      偷指針的人
      挖掘數(shù)學(xué)教學(xué)內(nèi)容所固有的美
      為什么表的指針都按照順時(shí)針?lè)较蜣D(zhuǎn)動(dòng)
      “啟蒙運(yùn)動(dòng)”一課教學(xué)內(nèi)容分析
      “清末新政”也可作為重要的教學(xué)內(nèi)容
      基于改進(jìn)Hough變換和BP網(wǎng)絡(luò)的指針儀表識(shí)別
      線性代數(shù)課程學(xué)—研—用教學(xué)內(nèi)容及模式探索
      精心設(shè)計(jì)教案 重構(gòu)教學(xué)內(nèi)容
      ARM Cortex—MO/MO+單片機(jī)的指針變量替換方法
      湖州市| 黎川县| 镇平县| 达拉特旗| 屯留县| 平利县| 成武县| 齐河县| 彭山县| 永吉县| 红桥区| 田林县| 格尔木市| 习水县| 东城区| 昌乐县| 宾阳县| 凤山县| 抚州市| 巴塘县| 溧水县| 株洲市| 孟村| 高雄县| 黄山市| 河东区| 盈江县| 德庆县| 阳城县| 洞口县| 高陵县| 和林格尔县| 白朗县| 沐川县| 岳阳县| 南康市| 红桥区| 阜新市| 临城县| 清涧县| 馆陶县|