第1章-导言-习题1.13-1.17

1-13

先放上自己写的程序,不论是打印水平方向的直方图还是垂直方向的直方图,前提都是先得到单词的长度,然后将该长度在数组nlenth[]对应的元素加1,也就说统计不同长度出现的次数。

 1 #include<stdio.h>
 2 
 3 #define IN 1
 4 #define OUT 0
 5 #define MAXSIZE 10
 6 
 7 /* 16/06/09 打印输入中单词长度的直方图 */
 8 main()
 9 {
10     char state = OUT;
11     char c,i;
12     int nlength[MAXSIZE];
13     char nword = 0;
14 
15     for (i = 0; i < MAXSIZE; i++) {
16         nlength[i] = 0;
17     }
18     while ((c = getchar()) != EOF) {
19         if (c == ' ' || c == '\t' || c == '\n') {
20             state = OUT;
21         }
22         else if (state == OUT) {
23             state = IN;
24         }
25         while (state == IN) {
26             nword++;
27             c = getchar();
28             if (c == ' ' || c == '\t' || c == '\n') {
29                 state = OUT;
30                 nlength[nword]++;
31                 nword = 0;
32             }
33         }
34     }
35     /* 绘制水平方向直方图 */
36     /*
37     for (i = 0; i < MAXSIZE; i++) {
38         printf("%d ", i);
39         for (j = 0; j < nlength[i]; j++) {
40             putchar('*');
41         }
42         putchar('\n');
43     }
44     */
45     /* 绘制垂直方向直方图,思路仍是一行行输出 */
46     int ncopy[MAXSIZE];
47     int ln, k, kmax;
48     /* 下面这一段代码是求数组nlength[]中的最大值 */
49     for (ln = sizeof(nlength) / sizeof(int), k = kmax = 0; k < ln; k++) {
50         if (nlength[kmax] < nlength[k])
51             kmax = k;
52     }
53     for (i = 0; i < MAXSIZE; i++) {
54         ncopy[i] = nlength[i];
55         printf("%d ", i);
56     }
57     putchar('\n');
58     for (k = 0; k < kmax; k++) {
59         for (i = 0; i < MAXSIZE; i++) {
60             if (ncopy[i] > 0) {
61                 putchar('*');
62                 putchar(' ');
63                 ncopy[i]--;
64             }
65             else {
66                 putchar(' ');
67                 putchar(' ');
68             }
69         }
70         putchar('\n');
71     }
72     
73 }
1-13.c

打印水平方向的直方图容易点,运行结果如下(注意输入完毕后先Enter再Ctrl+Z)

接下来是绘制垂直方向的直方图,写的稍微费事了一些,思路是先找到数组nlength[]中的最大值,在一次性输出0-9的过程中将数组nlength复制到另一个数组ncopy(否则后面的自减会丢失),然后根据相应数目输出*。

答案的前提和我的相同,也需要统计不同长度出现的次数,不过引入了overflow来统计超出允许最大长度的单词个数。

对于水平直方图(程序为1-13-a1.c),答案额外写了一段代码来找到统计到的长度数值中的最大值,以此来计算wl[i]对应的直方图长度(我的是有多少就输出多少*),计算公式是len=wl[i]*MAXHIST/maxvalue,我觉得采取这个公式只是起到计算的作用,没有特殊意义。

 1 #include<stdio.h>
 2 
 3 #define IN 1
 4 #define OUT 0
 5 #define MAXSIZE 10
 6 #define MAXHIST 15
 7 
 8 /* 16/06/15 打印输入单词长度的水平直方图 */
 9 main()
