初學UNIX C時的一點小收穫 (轉)

worldblog發表於2007-08-17
初學UNIX C時的一點小收穫 (轉)[@more@]

下面是我以前寫程式碼時遇到的一個小,問題不大,但是忙活了好半天!下面我就用比較正是的方式來將這段經歷送給大家。

請在vi編輯器下編寫這段程式碼.

/*a.c*/

#include

main()

{

  int I = 0;

  while(I != 1)

  {

  scanf(“%d”, &I);

}

}

我曾經問過幾個朋友:這段程式碼有沒有問題;都說:應該沒問題吧!那麼我們來測試一下。

我們先寫一段簡單的makefile

下面在下輸入

$vi makefile

在vi編輯器下編輯下面這段程式碼

#這是一段makefile程式碼

#作用是:編譯a.c成可a

HEADERS = include/stdio.h

S = a.c

PRODUCT = a

CC = cc

$(PRODUCT):$(SOURCE)

  $(CC) -o $(PRODUCT) $(SOURCES)

編輯完成後,我們來執行makefile

$  make

  cc -o a a.c

現在一個可執行的a已經生成了,下面開始寫我們的單元測試計劃

測試編 號

輸入

輸出

測試結果

分析

1

1

跳出

:namespace prefix = o ns = "urn:schemas--com::office" />

2

2

進入下一次輸入狀態

3

1.2

跳出

4

1.9

跳出

5

0.9

進入下一次輸入狀態

6

a

進入下一次輸入狀態

$ a

1

$

邊測試邊填寫測試計劃表

測試編 號

輸入

輸出

測試結果

分析

1

1

跳出

正確

2

2

進入下一次輸入狀態

正確

3

1.2

跳出

正確

4

1.9

跳出

正確

5

0.9

進入下一次輸入狀態

正確

6

a

進入下一次輸入狀態

看樣子沒問題,還有一步就完成了,輸入一個非數值,a,回車!好像沒問題!再輸入1回車!!問題出現了!沒有退出迴圈!Ctrl+c退出吧!

$ a.out

a

1

^C$

測試編 號

輸入

輸出

測試結果

分析

1

1

跳出

正確

此程式碼有一處嚴重錯誤將不予以釋出

2

2

進入下一次輸入狀態

正確

3

1.2

跳出

正確

4

1.9

跳出

正確

5

0.9

進入下一次輸入狀態

正確

6

a

進入下一次輸入狀態

出錯

為什麼會這樣呢?出現了嚴重的,馬上。首先讓我們在scanf語句後面加上一句:

printf(“%d”, I),看一看究竟I後來發生了什麼樣的變化,然後重複編號6的測試步驟,你會發現程式執行進入了死迴圈!它在不停的列印0!也就是說scanf根本不執行了!為什麼會這樣呢?我們的scanf 去哪裡了?經過一番認真學習和聽取老師們的指導終於明白,原來是這樣的。先看下面的概念。

  scanf在發生輸入錯或者讀到了EOF,scanf立即返回,如果它讀入了一個不正確字元(如,在應是數字的地方出現了字母),它也立即返回。scanf返回它所完成的轉換的數目;如果它沒有完成任何轉換,則它返回EOF。

scanf在讀到一個換行符時才停止。除非清除換行符,否則它將保留在標準輸入裝置的緩衝區中。如果程式設計師在第二次scanf前沒有清除輸入緩衝區,則會產生錯誤的結果。

下面我們做個實驗,將程式碼改寫成以下。

#include

main()

{

  int i = 0;

   int j = 0;

  char buffer[256];

  while( i != 1 )

  {

  fgets( buffer, 256, stdin );

  printf( "****** %s ******** ", buffer );

  fflush( stdin );

  j = scanf( "%d",  &i );

   printf( "%d ",  j );

  }

編譯並執行,先輸入任意一個值,比如a;這時候列印出來的輸入緩衝區結果是a;然後再輸入一個數字,比如2,這時候scanf將返回一個1,以示輸入轉換成功,同時輸入緩衝區將會被清理,所以沒有任何值輸出。

接下來我們再試著輸入一個a,回車,這時候scanf將返回一個0,以示輸入轉換出錯,另外緩衝區中將會列印出a及回車,由此可見在接下來如果沒有對緩衝區進行fflush的話,scanf將會接受到這個在輸入緩衝區的a和回車,從而進入死迴圈!

也就是說剛才我們進行的輸入,在輸入了字母然後回車,scanf返回了一個EOF,而這個結果將會保留在緩衝區中,當下一次程式呼叫scanf時,由於這個輸入緩衝區中所記憶的錯誤,scanf將不會正確執行,從而致使I的值無法改變,從而程式成了一個死迴圈!

問題找到了,解決的方法就是在呼叫scanf之前清除緩衝區,即在其前面加上:

fflush( stdin );

/*a.c*/

#include

main()

{

  int I = 0;

  while(I != 1)

  {

  fflush( stdin );

  scanf(“%d”, &I);

}

}

這下再一次測試這段程式碼!再接下來該幹什麼幹什麼吧!


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-963478/,如需轉載,請註明出處,否則將追究法律責任。

相關文章