典型錯誤1:指針指向
上述代碼意圖比較明顯:定義了一個int變量a和指針變量pa,并且把a(bǔ)的地址給了指針pa。接著通過鍵入給a賦值,但運(yùn)行結(jié)果如下:
其實(shí)這個問題是我們學(xué)習(xí)指針的時候的一個典型錯誤了,我們知道調(diào)用scanf函數(shù)給變量賦值時,賦值對象要為地址的形式,通常是加取址符“&”,但是這里采用的是*pa的格式,這里涉及的指針相關(guān)知識前面給大家講過,為了更好地理解本題,就再重復(fù)一下: 對于指針來說,有己址、己值、它址、它值等特點(diǎn),己址就是指針變量本身的地址,己值就是指針變量本身地址所存放的值,也就是我們通常說的指向的地址,這也正是它址,所以己值和它址意義是一樣的,而它值就是指針指向地址位置所存放的值。 而這里的*pa表示的意義就是它值a,那就是說這么寫的話下面兩行代碼是等價的:
scanf("%d", *pa);scanf("%d", a);
對比過后顯然是錯誤的,大家一眼看出a要寫成&a,這沒問題。但也有人說可以把*pa改成&pa,這樣行嗎?其實(shí)這么說的人還是對指針中己值和己址的概念沒搞清楚,&pa表示的意義是己址,即指針變量本身的地址,就是說你試圖用scanf修改指針變量本身地址上的值,而這個值原本是變量a的地址,其實(shí)就是在修改指針的指向!正確的寫法應(yīng)該這樣:
scanf("%d",pa);
pa表示a的地址,即為它址,也就是&a,所以上面寫法才與下面的等價:
scanf("%d", &a);
典型錯誤2:getchar函數(shù)
char c;while((c=getchar())!=EOF){...}
這段代碼的本意是用getchar函數(shù)讀取緩沖區(qū)字符直到結(jié)束,但是在編譯運(yùn)行時,發(fā)現(xiàn)上面幾行代碼一直報錯!邏輯上沒問題啊,那這究竟錯在哪里?讀者可以自己思考一下再往下看。
其實(shí)產(chǎn)生報錯的原因有兩點(diǎn),一個是對getchar函數(shù)理解不到位,另一個是EOF的問題。
我們首先來說說getchar函數(shù)的問題,標(biāo)準(zhǔn)庫中給出了該函數(shù)的使用說明:在它讀取一個字符后,會將其轉(zhuǎn)換為int類型返回,所以首先char c要改為int c,關(guān)于getchar的問題還沒講完,后面還要說。 我們接著來看看EOF的問題,初學(xué)者對它的理解經(jīng)常會有偏差,首先它是一個宏,定義于頭文件,為-1;其次它并不是很多人理解的文件結(jié)束符,實(shí)際上它是一個標(biāo)志位,區(qū)別于其他所有字符的存在,表示一種沒有其他字符的信號。 講到這里,我們再回到getchar函數(shù),由上面可以看出它的返回值必須是一個能包含所有字符的數(shù)據(jù)類型,方便它表示任意字符和EOF等標(biāo)志位。 因此,上面代碼的錯誤就很明顯了,可能有兩種情況:1.如果編譯器中的char是有符號的且EOF被定義為-1,而恰好有字符等于0xff,那么getchar就會提前結(jié)束。當(dāng)然,如果輸入全部是7位以下的字符,那很長時間不會有錯誤。2.如果編譯器中的char是無符號的,則實(shí)際的EOF值會被截斷,不再會識別為EOF,將會陷入無限循環(huán)。
這里肯定會有人問我們鍵入-1來模擬EOF跳出循環(huán)不行嗎?實(shí)際上是不行的,-1是有-和1兩個字符組成的,而getchar一次只能讀取一個字符,所以上述代碼EOF與從鍵盤輸入的字符無關(guān),那這豈不是只能死循環(huán)了?當(dāng)然不是,我們可以通過按鍵組合ctrl+d或者ctrl+z來指示結(jié)束,當(dāng)然,這里的按鍵組合輸入只是我們的一種約定,不應(yīng)該顯示檢查按鍵組合的值。
典型錯誤3:存儲機(jī)制
char *p = NULL;p = "hello world";strcpy(p, "hello world");
題目很簡單,就問這段代碼寫的有沒有問題,如果有,問題在哪里?
其實(shí)這個問題如果你對C語言的存儲機(jī)制非常熟悉的話,應(yīng)該是很簡單的:我們簡單分析一下,第一行代碼是沒問題的,第二行意思是讓指針p指向字符串常量,單看也沒問題,而問題就出在第三行了,它的意圖是對指針p指向地址的內(nèi)容進(jìn)行修改,當(dāng)然還用“hello world”只是為了增加點(diǎn)迷惑性而已。
上面說到了C語言的內(nèi)存機(jī)制,其實(shí)第二行代碼過后,hello world 作為字符串常量存放于內(nèi)存中的常量區(qū),且是只讀,而此時指針p存放的是字符串常量的地址,第三行代碼企圖通過strcpy修改只讀段的內(nèi)容,因此很明顯會報錯,這也是這三行代碼的問題所在了。
關(guān)于C的存儲問題,可能有的人還不太了解,那就借這個機(jī)會簡單給大家提幾句,這也是以前我寫過的問題:
一個編譯的C程序占用的內(nèi)存分為以下幾個部分:
1、棧區(qū)(stack)—也稱自動類型存儲區(qū),由編譯器自動分配釋放,存放函數(shù)的參數(shù)值,局部變量的值等,例如函數(shù)調(diào)用結(jié)束后自動釋放。
2、堆區(qū)(heap)—也稱動態(tài)分配內(nèi)存區(qū),由程序員分配釋放,從分配到程序結(jié)束為止,若不釋放,程序結(jié)束時可能由OS回收,比如malloc分配的內(nèi)存,free釋放的內(nèi)存。
3、全局區(qū)(靜態(tài)區(qū))(static)—全局變量和靜態(tài)變量的存儲是放在一塊的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域,未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域,程序結(jié)束后由系統(tǒng)釋放。
4、文字常量區(qū)—常量字符串放在這里,程序結(jié)束后由系統(tǒng)釋放。
5、程序代碼區(qū)—編譯后的程序代碼放在這里。 來看一個具體的C程序
怎么樣?問題雖然簡單,但也給我們以后寫代碼提了個醒,這種不易察覺的錯誤大家一定要小心再小心,盡量避免,就說到這里吧,感謝大家耐心閱讀!
-END-
-
C語言
+關(guān)注
關(guān)注
180文章
7632瀏覽量
141691 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4380瀏覽量
64853
原文標(biāo)題:3個C語言編程易犯的錯誤:也許你也犯過(附代碼)
文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
深入理解C語言:C語言循環(huán)控制

評論