10 {
11     char state = OUT;
12     char c, i;
13     int nlength[MAXSIZE];
14     int len;
15     int nc, overflow;
16     int maxvalue;
17 
18     nc = 0;
19     overflow = 0;
20     for (i = 0; i < MAXSIZE; i++) {
21         nlength[i] = 0;
22     }
23     while ((c = getchar()) != EOF) {
24         if (c == ' ' || c == '\t' || c == '\n') {
25             state = OUT;
26             if (nc > 0) {
27                 if (nc<MAXSIZE) 
28                     ++nlength[nc];
29                 else ++overflow;
30             }
31             nc = 0;
32         }
33         else if (state == OUT) {
34             state = IN;
35             nc = 1;
36         }
37         else nc++;
38     }
39     /* 绘制水平方向直方图 */
40     maxvalue = 0;
41     for (i = 1; i < MAXSIZE; i++) {
42         if (maxvalue < nlength[i])
43             maxvalue = nlength[i];
44     }
45     for (i = 1; i < MAXSIZE; i++) {
46         printf("%d - %d : ", i, nlength[i]);
47         if (nlength[i] > 0) {
48             if ((len = nlength[i] * MAXHIST / maxvalue) <= 0)
49                 len = 1;
50         }
51         else len = 0;
52         while (len--)
53             putchar('*');
54         putchar('\n');
55     }
56     if (overflow > 0)
57         printf("There are %d words >= %d\n", overflow, MAXSIZE);
58 
59 }
1-13-a1.c

运行效果如下:

1-13-a2是绘制垂直直方图,

 1 #include<stdio.h>
 2 
 3 #define IN 1
 4 #define OUT 0
 5 #define MAXSIZE 10
 6 #define MAXHIST 15
 7 
 8 /* 16/06/15 打印输入单词长度的垂直直方图 */
 9 main()
10 {
11     char state = OUT;
12     char c, i, j;
13     int nlength[MAXSIZE];
14     int nc, overflow;
15     int maxvalue;
16 
17     nc = 0;
18     overflow = 0;
19     for (i = 0; i < MAXSIZE; i++) {
20         nlength[i] = 0;
21     }
22     while ((c = getchar()) != EOF) {
23         if (c == ' ' || c == '\t' || c == '\n') {
24             state = OUT;
25             if (nc > 0) {
26                 if (nc<MAXSIZE)
27                     ++nlength[nc];
28                 else ++overflow;
29             }
30             nc = 0;
31         }
32         else if (state == OUT) {
33             state = IN;
34             nc = 1;
35         }
36         else nc++;
37     }
38     /* 绘制水平方向直方图 */
39     maxvalue = 0;
40     for (i = 1; i < MAXSIZE; i++) {
41         if (maxvalue < nlength[i])
42             maxvalue = nlength[i];
43     }
44     for (i = MAXHIST; i > 0; i--) {                        //之所以是从MAXHIST开始是为了从底部开始显示*,看一下运行结果就知道了
45         for (j = 1; j < MAXSIZE; j++) {
46             if ((nlength[j] * MAXHIST / maxvalue) >= i)
47                 printf(" * ");
48             else 
49                 printf("   ");
50             
51         }
52         putchar('\n');                                    //注意这一句是必须写的
53     }
54     for (i = 1; i < MAXSIZE; i++) 
55         printf(" %d ", i);
56     putchar('\n');
57     for (i = 1; i < MAXSIZE; i++) 
58         printf(" %d ", nlength[i]);
59     putchar('\n');
60     if (overflow > 0)
61         printf("There are %d words >= %d\n", overflow, MAXSIZE);
62 
63 }
1-13-a2.c

运行效果如下,

 

1-14

我仅仅是在教材P15例程基础上稍作改动,根据统计到的ndigit[i]、nwhite、nother打印相应数目的*,

 1 #include<stdio.h>
 2 
 3 /* 16/06/09 打印输入中各个字符出现频度的直方图 */
 4 main()
 5 {
 6     char c, i, j,nwhite, nother;
 7     int ndigit[10];
 8 
 9     nwhite = nother = 0;
10     for (i = 0; i < 10; i++) {
11         ndigit[i] = 0;
12     }
13     while ((c = getchar()) != EOF) {
14         if (c >= '0'&&c <= '9')
15             ++ndigit[c - '0'];
16         else if (c == ' ' || c == '\t' || c == '\n')
17             ++nwhite;
18         else ++nother;
19     }
20     /* 绘制水平方向直方图 */
21     for (i = 0; i < 10; i++) {
22         printf("%d     ", i);
23         for (j = 0; j < ndigit[i]; j++) {
24             putchar('*');
25         }
26         putchar('\n');
27     }
28     
29     printf("white ");
30     for (i = 0; i < nwhite; i++) putchar('*');
31     putchar('\n');
32     
33     printf("other ");
34     for (i = 0; i < nother; i++) putchar('*');
35     putchar('\n');
36 
37 }
1-14.c

