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

?

C語(yǔ)言教學(xué)中的幾個(gè)常見問題

2009-06-20 08:45
計(jì)算機(jī)教育 2009年10期
關(guān)鍵詞:C語(yǔ)言程序設(shè)計(jì)教學(xué)

黃 宇

文章編號(hào):1672-5913(2009)10-0096-03

摘要:作者在多年的C語(yǔ)言教學(xué)過程中,對(duì)學(xué)生中經(jīng)常遇到的問題進(jìn)行了一些總結(jié)。本文就學(xué)生中經(jīng)常遇到的5個(gè)帶有普遍性的問題,通過C程序示例進(jìn)行了分析,指出了出現(xiàn)錯(cuò)誤的原因,給出了改正的方法。

關(guān)鍵詞:C語(yǔ)言;程序設(shè)計(jì);教學(xué)

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

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

1引言

隨著計(jì)算機(jī)應(yīng)用技術(shù)的普及,大學(xué)中很多專業(yè)都開設(shè)了計(jì)算機(jī)編程課程。在非計(jì)算機(jī)專業(yè)中,大多以教授C語(yǔ)言編程為主。本人長(zhǎng)期從事對(duì)非計(jì)算機(jī)專業(yè)學(xué)生的C語(yǔ)言編程課的教學(xué)工作,在長(zhǎng)期的教學(xué)實(shí)踐中,發(fā)現(xiàn)了一些學(xué)生在編程中經(jīng)常會(huì)遇到的問題。在此,就幾個(gè)典型的常見問題,展開一些探討。這些問題的解決,對(duì)于更深入的理解C語(yǔ)言,將起到一定的幫助作用。

2幾個(gè)常見問題

2.1無符號(hào)數(shù)運(yùn)算問題

大家知道,在C語(yǔ)言中,不同類型的數(shù)據(jù)一起運(yùn)算時(shí)是按照隱式類型轉(zhuǎn)換的規(guī)則進(jìn)行的,也就是將兩個(gè)類型不一致的數(shù)據(jù)首先轉(zhuǎn)換成一致的,然后再進(jìn)行運(yùn)算。其轉(zhuǎn)換的基本原則有兩點(diǎn),一是小數(shù)據(jù)類型向大數(shù)據(jù)類型轉(zhuǎn)換,二是有符號(hào)類型向無符號(hào)類型轉(zhuǎn)換。比如,當(dāng)一個(gè)float類型數(shù)據(jù)和一個(gè)double類型的數(shù)據(jù)進(jìn)行運(yùn)算時(shí),就是首先將float類型的數(shù)據(jù)轉(zhuǎn)換成double類型的數(shù)據(jù),然后再進(jìn)行運(yùn)算;而當(dāng)一個(gè)int類型的數(shù)據(jù)和一個(gè)unsigned int類型的數(shù)據(jù)進(jìn)行運(yùn)算時(shí),則首先把int類型的數(shù)據(jù)轉(zhuǎn)換為unsigned int類型的數(shù)據(jù),然后再進(jìn)行運(yùn)算。對(duì)于第一種情況,一般不會(huì)遇到問題,但是對(duì)于第二種情況,初學(xué)者往往注意不到這種轉(zhuǎn)換中可能會(huì)隱含的問題,導(dǎo)致程序運(yùn)行結(jié)果出現(xiàn)與自己設(shè)想不一致的情況。

下面給一個(gè)具體的例子:

#include

int main()

{

unsigned int n = 1;

int m = -1;

if (m < n)printf("m < n");

else printf("m >= n");

return 1;

}

在這段程序中,n = 1,m = -1,顯然應(yīng)該是m= n。初學(xué)者遇到這種情況,往往百思不得其解,最終往往會(huì)歸咎于是不是系統(tǒng)出現(xiàn)了問題。

