iT邦幫忙

DAY 15
3

emacs的30天學習筆記系列 第 30

懷舊C語言:1988 The C Programming Language 2nd Edition(PART II)

  • 分享至 

  • xImage
  •  

隨著習題的深入,發現這本書果然很困難,要練習的地方,比想像的還多,但實做下去就對了。

1988年,那時的主流,(到現在可能還是),能夠寫一個小的編譯器,從計算機,可以解析四則運算的數字句子,可以分出先乘除後加減,進一步,有含括號的句子,所以能把input裏的字元(char)數字(digit)從一串句子裏,一個一個分出來,是熟悉語言的主流,難怪,那時候的程式員,似乎都很會新創一個語言,因為他們就是這樣練功練上來的。

2010年之後,除了hello world之外有保留,其他的基礎幾乎不保留了,就切入這語言的強項,例如MVC, 快速的把MODEL ,VIEW, CONTROLLER建立起來,然後做一個小網站,網站建構注意的事項,讓讀者快速有產能,像這種只能做小計算機的練習,就不再出現了。反應20多年間,學習方向的不同。

像筆者這種非計算機科系畢業的,走了一圈之後,現在有一種體會:慢慢來比較快,在慢****中,才能體會因為放慢,很多細微的動作才能看得清楚!!

另一部分,是本書,和UNIX 比較有緊密的結合,所以如果老師只用WINDOWS,覺得不適應吧。
UNIX的設計,就是所有東西皆是檔案的概念,設備(device)也是檔案(file)。


第5章 指標和陣列

問題1:

Exercise 5-1. As written, getint treats a + or - not followed by a digit as a valid representation of zero. Fix it to push such a character back on the input.

這裏稍微交待一下前因後果,getint
是一個函數,會傳回數字,
輸出/輸入大概是

$ a
+123
123

$ a
-223
-223

$ a
123 45
123

$ a
123++
123

$ a
123--
123

$ a
123PPPPP
123

$ a
wer123
2008950864

$ a
01234
1234

本題的意思是說,書上的範例程式有一個bug,當你輸入123+,或是**123-**時,
getint會將傳入的字串,變成0。請修正這個bug。讓它顯示正確。

一開始是搞不懂怎麼用,試了老半天,弄懂怎麼用。

會有bug的程式如下:

#include <ctype.h>
#include <stdio.h>

#define BUFSIZE 100
#define SIZE 10
char buf[BUFSIZE]; /* buffer for ungetch */
int bufp = 0; /* next free position in buf */

int getch(void);
void ungetch(int); 
int getint(int *pn);

int main()
{
  int n = 0,  getint(int *),array[SIZE];
  for (n = 0; n < SIZE && getint(array) != EOF; n++)
    ;
    printf("%d \n\n",*array);
}


/* getint: get next integer from input into *pn */
int getint(int *pn)
{
  int c, sign;
  while (isspace(c = getch())) /* skip white space */
    ;
  if (!isdigit(c) && c != EOF && c != '+' && c != '-') {
    ungetch(c); /* it is not a number */
    return 0;
  }
  sign = (c == '-') ? -1 : 1;
  if (c == '+' || c == '-')
    c = getch();
  for (*pn = 0; isdigit(c); c = getch())
    *pn = 10 * *pn + (c - '0');
  *pn *= sign;
  if (c != EOF)
    ungetch(c);
  return c;
}

int getch(void) /* get a (possibly pushed-back) character */
{
  return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c) /* push character back on input */
{
  if (bufp >= BUFSIZE)
    printf("ungetch: too many characters\n");
  else
    buf[bufp++] = c;
}

 for (n = 0; n < SIZE && getint(array) != EOF; n++)
    ;

是作者建議的方式,確實會發生作者所說的錯誤。

可是我反覆trace了好幾次,尤其是看了作者實作的getint
基本上,回返值是最後一個char字元,而傳入的陣列,才是要做轉成數字的動作,
想了半天,覺得,上述那行,莫非是作者筆誤,

把那個感覺沒用的for 迴圈,改成

  n=getint(array);

然後,一切都正常了。

可是我沒有按題意去改寫(FIX)getint函式,只是改變呼叫的方式。

可能不同的讀者,有不同的解讀方式,這是筆者的解讀。

其中,兩個簡短的小函式,getch(),ungetch(),筆者從原書第四章,copy過來這裏,方便查閱
getch 好像把getchar再包裝一下,取得user 的input。

小結:
不知道是不是gcc的問題,得到和作者不一樣的結果,getint(待處理的字串),傳回最後一個字元。
除錯時,每個字元,是傳回ascii值,可參考http://www.asciitable.com/
1是 49,2是50,3是51,+是43
作者在getint用了一個技巧:

  for (*pn = 0; isdigit(c); c = getch())
    *pn = 10 * *pn + (c - '0');

不知道各位邦友會不會很容易一眼看出它的效果。
可以把'1','2','3'變成 數字的123。

在gdb裏,很方便印出(c - '0')的數值,兩個字元相減,得到一個數字。

所以系統程式人員的寫法,和MIS不太一樣。還好有gdb.

不知道作者怎麼會想到這樣寫,我是trace了近一個早上,才恍然大悟。

而第二題,是要把getint 改成getfloat. 筆者想,難度可能在這個式子。



上一篇
那些Web Service的往事
下一篇
Web service的好朋友:cURL
系列文
emacs的30天學習筆記38
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言