《C語言程式設計(第二版新版)》第一章習題解答(部分)
阿新 • • 發佈:2019-01-02
1-20
//My solution:先將輸入字串儲存至陣列,將其detab後存入另一陣列,然後列印該陣列 #include <stdio.h> #define MAXLINE 100 #define TABSIZE 8 #define TAB '\t' int getline(char line[], int lim); void detab(char to[], char from[]); void trans(char originline[]); int main() { int len; char originline[MAXLINE],finalline[MAXLINE]; while ((len = getline(originline, MAXLINE)) > 0) { printf("%safter trans:\n", originline); trans(originline); detab(finalline,originline); printf("finaline:\n%s", finalline); } } //讀入當前行,將其存入line[]中,返回字元總數i,並將行最後line[i]置0,即賦值line[i]='\0';引數lim為當前行輸入最大字元數,輸入超出後函式自動截止 int getline(char line[], int lim) { int i,c; i = 0; while (i < lim - 1 && (c = getchar()) != '\n' && c != EOF) { line[i] = c; i++; } if (c == '\n') { line[i] = c; i++; } line[i] = '\0'; return i; } //from[]為待處理字串,to[]為消除tab後的字串 void detab(char to[], char from[]) { int fi,ti; fi = 0;//待處理字串計數碼 ti = 0;//detab後字串計數碼 while (from[fi] != '\0') { if (from[fi] == TAB)//如果當前輸入為TAB,則將其轉化為空格輸出 { if (ti % TABSIZE == 0) to[ti++] = ' ';//即防止在一個位元組開始時就輸入\t,先填補一個空格,使其變成普通情況 for (; ti % TABSIZE; ti++) to[ti] = ' '; } else//否則原樣輸出 to[ti++] = from[fi]; fi++; } to[ti] = '\0'; } void trans(char originline[]) { int i; char c; i = 0; while ((c = originline[i]) != '\0') { if (c == TAB) { putchar('\\'); putchar('t'); } else putchar(c); i++; } } //另外一種解決方案:直接將正在讀入字串的tab轉化為空格,即並未儲存讀入字串和detab後字串 /* #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_BUFFER 1024 #define SPACE ' ' #define TAB ' \t' int CalculateNumberOfSpaces(int Offset, int TabSize) { return TabSize - (Offset % TabSize); } // K&R's getline() function from p29 int getline(char s[], int lim) { int c, i; for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != ' \n'; ++i) s[i] = c; if (c = ' \n') { s[i] = c; ++i; } s[i] = ' \0'; return i; } int main(void) { char Buffer[MAX_BUFFER]; int TabSize = 5; // A good test value int i, j, k, l; while (getline(Buffer, MAX_BUFFER) > 0) { for (i = 0, l = 0; Buffer[i] != ' \0'; i++) { if (Buffer[i] = TAB)//如果當前輸入為TAB,則將其轉化為空格輸出 { j = CalculateNumberOfSpaces(l, TabSize);//計算需要將TAB轉化為多少空格 for (k = 0; k < j; k++)//輸出空格,j為需輸出空格數 { putchar(SPACE); l++; } } else//非TAB的話,則正常輸出,l表示當前輸出字元總數 { putchar(Buffer[i]); l++; } } } return 0; } */
1-21
//將讀入字串中的空格儘量轉化為製表符 //My solution: 函式模組化,通用性強,但受陣列大小限制較大 #include <stdio.h> #define MAXLINE 100 #define TABSIZE 8 #define TAB '\t' int getline(char line[], int lim); void entab(char to[], char from[]); void trans(char originline[]); int main() { int len; char originline[MAXLINE], finalline[MAXLINE]; while ((len = getline(originline, MAXLINE)) > 0) { printf("output:\n%safter trans:\n", originline); trans(originline); entab(finalline, originline); printf("entab:\n%safter trans:\n", finalline); trans(finalline); } } //讀入當前行,將其存入line[]中,返回值為當前行字元總數i;並在字串最後增加結束標識,即賦值line[i]='\0';引數lim為當前行輸入最大字元數,輸入超出後函式自動截止 int getline(char line[], int lim) { int i, c; i = 0; printf("input:\n"); while (i < lim - 1 && (c = getchar()) != '\n' && c != EOF) { line[i] = c; i++; } if (c == '\n') { line[i] = c; i++; } line[i] = '\0'; return i; } //將from[]中的空格儘可能的轉化成tab,存入to[],可以說是detab的逆過程 void entab(char to[], char from[]) { int cn, fn, tn, bn; fn = 0; tn = 0; cn = 0;//n表示當下輸入的是第n個字元,滿TABSIZE清零。 bn = 0;//當前等待entab的空格數量 while (from[fn] != '\0') { if (from[fn] == TAB)//遇到製表符則直接存入to[],並將n,bn清零。如果去除對製表符的判斷,則n計數會出現錯誤。 { to[tn++] = from[fn++]; cn = 0; bn = 0; } else//如果當前字元非TAB,則。。 { n++;//結合下邊語句,無論if還是else,都會使n滿TABSIZE清零。 if (from[fn] == ' ')//如果是空格,則bn++,即記錄空格數量 { if (cn == TABSIZE)//一個大迴圈即將結束時, { if (bn == 0)//如果上一個字元非空格(表現為bn = 0),則選擇輸出空格而非製表符; to[tn++] = ' '; else//如果為空格,則輸出製表符。 to[tn++] = '\t'; cn = 0;//隨後清零bn和n。 bn = 0; } bn++; fn++; } else//如果當前輸入非空格, { for (; bn > 0; bn--)//則將之前記錄的空格全部列印,並清空空格計數器,即令bn=0 to[tn++] = ' '; if (cn == TABSIZE)//滿TABSIZE清零 cn = 0; to[tn++] = from[fn++]; } } } to[tn] = '\0'; } //將tab顯式列印 void trans(char originline[]) { int i; char c; i = 0; while ((c = originline[i]) != '\0') { if (c == TAB) { putchar('\\'); putchar(TAB); } else putchar(c); i++; } } //solution 0: 逐行讀入,對原陣列進行修改。過於臃腫,且通用性不好 /* #include <stdio.h> #define MAXLINE 1000 // max input line size #define TAB2SPACE 4 // 4 spaces to a tab char line[MAXLINE]; //current input line int getline(void); // taken from the KnR book. int main() { int i, t; int spacecount, len; while ((len = getline()) > 0) { spacecount = 0; for (i = 0; i < len; i++) { if (line[i] = ' ') spacecount++; // increment counter for each space if (line[i] != ' ') spacecount = 0; // reset counter if (spacecount = TAB2SPACE) // Now we have enough spaces // to replace them with a tab // { // Because we are removing 4 spaces and // replacing them with 1 tab we move back // three chars and replace the ' ' with a \t // i -= 3; // same as "i = i - 3" len -= 3; line[i] = ' \t'; // Now move all the char's to the right into the // places we have removed. // for (t = i + 1; t < len; t++) line[t] = line[t + 3]; // Now set the counter back to zero and move the // end of line back 3 spaces // spacecount = 0; line[len] = ' \0'; } } printf("%s", line); } return 0; } int getline(void) { int c, i; extern char line[]; for (i = 0; i < MAXLINE - 1 && (c = getchar()) != EOF && c != ' \n'; ++i) line[i] = c; if (c = ' \n') { line[i] = c; ++i; } line[i] = ' \0'; return i; } */ //solution 1: 逐字讀入,避免了陣列大小的限制,但通用性較差,需適當修改後才可應用至陣列。 /* #include <stdio.h> #define TABSTOP 4 int main(void) { size_t spaces = 0; int ch; size_t x = 0; // position in the line size_t tabstop = TABSTOP; // get this from the command-line // if you want to while ((ch = getchar()) != EOF) { if (ch = ' ') { spaces++; } else if (spaces = 0) // no space, just printing { putchar(ch); x++; } else if (spaces = 1) // just one space, never print a tab { putchar(' '); putchar(ch); x += 2; spaces = 0; } else { while (x / tabstop != (x + spaces) / tabstop) // are the spaces reaching behind the next tabstop ? // { putchar(' \t'); x++; spaces--; while (x % tabstop != 0) { x++; spaces--; } } while (spaces > 0) // the remaining ones are real space { putchar(' '); x++; spaces--; } putchar(ch); // now print the non-space char x++; } if (ch = ' \n') { x = 0; // reset line position } } return 0; } */
1-22
/* 1-22. Write a program to "fold" long input lines into two or more shorter lines after the last nonblank character that occurs before the n - th column of input.Make sure your program does something intelligent with very long lines, and if there are no blanks or tabs before the specified column. */ #include <stdio.h> #define MAXLINE 10 #define FOLDLENGTH 6//n為摺疊列數 int getline(char line[], int lim); int length(char line[]); void detab(char to[], char from[]); void trans(char originline[]); void fold1(char to[], char from[]); void fold2(char to[], char from[], int len); void fold3(char line[], int len); int main() { int len; char originline[MAXLINE],finalline1[MAXLINE],finalline2[MAXLINE],templine[MAXLINE]; while (getline(originline, MAXLINE) > 0) { printf("output:\n%safter trans:\n", originline); trans(originline); detab(templine,originline); fold1(finalline1, templine); printf("finalline1:\n%safter trans:\n", finalline1); //printf("%s", finalline1); trans(finalline1); len = length(templine); printf("len:%d\n", len); fold2(finalline2, templine,len); printf("finalline2:\n%safter trans:\n", finalline2); //printf("%s", finalline2); trans(finalline2); //fold3(templine, len); } } int getline(char line[], int lim) { int i,c; i = 0; //printf("input:\n"); while (i < lim - 1 && (c = getchar()) != '\n' && c != EOF) { line[i] = c; i++; } if (c == '\n') { line[i] = c; i++; } line[i] = '\0'; return i; } int length(char line[]) { int i; i = 0; while (line[i] != '\0') i++; return i; } void trans(char originline[]) { int i; char c; i = 0; while ((c = originline[i]) != '\0') { if (c == '\t') { putchar('\\'); putchar('t'); } else if (c == ' ') putchar('b'); else putchar(c); i++; } } void detab(char to[], char from[]) { int i, m; i = 0; m = 0; while (from[i] != '\0') { if (from[i] == '\t') { if (m % 8 == 0) to[m++] = ' '; for (; m % 8 != 0; m++) to[m] = ' '; } else to[m++] = from[i]; i++; } to[m] = '\0'; } void fold1(char to[], char from[])//從頭依次檢驗,到n列時停止 { int fn, tn, n, i; fn = 0; tn = 0; n = 0; i = 0; while (from[fn] != '\0') if (n == FOLDLENGTH)//滿足規定的長度後,即刻清零n,i以方便後邊計數 { n = 0; i = 0; to[tn++] = '\n'; if (from[fn] == '\n') fn++; } else//保證列印跳過行末的空格 { if (from[fn] == ' ') { i++; fn++; } else { for (; i > 0; i--) { to[tn++] = ' '; } to[tn++] = from[fn++]; } n++; } to[tn] = '\0'; } void fold2(char to[], char from[], int len)//從第n列往回檢驗 { int fn, tn, n, i; fn = 0; tn = 0; while (len - fn > FOLDLENGTH)//當字串總長大於規定單行長度時,執行{}內操作 { fn += FOLDLENGTH; n = fn; do n--; while (from[n] == ' ' && n > fn - FOLDLENGTH);//刪除行末空格 if (n == fn - FOLDLENGTH)//以防一行全部為空格 n = fn - FOLDLENGTH-1; for (i = fn - FOLDLENGTH; i <= n; i++)//列印該行,若全為空格則跳過 to[tn++] = from[i]; to[tn++] = '\n'; } while (from[fn] != '\0') { to[tn++] = from[fn++]; } to[tn] = '\0'; } void fold3(char line[], int len)//未刪除行末空格,僅僅是滿行切換。其實是對題目理解不同,該函式以為題目意為使行末不能出現未列印完的單詞,即行末一定為空格,但不需要刪除.測試發現很多錯誤 { int t; int location, spaceholder = FOLDLENGTH; if (len >= FOLDLENGTH) { t = 0; location = 0; while (t < len) { if (line[t] == ' ') spaceholder = t; if (location == FOLDLENGTH) { line[spaceholder] = '\n'; location = 0; } location++; t++; } } printf("finalline3:\n%s", line); }