練習1-6:
驗證表達式getchar()!=EOF的值是0還是1
#include <stdio.h> main() { int c; while(1) printf("%d",c=getchar()!=EOF); }
練習1-7:
編寫一個打印EOF值的程序
#include <stdio.h> main() { int c; c=EOF; printf("%d",c); }
練習1-8:
編寫一個統計空格、製表符與換行符個數的程序
#include <stdio.h> main() { int c,space,tab,enter; t=0,space=0,enter=0; /*remember init ,otherwise something may be wrong*/ while((c=getchar())!= '#') { if (c==' ') ++space; if(c == '\t') ++tab; if (c=='\n') ++enter; } printf("space: %d tab:%d enter:%d",space,tab,enter); }
練習1-9:
編寫一個將輸入複製到輸出的程序,並將其中連續的多個空格用一個空格代替
#include <stdio.h> main() { int c; while((c=getchar())!=EOF) { if(c==' ') { while((c=getchar()) == ' ') { continue; } printf(" "); } putchar(c); } }
練習1-10:
編寫一個將輸入複製到輸出的程序,並將其中的製表符替換爲\t,把回退符替換爲\b,把反斜槓替換爲\\。這樣可以將製表符和回退符以可見的方式像是出來。
#include <stdio.h> main() { int c; while ((c=getchar())!=EOF) { if(c =='\t') printf("\\t"); else if(c == '\b') printf("\\b"); else if(c == '\\') printf("\\"); else putchar(c); } }
練習1-11:
你準備如何測試單詞計數程序? 如果程序中存在某種錯誤,那麼什麼樣的輸入最可能發現這類錯誤?
個人答案:輸入測試滿足邊界條件的情況,比如此程序中,就分別測試換行,空格,製表符,情況下的單詞計數是否準確。順便貼下此程序:
#include <stdio.h> #define IN 1 #define OUT 0 int main() { int c, nl, nw, nc, state; state = OUT; nl = nw = nc = 0; while ((c = getchar()) != EOF) { ++nc; if(c == '\n') ++nl; if(c == ' ' || c == '\n' || c == '\t') state = OUT; else if (state == OUT){ state = IN; ++nw; } } printf("%d %d %d\n", nl, nw, nc); }
練習 1-12:
編寫一個程序,以每行一個單詞的形式打印其輸入。
#include <stdio.h> main() { int c; while((c=getchar())!=EOF) { if(c==' '||c=='\t') { while((c=getchar())==' '||c=='\t') { continue; } printf("\n"); } putchar(c); } }
個人的debug過程:
1.while((c=getchar())==' '||c=='\t') 不能寫成while((c=getchar())==' '||(c=getchar())=='\t') 因爲這樣的話,當變量滿足空格的時候,進入的話會被賦值兩次,從而導致結果缺失。
比如,當你輸入“ ss”,因爲第一次空格會進入循環,而當第一個輸入s的時候,getchar了一次,c=getchar())==' '不滿足,但是後面還有判斷'\t'的,又getchar了一次,相當於損失了一個s,所以最後答案會輸出s,而不是ss
2.putchar()不能放在if的else後面,也就是:
if(c==' '||c=='\t') { while((c=getchar())==' '||c=='\t') { continue; } printf("\n"); } else putchar(c);
原因跟1是類似的,當有空格的時候,循環會消耗一個getchar的值,也就是說,進入循環的幾次就會缺少幾個字符。
練習1-13:
編寫一個程序,打印輸入中單詞長度的直方圖
水平直方圖: (這裏假設最大單詞長度爲10)
#include <stdio.h> #define MAXLENTH 10 main() { int w,L,wl[MAXLENTH],j,i; w=0,L=0,j=0; for(i=0;i<=MAXLENTH;i++) wl[i]=0; while((w=getchar())!=EOF) { if(w==' '||w=='\n'||w=='\t') { ++wl[L]; L=0; } else ++L; } printf("\n"); for(i=1;i<=MAXLENTH;i++) { printf("%d :",i); for(j=0;j<wl[i];j++) printf("#"); printf("\n"); } }
debug:
這裏的++wl[L]不能寫成跟書上類似的++wl[L-'0'],因爲書本的案例中c是個字符,c-'0'是爲了把c轉化爲整型,(0的ascii值爲48,而字符1-9的ascii恰好爲49-57,差值恰好符合自身)而這裏L是數字不需要轉換,(L-‘0’相當於L的值減去48,可以寫成L-0,這樣就沒錯)
垂直直方圖:
思路:首先求得所有不同長度單詞的個數的最大值,這也是縱座標的最大值m,縱座標遞減,每次逐一對比每個長度單詞的個數,如果個數等於m,那麼就打印'#',否則打印空格。 我的程序中,額外加了個數組t[],這個數組是用來打tag,表明這個長度的單詞個數需要多次打印,比如說,長度爲1的單詞出現了5次,那麼在縱座標[1,5],它都需要打印‘#’
#include <stdio.h> #define MAXLENTH 10 main() { int w,L,wl[MAXLENTH],j,i,m,t[MAXLENTH]; //w:word,L:lenth,m:maxLenth// w=0,L=0,j=0,m=0; for(i=0;i<=MAXLENTH;i++) wl[i]=0,t[i]=0; while((w=getchar())!=EOF) { if(w==' '||w=='\n'||w=='\t') { ++wl[L-0]; L=0; } else ++L; } printf("\n"); for(i=1;i<=MAXLENTH;i++) { if(m<wl[i]) m=wl[i]; } printf(" ^\n |\n |\n"); for(i=m;i>0;i--) { if(i>=10) printf("%d|",i); else printf("%d |",i); for(j=0;j<=MAXLENTH;j++) { if(wl[j]==i) t[j]=1; if(t[j]==1) printf(" #"); else printf(" "); } printf("\n"); } printf(" - - - - - - - - - - - - - - - - - >\n " ); for(i=1;i<=MAXLENTH;i++) printf(" %d",i); printf("\n"); }
練習1-14:
編寫一個程序,打印輸入中各個字符出現頻度的直方圖
#include <stdio.h> #define MAXHIST 15 #define MAX 128 main() { int c,i,j; int cc[MAX]; for(i=0;i<MAX;++i) cc[i]=0; while((c=getchar())!=EOF){ if(c<MAX) ++cc[c]; } printf("\n"); for(i=1;i<=MAX;i++) { if(isprint(i)) { putchar(i); printf(" :"); for(j=0;j<cc[i];j++) printf("#"); printf("\n"); } } }
思路:
利用ascii碼的特性保存輸入字符的位置(getchar獲得的是字符的ascii編碼值,我們把這個值保存在數組對應的位置上,然後getchar對應的值可以輸出該字母。 比如:我們輸入字母a,它對應的ascii值爲97,所以我們保存在數組cc[97],然後對c[97]進行增值,打印字母用getchar打印出a),這裏因爲字符很多,所以只打印水平直方圖。 isprint函數是判斷該字符是否可以打印,用這個選項可以過濾掉那些不可打印的字符。 豎直直方圖的打印可以考慮直接打印那些非0次數的字母,這樣就可以放得下,但是這樣做就得先提取出來那些非0次數的,這裏我寫了一個簡潔的:
#include <stdio.h> #define MAXHIST 15 #define MAX 128 main() { int c,i,j,m=0; int cc[MAX],t[MAX]; for(i=0;i<MAX;++i) cc[i]=t[i]=0; while((c=getchar())!=EOF){ if(c<MAX) ++cc[c]; } printf("\n"); for(i=1;i<=MAX;i++) { if(m<cc[i]) m=cc[i]; } printf(" ^\n |\n |\n"); for(i=m;i>0;i--) { if(i>=10) { putchar(i); printf("|"); } else { putchar(i); printf(" |"); } for(j=0;j<=MAX;j++) { if(cc[j]==0) continue; if(cc[j]==i) t[j]=1; if(t[j]==1) printf(" #"); else printf(" "); } printf("\n"); } printf(" - - - - - - - - - - - - - - - - - >\n "); for(i=0;i<=MAX;i++) { if(cc[i]==0) continue; else { printf(" "); putchar(i); } } printf("\n"); }
這個程序有個問題就是要手動輸入才行,利用echo通過管道作爲輸入座標軸就不準,具體原因有待查明。
效果圖:
練習1-15:
重新編寫1.2節中的溫度轉換程序,使用函數實現溫度轉換計算。
#include <stdio.h> main() { fahr_to_celsius(0,300,20); } fahr_to_celsius(int begin,int end,int step) { int b,e,s,f,c; b=begin; e=end; s=step; f=begin; while(f<=e){ c=5*(f-32/9); printf("%d\t%d\n",f,c); f=f+s; } }
練習1-16:
修改打印最長文本行的程序的主程序main,使之可以打印任意長度的輸入行的長度,並儘可能多地打印文本
#include <stdio.h> #define MAXLINE 10 int getline1(char s[],int lim); void copy(char to[],char from[]); main() { int max,len; max=len=0; char line[MAXLINE]; char longest[MAXLINE]; while((len=getline1(line,MAXLINE))>0) if(len>max) { printf("%d",len); max=len; copy(longest,line); } if (max > 0) { printf("max= %d, the longestLine = %s",max, longest); } } int getline1(char s[],int lim) { int c,i,j; j=0; for(i=0;(c=getchar())!=EOF&&c!='\n';i++) if(i<lim-2) { s[j]=c; j++; } if(c=='\n') { s[j]=c; j++; i++; } s[j]='\0'; return i; } void copy(char to[],char from[]) { int i; i=0; while((to[i]=from[i])!='\0') ++i; }
debug:
1.一直沒很懂題意,所以參考了:http://blog.csdn.net/pollution_free/article/details/53411685
2.之所以用getline1這個函數名,是因爲getline會和stdio.h裏面的getline衝突,我的是centos6.5,gcc4.47版本請根據實際情況來
3.getline1裏面的判斷要把i<lim-2獨立出來,不能跟課本一樣寫成 i<lim-2&&(c=getchar())!=EOF的形式,因爲這樣的話i就不會再自動加1了
4.其他都是小問題,具體原理參考上面那個鏈接
練習1-17:
編寫一個程序,打印長度大於80個字符的所有輸入行
#include <stdio.h> #define MAXLINE 1000 int getline1(char s[],int lim); void copy(char to[],char from[]); main() { int max,len; max=len=0; char line[MAXLINE]; char longest[MAXLINE]; while((len=getline1(line,MAXLINE))>80) printf("max= %d, the longestLine = %s",len, line); } int getline1(char s[],int lim) { int c,i,j; j=0; for(i=0;(c=getchar())!=EOF&&c!='\n';i++) if(i<lim-2) { s[j]=c; j++; } if(c=='\n') { s[j]=c; j++; i++; } s[j]='\0'; return i; } void copy(char to[],char from[]) { int i; i=0; while((to[i]=from[i])!='\0') ++i; }
有了1-16的例子,1-17就很簡單了,參考1-16
練習1-18
編寫一個程序,刪除每個輸入行末尾的空格及製表符,並刪除完全是空格的行
#include <stdio.h> #define MAXLINE 1000 int getline1(char line[],int maxline); int remove1(char s[]); int main() { char line[MAXLINE]; while(getline1(line,MAXLINE)>0) { if(remove1(line)>0){ printf("%s",line); } } return 0; } int getline1(char s[],int lim) { int c,i,j; j=0; for(i=0;((c=getchar())!=EOF) && (c!='\n');++i){ if(i<lim-2){ s[j]=c; ++j; } } if(c=='\n'){ s[j]=c; ++j; ++i; } s[j]='\0'; return i; } int remove1(char s[]) { int i; i=0; while(s[i]!='\n'){ ++i; } --i; while(i>=0 && (s[i]==' '||s[i]=='\t')){ --i; } if(i>=0){ ++i; s[i]='\n'; ++i; s[i]='\0'; } return i; }
參考:http://blog.csdn.net/civil_chow/article/details/51533119
先讀取字符串的最後一位,然後往後推,直到遇到不是空格和製表符的字符位置,在其位置填充代表行結束的'\n'和'\0',這個就完成了刪掉末尾的空格和製表符的目的,然後打印字符長度不爲0的字符串就達到了去空行的目的。
練習1-19
編寫函數reverse(s),將字符串s中的字符順序顛倒過來,使用該函數編寫一個程序,每次顛倒一個輸入行中的字符順序
#include <stdio.h> #define MAXLINE 1000 int getline1(char line[],int maxline); int reverse1(char s[]); int main() { int len; len=0; char line[MAXLINE]; while((len=getline1(line,MAXLINE))>0) reverse1(line); } int getline1(char s[],int lim) { int c,i,j; j=0; for(i=0;((c=getchar())!=EOF) && (c!='\n');++i){ if(i<lim-2){ s[j]=c; ++j; } } if(c=='\n'){ s[j]=c; ++j; ++i; } s[j]='\0'; return i; } int reverse1(char s[]) { int i,j; i=0; while(s[i]!='\n') i++; char to[i+2]; j=0; while(i>=0) { to[j]=s[i]; i--; j++; } to[j]='\n'; j++; to[j]='\0'; printf("%s",to); }
參考:http://blog.csdn.net/civil_chow/article/details/51542081
個人解題思路:
先計算出字符串有多長,然後以賦值方式從最後一個字符往前賦值給新的字符串數組to[i+2] (這裏i+2是因爲默認最後的字符以'\n'和'\0'作爲結束標誌,也就是i+2是整個字符串長度,i是字符串最後一個真實的字符),然後打印to數組。
練習1-20:
編寫程序detab,將輸入中的製表符換成適當數目的空格,使空格充滿到下一個製表符終止的地方
參考:http://www.cnblogs.com/ningvsban/p/3774519.html
#define DETAB 8 //將製表符替換爲適當的空格,並且空格填充到下一個製表符終止位 void main(){ int c,pos,i,nbs; pos = 1; nbs = 0; while((c=getchar())!=EOF){ if(c == '\t'){ nbs = (DETAB-pos%DETAB)%DETAB+1; i = 0; for(;i<nbs;i++){ putchar(' '); } pos += nbs; }else if(c == '\n'){ putchar(c); pos = 1; nbs = 0; }else{ pos++; putchar(c); } } }
源碼抄自參考上面的鏈接,老實說,這個題目什麼意思,我現在也沒看懂..
練習1-21:
編寫程序entab,將空格串替換成最少數量的製表符和空格,但要保持單詞之間的間隔不變。假設製表符終止位的位置與練習1-20的detab程序的情況相同。當使用一個製表符或者一個空格都可以到達下一個製表符終止位時,選用哪種替換字符比較好?
思路參考:http://www.mamicode.com/info-detail-55979.html
源碼抄自:http://www.cnblogs.com/jango/archive/2013/10/25/3388574.html
#include <stdio.h> #define TABINC 8 main() { int c, nb, nt, pos; nb = 0; nt = 0; for(pos = 1; (c = getchar()) != EOF; ++pos) if(c == ' ') { if(pos % TABINC != 0) ++nb; else { nb = 0; ++nt; } }else { for( ; nt > 0; --nt) putchar('\t'); if(c == '\t') nb = 0; else for( ; nb > 0; --nb) putchar(' '); putchar(c); if(c == '\n') pos = 0; else if (c == '\t') pos = pos + (TABINC - (pos - 1) % TABINC) - 1; } }
練習1-22:
編寫一個程序,把較長的輸入行‘折’成短一些的兩行或多行,折行的位置在輸入行的第n列之前的最後一個非空格之後。要保證程序能夠只能第處理輸入行很長以及在指定的列前有空格或製表符的情況。
參考:http://www.cnblogs.com/ningvsban/p/3775383.html
#include<stdio.h> #define MAX_LEN 1000 #define TABLEN 8 #define SEPNUM 10 int getCol(char charArr[MAX_LEN],int start,int index); //主函數 void main(){ int c,i,index,nbs,pos; char charArr[MAX_LEN]; index=0; nbs = 0; while((c=getchar())!=EOF && c!='\n'){ if(c=='\t'){ //製表符替換爲空格 nbs = TABLEN-(index+1)%TABLEN; for(i=0;i<=nbs;i++){ charArr[index]=' '; index++; } }else{ charArr[index]=c; //保存字符 index++; } } index--; pos=0; while(pos<=index){ pos = getCol(charArr,pos,index); } } //該函數用於獲取n個字符,並輸出最後一個非空字符(包括該字符)之前的字符,返回緊跟該非空字符之後的空格的位置 int getCol(char charArr[MAX_LEN],int start,int index){ int end,pos,i,tmp; tmp = start+SEPNUM-1; pos = 0; if(tmp>index){ end = index; }else{ end = tmp; } for(i=end;i>=start;i--){ if(charArr[i]!=' '){ pos = i; break; } } if(pos>0){ for(i=start;i<=pos;i++){ putchar(charArr[i]); } putchar('\n'); return pos+1; }else{ //該n個字符全部爲空格的情況 return end+1; } }
ps: 還是抄的...看不懂題目要幹嘛..
練習1-23:
編寫一個刪除c語言程序中所有的註釋語句。要正確處理帶引號的字符串與字符常量。在c語言中,註釋不允許嵌套。
參考:http://blog.csdn.net/ycjnx/article/details/73649924
http://blog.csdn.net/yuezhiren/article/details/7957823
練習1-24:
編寫一個程序,查找C語言程序中的基本語法錯誤,如圓括號,方括號以及花括號不配對等。要正確的處理引號(包括單引號,雙引號)~轉移字符序列與註釋(如果讀者想把該程序編寫成完全通用的程序,難度會比較大。)
參考:http://www.cnblogs.com/jango/p/3390990.html
1-23,1-24都超出我目前能力了,打個tag,有機會回來補上