為什么會(huì)出現(xiàn)這種情況呢?這是因?yàn)閚是unsigned int類型的,而m是int類型的,在m和n進(jìn)行比較運(yùn)算時(shí),由于二者的類型不一致,首先要進(jìn)行類型轉(zhuǎn)換。按照C語(yǔ)言隱式類型轉(zhuǎn)換規(guī)則,有符號(hào)類型的int轉(zhuǎn)換為無符號(hào)類型的unsigned int。這樣,m(=-1)中的符號(hào)位被當(dāng)成了“數(shù)字”進(jìn)行轉(zhuǎn)換,有符號(hào)的-1成為了無符號(hào)的4294967295(四字節(jié)的情況下。如果是二字節(jié)的則是65535)。而4294967295當(dāng)然要大于1了,所以就有了以上的運(yùn)行結(jié)果。

不單單是在比較運(yùn)算中會(huì)出現(xiàn)這種情況,在其他運(yùn)算中,比如加減乘除等,也一樣會(huì)有類似的情況出現(xiàn)。所以,當(dāng)有符號(hào)和無符號(hào)的數(shù)據(jù)混合運(yùn)算時(shí),一定要注意這個(gè)問題,除非特殊情況,應(yīng)盡量避免有符號(hào)和無符號(hào)的混合運(yùn)算。

2.2計(jì)算數(shù)組的長(zhǎng)度

在C語(yǔ)言中,操作符sizeof( )可以計(jì)算一個(gè)類型或者一個(gè)變量所占用的字節(jié)數(shù)。比如:sizeof(int)或者sizeof(x)(假定x是int類型的),當(dāng)一個(gè)整數(shù)占用4個(gè)字節(jié)時(shí),就可以得到4的結(jié)果。

再比如,一個(gè)整數(shù)數(shù)組:int a[8];

可以通過sizeof(a)/sizeof(int)得到數(shù)組a的元素個(gè)數(shù)。因?yàn)閟izeof(a)得到的是a數(shù)組占用的總字節(jié)數(shù),除以每個(gè)int所占用的字節(jié)數(shù)sizeof(int),就是該數(shù)組的長(zhǎng)度。

由于很多情況下需要知道一個(gè)數(shù)組的長(zhǎng)度,比如在對(duì)一個(gè)數(shù)組排序時(shí),因此,有些初學(xué)者就利用sizeof在函數(shù)中計(jì)算數(shù)組的長(zhǎng)度。舉例如下:

mysort(int a[])

{

int len;

len = sizeof(a)/sizeof(int); //得到數(shù)組a的長(zhǎng)度

//以下對(duì)a進(jìn)行排序

}

但是往往會(huì)發(fā)現(xiàn),這樣的結(jié)果并不正確,len經(jīng)常得到的是1(假定是32位系統(tǒng),一個(gè)整數(shù)占4個(gè)字節(jié))。這又是為什么呢?

這個(gè)問題,與C語(yǔ)言中數(shù)組參數(shù)的傳遞方式有關(guān)。在C語(yǔ)言中,當(dāng)一個(gè)數(shù)組當(dāng)作參數(shù)傳遞時(shí),數(shù)組被轉(zhuǎn)換為指針。在上面的例子中,無論你在函數(shù)定義是mysort(int a[])還是mysort(int a[100]),在函數(shù)內(nèi)部,a均被轉(zhuǎn)換成int *a類型,與定義mysort(int *a)是一致的。因此,在函數(shù)內(nèi)部,當(dāng)計(jì)算sizeof(a)時(shí),實(shí)際上計(jì)算的是sizeof(int *)。因此,當(dāng)作為形參時(shí),無論你的mysort(int a[N])定義中,有無N,或者N是多大,sizeof(a)得到的都是4(假定在32位系統(tǒng)中)。

因此,在一個(gè)函數(shù)內(nèi)部,是無法得到一個(gè)數(shù)組參數(shù)的長(zhǎng)度的,其長(zhǎng)度只能通過參數(shù)進(jìn)行傳遞。所以,上述的排序函數(shù)應(yīng)該定義成如下的形式:

mysort(int a[], int len)

{

//以下對(duì)a進(jìn)行排序

}

2.3常量字符串問題