答案能够处理的字符是ASCII字符集范围内的字符,因而设置了#define MAXCHAR 128,在这个宏定义的范围内,++cc[c]。

 1 #include<stdio.h>
 2 #include<ctype.h>
 3 
 4 #define MAXCHAR 128
 5 #define MAXHIST 15
 6 
 7 /* 16/06/15 打印输入中各个字符出现频度的直方图 */
 8 main()
 9 {
10     int c, i;
11     int len;
12     int maxvalue;
13     int cc[MAXCHAR];
14 
15     for (i = 1; i < MAXCHAR; i++) {
16         cc[i] = 0;
17     }
18     while ((c = getchar()) != EOF) {
19         if (c < MAXCHAR) {
20             ++cc[c];
21         }
22     }
23     /* 绘制水平方向直方图 */
24     maxvalue = 0;
25     for (i = 1; i < MAXCHAR; i++) {
26         if (maxvalue < cc[i])
27             maxvalue = cc[i];
28     }
29     for (i = 1; i < MAXCHAR; i++) {
30         if (isprint(i))
31             printf("%5d - %c - %5d : ", i, i, cc[i]);
32         else 
33             printf("%5d -   - %5d : ", i, cc[i]);
34         len = cc[i];                                    //还是直接让len=cc[i],好理解一些,下面的代码也只是输出cc[i]的倍数而已
35         /*
36         if (cc[i] > 0) {
37             if ((len = cc[i] * MAXCHAR / maxvalue) <= 0)
38                 len = 1;
39         }
40         else len = 0;
41         */
42         while (len > 0) {
43             putchar('*');
44             --len;
45         }
46         putchar('\n');
47     }
48 
49 }
1-14-a.c

注意后面的输出格式设置,如果是ASCII字符集范围内的字符就显示出来,否则打印空白,

1 if (isprint(i))
2     printf("%5d - %c - %5d : ", i, i, cc[i]);
3 else 
4     printf("%5d -   - %5d : ", i, cc[i]);

运行结果如下

 

1-15

比较简单,但是我的程序比较糟糕的一点是在函数Fahr_to_Cel内使用了printf,感觉独立性差了点,

 1 #include<stdio.h>
 2 
 3 #define LOWER 0
 4 #define UPPER 300
 5 #define STEP 20
 6 
 7 void Fahr_to_Cel(int lower, int upper, int step);
 8 
 9 /*  16/06/09 温度转换程序 */
10 main()
11 {
12     Fahr_to_Cel(LOWER, UPPER, STEP);
13 }
14 
15 void Fahr_to_Cel(int lower, int upper, int step)
16 {
17     int fahr, celsius;
18 
19     for (fahr = lower; fahr <= upper; fahr += step) {
20         celsius = 5 * (fahr - 32) / 9;
21         printf("%d\t%d\n", fahr, celsius);
22     }
23 }
1-15.c

下面给出参考答案程序,

 1 #include<stdio.h>
 2 
 3 #define LOWER 0
 4 #define UPPER 300
 5 #define STEP 20
 6 
 7 float Fahr_to_Cel(float fahr);
 8 
 9 /* 16/06/15 温度转换程序  */
10 main()
11 {
12     float fahr;
13     for (fahr = LOWER; fahr < UPPER; fahr += STEP) {
14         printf("%3.0f %6.1f\n",fahr,Fahr_to_Cel(fahr));
15     }
16 }
17 
18 float Fahr_to_Cel(float fahr)
19 {
20     return (5.0 / 9.0)*(fahr - 32.0);
21 }
1-15-a.c

 

1-16

