隨著習題的深入,發現這本書果然很困難,要練習的地方,比想像的還多,但實做下去就對了。
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. 筆者想,難度可能在這個式子。