在學(xué)習(xí)完字符串的操作之后,同學(xué)們往往會(huì)編寫一些簡(jiǎn)單的練習(xí)程序,這時(shí)經(jīng)常會(huì)遇到一些“莫名其妙”的情況,使得程序不能正確運(yùn)行。

比如下面這個(gè)程序,非常簡(jiǎn)單,就是把字符串"abcde"中的'a'換成'A':

int main()

{

char *p = "abcde";

p[0] = 'A';

return 1;

}

程序編譯沒有問題,一運(yùn)行就出現(xiàn)錯(cuò)誤。這是為什么呢?

在這個(gè)程序中,字符串"abcde"是一個(gè)常量,指針p指向了這個(gè)常量。而“常量”顧名思義是不能修改的,而該程序試圖通過指針p修改一個(gè)常量字符串,導(dǎo)致運(yùn)行錯(cuò)誤。

把程序修改如下,就沒有問題了:

int main()

{

char p[] = "abcde";

p[0] = 'A';

return 1;

}

這是因?yàn)閜是一個(gè)字符數(shù)組,并通過初始化的方法對(duì)該數(shù)組進(jìn)行了賦值。雖然字符數(shù)組p也是一個(gè)字符串,但是p不是常量,可以修改,因此就不會(huì)出現(xiàn)運(yùn)行錯(cuò)誤了。

同樣,如果是這樣,也不會(huì)出現(xiàn)錯(cuò)誤:

int main()

{

char p[] = "abcde";

char *q = p;

q[0] = 'A';

return 1;

}

因?yàn)樵谶@里q指向是字符數(shù)組p,而不是字符串常量"abcde"。

2.4文件結(jié)束判斷問題

在C語(yǔ)言中,函數(shù)feof( )可以判斷文件結(jié)束,但是初學(xué)者在使用feof( )時(shí),經(jīng)常會(huì)犯錯(cuò)誤。請(qǐng)看下面這個(gè)例子,該程序?qū)崿F(xiàn)將文件a.txt拷貝到b.txt的功能,通過feof判斷a.txt是否結(jié)束,在結(jié)束之前,每次讀一個(gè)字符,并寫到b.txt中。程序如下:

int main()

{

FILE *pi, *po;

char c;

pi = fopen("a.txt", "rb");

po = fopen("b.txt", "wb");

while (!feof(pi))

{

c = fgetc(pi);

fputc(c, po);

}

fclose(pi);

fclose(po);

return 1;

}

程序很簡(jiǎn)單,看似沒有什么錯(cuò)誤。但是這里卻隱含了一個(gè)初學(xué)者經(jīng)常會(huì)犯的錯(cuò)誤。運(yùn)行一下該程序,就會(huì)發(fā)現(xiàn)在b.txt的最后,會(huì)“奇怪”地多出了一個(gè)字符。

問題出現(xiàn)在什么地方呢?主要是對(duì)feof的認(rèn)識(shí)有誤造成的。

仔細(xì)看一下feof的功能,會(huì)發(fā)現(xiàn)當(dāng)讀完了最后一個(gè)字符后,feof還是保持“假”,只有當(dāng)讀完了最后一個(gè)字符再試圖讀文件時(shí),feof才為真。也就是說,feof判斷是否到達(dá)文件尾比實(shí)際情況要“晚”一步。按照上面的程序,當(dāng)fgetc從a.txt中讀完了最后一個(gè)字符后,feof并不馬上為真,還要循環(huán)再讀一次a.txt,并通過fputc函數(shù)將這次得到的結(jié)果(在字符c中)寫入到b.txt中,造成了b.txt中多了一個(gè)字符。而這時(shí),feof才變成了真,程序退出循環(huán)結(jié)束。

明白了這一點(diǎn),程序按照如下方式增加一個(gè)if語(yǔ)句就可以了:

int main()

{

FILE *pi, *po;

char c;

pi = fopen("a.txt", "rb");

po = fopen("b.txt", "wb");

while (!feof(pi))

{

c = fgetc(pi);

if (feof(pi)) break;//新增加的一個(gè)判斷

fputc(c, po);

}

fclose(pi);

fclose(po);

return 1;

}