①开始思路是将某行的长度与该输入行放在同一数组line[]里面,然后再接下一行的长度和内容,

 1 #include<stdio.h>
 2 #define MAXLINE 1000
 3 
 4 int getline(char line[], int maxline,int pos);
 5 
 6 /* 16/06/09 程序的思路是将某行的长度与该行放在一起,后接下一行,存在很大缺陷,输入某个行的长度不能超过9 */
 7 main()
 8 {
 9     int c,len;
10     char line[MAXLINE];
11     int position=0;
12 
13     while((c=getchar())!=EOF){
14         line[position + 2] = c;
15         len = getline(line, MAXLINE, position+3);
16         line[position] = (len-position-3)+'0';
17         line[position+1] = ' ';
18         position = len;
19     }
20     line[position] = '\0';
21     printf("%s", line);
22 }
23 
24 int getline(char s[], int lim, int pos)
25 {
26     int c, i;
27     for (i = pos; i < lim - 1 && (c = getchar()) != EOF&&c != '\n'; ++i)
28         s[i] = c;
29     if (c == '\n')
30         s[i++] = c;
31     return i;
32 }
1-16.c

但是单个输入行的长度不要超过9,否则该输入行长度显示会出错,原因在于10以上的数字无法用单个ASCII字符表示。

②看来只能将长度与数据分开存放了,运行结果如下,重要的地方已在程序注释。

 1 #include<stdio.h>
 2 #define MAXLINE 1000
 3 
 4 int getline(char line[], int maxline, int pos);
 5 
 6 /* 16/06/09 程序的思路是将某行的长度与该行内容分开存放在不同数组line_num与line_dat */
 7 main()
 8 {
 9     int c, len;
10     int i = 0, j = 0;
11     char line_dat[MAXLINE];
12     char line_num[MAXLINE];
13     int position = 0;
14 
15     /* 下面的代码段将输入文本的内容保存在同一个数组line_dat里面,回车用\n取代 */
16     while ((c = getchar()) != EOF) {
17         line_dat[position] = c;                            //这一句是有必要的,否则头字母丢失
18         len = getline(line_dat, MAXLINE, position + 1);    //从该行的第二个字母开始判断
19         line_num[i++] = len-position-1;                    //保存该行的长度
20         position = len;
21     }
22     line_dat[position] = '\0';                            //整个文本输入完毕后,在保存数据的字组line_dat末尾加入\0表征字符串的结尾
23     i = 0;
24     /* 下面的代码段先输出某行的长度,再输出该行的内容 */
25     while( i < MAXLINE&&line_dat[i] != '\0') {
26         printf("%d\t", line_num[j++]);
27         for (; line_dat[i] != '\n'; i++) {
28             putchar(line_dat[i]);
29         }
30         putchar(line_dat[i++]);
31     }
32 }
33 
34 int getline(char s[], int lim, int pos)
35 {
36     int c, i;
37     for (i = pos; i < lim - 1 && (c = getchar()) != EOF&&c != '\n'; ++i)
38         s[i] = c;
39     if (c == '\n')
40         s[i++] = c;
41     return i;
42 }
1-16-2.c

③前面两个程序均是在主函数main()内部借助c = getchar()) != EOF来判断是否达到文本流结尾,其实完全可以直接借助getline函数来判断(如果到达文本流结尾就返回-1),这样会使程序简化一些。

 1 #include<stdio.h>
 2 #define MAXLINE 1000
 3 
 4 int getline(char line[], int maxline, int pos);
 5 
 6 /* 16/06/10 写完1-18-2,回头改写了1-16-2,运行正常 */
 7 main()
 8 {
 9     int len;
10     int i = 0, j = 0;
11     char line_dat[MAXLINE];
12     char line_num[MAXLINE];
13     int position = 0;
14 
15     /* 下面的代码段将输入文本的内容保存在同一个数组line_dat里面,回车用\n取代 */
16     while ((len = getline(line_dat, MAXLINE, position)) >0) {
17         line_num[i++] = len - position - 1;                //保存该行的长度
18         position = len;
19     }
20     line_dat[position] = '\0';                            //整个文本输入完毕后,在保存数据的字组line_dat末尾加入\0表征字符串的结尾
21     i = 0;
22     /* 下面的代码段先输出某行的长度,再输出该行的内容 */
23     while (i < MAXLINE&&line_dat[i] != '\0') {
24         printf("%d\t", line_num[j++]);
25         for (; line_dat[i] != '\n'; i++) {
26             putchar(line_dat[i]);
27         }
28         putchar(line_dat[i++]);
29     }
30 }
31 
32 int getline(char s[], int lim, int pos)
33 {
34     int c, i;
35     for (i = pos; i < lim - 1 && (c = getchar()) != EOF&&c != '\n'; ++i)
36         s[i] = c;
37     if (c == EOF) return -1;
38     if (c == '\n')
39         s[i++] = c;
40     return i;
41 }
1-16-3.c

答案主要在教材【P21】的例程基础上对函数getline进行了修改,删除了i<lim-1,并加入if(i<lim-2)条件判断。答案是以每个输入行为单位一行一行地输出,无法像我的程序那样处理多行。

 1 #include<stdio.h>
 2 #define MAXLINE 1000
 3 
 4 int getline(char s[], int lim);
 5 
 6 /* 16/06/15 是以每个输入行为单位一行一行地输出,无法像我的程序那样处理多行 */
 7 main()
 8 {
 9     int len;
10     int i = 0, j = 0;
11     char line_dat[MAXLINE];
12 
13     /* 下面的代码段将输入文本的内容保存在同一个数组line_dat里面,回车用\n取代 */
14     while ((len = getline(line_dat, MAXLINE)) >0) {
15         printf("%d, %s", len, line_dat);
16     }
17     return 0;
18 }
19 
20 int getline(char s[], int lim)
21 {
22     int c, i;
23 
24     for (i = 0; (c = getchar()) != EOF && c != '\n'; ++i) {
25         if (i < lim - 2) {
26             s[i] = c;
27         }
28     }
29     if (c == '\n') {
30         s[i] = c;
31         i++;
32     }
33     s[i] = '\0';
34     return i;
35 }
1-16-a.c

答案运行结果如下

注意对于超过1000的输入,运行结果如下(一行为120个字符,共10行),可以看出能输出正确数目,但是不会输出完整的尾部内容。

 

 1-17

在1-16-2.c基础上稍作修改即可,这里是设定打印长度大于10个字符的所有输入行。

 1 #include<stdio.h>
 2 #define MAXLINE 1000
 3 
 4 int getline(char line[], int maxline, int pos);
 5 
 6 /* 16/06/09 打印长度大于10个字符的所有输入行,在1-16-2.c基础上修改 */
 7 main()
 8 {
 9     int c, len;
10     int i = 0, j = 0;
11     char line_dat[MAXLINE];
12     char line_num[MAXLINE];
13     int position = 0;
14 
15     while ((c = getchar()) != EOF) {
16         line_dat[position] = c;                            
17         len = getline(line_dat, MAXLINE, position + 1);
18         line_num[i++] = len - position - 1;                    
19         position = len;
20     }
21     line_dat[position] = '\0';                            
22     i = 0;
23     /* 下面是修改部分 */
24     while (i < MAXLINE&&line_dat[i] != '\0') {
25         if (line_num[j]>10) {
26             printf("%d\t", line_num[j++]);
27             for (; line_dat[i] != '\n'; i++) {
28                 putchar(line_dat[i]);
29             }
30             putchar(line_dat[i++]);
31         }
32         else {
33             j++;
34             while (line_dat[i++] != '\n');
35         }
36     }
37 }
38 
39 int getline(char s[], int lim, int pos)
40 {
41     int c, i;
42     for (i = pos; i < lim - 1 && (c = getchar()) != EOF&&c != '\n'; ++i)
43         s[i] = c;
44     if (c == '\n')
45         s[i++] = c;
46     return i;
47 }
1-17.c

答案是在1-16-a.c的基础上加入长度条件判断if(len>LONGLINE)即可。

1 #define LONGLIEN 80
2 ...
3 main(){
4     ...
5     while ((len = getline(line_dat, MAXLINE)) >0) {
6         if(len>LONGLINE)    
7             printf("%d, %s", len, line_dat);
8     }    
9 }

 

posted @ 2016-07-31 11:43  cust渔舟唱晚  阅读(136)  评论(0编辑  收藏  举报