2.5結(jié)構(gòu)體的大小問題

通過sizeof可以計(jì)算一個(gè)結(jié)構(gòu)體占用的字節(jié)數(shù),比如下面一段程序是計(jì)算結(jié)構(gòu)體S所占的字節(jié)數(shù)。程序的輸出應(yīng)該是多少呢?

int main()

{

struct S

{

char a;

int n;

};

int n;

n = sizeof(struct S);

printf("%d", n);

return 1;

}

char占1個(gè)字節(jié),int占4個(gè)字節(jié),初學(xué)者往往會(huì)回答S長(zhǎng)度是5。但是一運(yùn)行程序,發(fā)現(xiàn)輸出的結(jié)果卻是8。見到這樣的結(jié)果,初學(xué)者往往又不得其解,不知為什么會(huì)這樣。

這里涉及的就是所謂的地址對(duì)齊的問題,編譯程序,在默認(rèn)的情況下,會(huì)按照一定的原則,比如讓寬度為2的基本數(shù)據(jù)類型(short等)都位于能被2整除的地址上,讓寬度為4的基本數(shù)據(jù)類型(int等)都位于能被4整除的地址上等等,這樣做的原因是為了加快程序的運(yùn)行速度。也就是說,對(duì)結(jié)構(gòu)體進(jìn)行了一定的填充,使得它的成員的地址滿足一定的要求。關(guān)于如何對(duì)齊問題涉及的內(nèi)容比較多,這里就不詳細(xì)解釋了,有興趣的讀者可以參考有關(guān)計(jì)算機(jī)組成原理方面的書。

3結(jié)束語(yǔ)

我們?cè)贑語(yǔ)言教學(xué)過程中,經(jīng)常會(huì)遇到學(xué)生提出的各種問題,有些問題是個(gè)別性的,有些問題則是普遍性的,從學(xué)生遇到的最多的問題中,整理出了這5個(gè)具有普遍性的問題,希望對(duì)有關(guān)C語(yǔ)言的教與學(xué)能起到一定的幫助。

參考文獻(xiàn):

[1] 薛勝軍. 計(jì)算機(jī)組成原理[M]. 武漢:華中科技大學(xué)出版社,2000.

[2] 王誠(chéng), 劉衛(wèi)東,宋佳興. 計(jì)算機(jī)組成與設(shè)計(jì)[M]. 3版. 北京:清華大學(xué)出版社,2008.

[3] 嚴(yán)蔚敏,吳偉民.數(shù)據(jù)結(jié)構(gòu)(C語(yǔ)言版)[M].北京:清華大學(xué)出版社,2006.

[4] 譚浩強(qiáng). C程序設(shè)計(jì)[M]. 北京:清華大學(xué)出版社,2006.

[5] David J. Kruglinski. Visual. C++技術(shù)內(nèi)幕[M]. 4版. 北京:清華大學(xué)出版社,2001.

[6] H.M.Deitel,P.J.Deitel. C程序設(shè)計(jì)教程[M]. 北京:機(jī)械工業(yè)出版社,2001.

猜你喜歡
C語(yǔ)言程序設(shè)計(jì)教學(xué)
基于OBE的Java程序設(shè)計(jì)個(gè)性化教學(xué)研究
項(xiàng)目化教學(xué)在Python程序設(shè)計(jì)課程中的應(yīng)用
C++程序設(shè)計(jì)課程教學(xué)改革研究
醫(yī)學(xué)專業(yè)“Python程序設(shè)計(jì)”課程教學(xué)改革總結(jié)與思考
“C語(yǔ)言程序設(shè)計(jì)”課程混合教學(xué)探索
基于C語(yǔ)言的計(jì)算機(jī)軟件編程技術(shù)探究
中職C語(yǔ)言單片機(jī)課堂教學(xué)中的趣味性探討
“自我診斷表”在高中數(shù)學(xué)教學(xué)中的應(yīng)用
計(jì)算機(jī)原理中C語(yǔ)言的應(yīng)用價(jià)值
在遺憾的教學(xué)中前行