博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第1章-导言-习题1.18-1.23
阅读量:6413 次
发布时间:2019-06-23

本文共 13413 字,大约阅读时间需要 44 分钟。

1-18

思路是改动getline函数,读入某个输入行后,从该输入行尾部开始往前读,一直读到非空格或非制表符为止。

1 #include
2 #define MAXLINE 1000 3 4 int getline(char line[], int maxline, int pos); 5 void count(char s[]); 6 7 /* 16/06/10 删除每个输入行末尾的空格及制表符,并删除完全是空格的行 */ 8 main() 9 {10 int len;11 int i = 0, j = 0;12 char line_dat[MAXLINE];13 int position = 0;14 15 while ((len = getline(line_dat,MAXLINE,position)) > 0) { //根据教材【P21】改写,避免一开始就写入数据16 position = len;17 }18 line_dat[position] = '\0'; //整个文本输入完毕后,在保存数据的字组line_dat末尾加入\0表征字符串的结尾19 20 printf("%s", line_dat);21 count(line_dat);22 }23 24 int getline(char s[], int lim, int pos)25 {26 int c, i, j;27 for (i = pos; i < lim - 1 && (c = getchar()) != EOF&&c != '\n'; ++i)28 s[i] = c;29 if (c == EOF) { //如果到达文本末尾,就返回-1,终止main的while循环30 return -1;31 }32 if (c == '\n') {33 for (j = i - 1; (j > pos) && ((s[j] == ' ') || (s[j] == '\t')); j--); //从尾部开始往前读,一直读到非空格或非制表符为止34 if (j == pos && s[pos] == ' ') j = pos; //全是空格的输入行35 else {36 j++;37 s[j++] = '\n';38 }39 }40 return j;41 }42 43 /* 为了检验是否删除了空格或制表符,将教材【P15】1-6的统计次数的程序单独写成函数 */44 void count(char s[])45 {46 int i, nwhite, nother;47 int ndigit[10];48 49 nwhite = nother = 0;50 for (i = 0; i < 10; i++)51 ndigit[i] = 0;52 53 for (i = 0; s[i] != '\0'; i++) {54 if (s[i] >= '0'&&s[i] <= '9')55 ++ndigit[i];56 else if (s[i] == ' ' || s[i] == '\n' || s[i] == '\t')57 ++nwhite;58 else59 ++nother;60 }61 62 printf("ndigit=");63 for (i = 0; i < 10; i++)64 printf("% d", ndigit[i]);65 printf(", white space = %d, other = %d\n", nwhite, nother);66 }
1-18-2.c

答案也是采取了从尾部往前读一直到非空格/非制表符为止,不过仍只能处理单行输入的情况,不如我的程序好,而且不像我的程序那样使用void count(char s[])来检验,无法直观感觉到底删除没有。

1 #include
2 #define MAXLINE 1000 3 4 int getline(char s[], int lim); 5 int removetail(char s[]); 6 void count(char s[]); 7 8 /* 16/06/16 答案也是采取了从尾部往前读一直到非空格/非制表符为止,不过仍只能处理单行输入的情况,不如我的程序好,而且不像我的程序那样使用void count(char s[])来检验,无法直观感觉到底删除没有 */ 9 main()10 {11 int len;12 char line_dat[MAXLINE];13 14 /* 下面的代码段将输入文本的内容保存在同一个数组line_dat里面,回车用\n取代 */15 while ((len = getline(line_dat, MAXLINE)) > 0) {16 if (removetail(line_dat) > 0) {17 printf("%s", line_dat);18 }19 count(line_dat);20 }21 return 0;22 }23 24 int removetail(char s[])25 {26 int i;27 28 i = 0;29 while (s[i] != '\n')30 i++;31 i--;32 for (; (i >= 0) && (s[i] == ' ' || s[i] == '\t'); i--);33 if (i >= 0) {34 i++;35 s[i]='\n';36 i++;37 s[i]='\0';38 }39 return i;40 }41 42 int getline(char s[], int lim)43 {44 int c, i;45 46 for (i = 0; (c = getchar()) != EOF && c != '\n'; ++i) {47 if (i < lim - 2) {48 s[i] = c;49 }50 }51 if (c == '\n') {52 s[i] = c;53 i++;54 }55 s[i] = '\0';56 return i;57 }58 /* 为了检验是否删除了空格或制表符,将教材【P15】1-6的统计次数的程序单独写成函数 */59 void count(char s[])60 {61 int i, nwhite, nother;62 int ndigit[10];63 64 nwhite = nother = 0;65 for (i = 0; i < 10; i++)66 ndigit[i] = 0;67 68 for (i = 0; s[i] != '\0'; i++) {69 if (s[i] >= '0'&&s[i] <= '9')70 ++ndigit[i];71 else if (s[i] == ' ' || s[i] == '\n' || s[i] == '\t')72 ++nwhite;73 else74 ++nother;75 }76 77 printf("ndigit=");78 for (i = 0; i < 10; i++)79 printf("% d", ndigit[i]);80 printf(", white space = %d, other = %d\n", nwhite, nother);81 }
1-18-a.c

加入void count(char s[]),输出结果如下

从运行结果得知,这一程序并没有删除完全是空格的行,而只是不显示而已。

 

1-19

1 #include
2 #define MAXLINE 1000 3 4 int getline(char s[], int lim); 5 void reverse(char s[]); 6 7 /* 16/06/16 将单个输入行的字符顺序颠倒过来,在1-16-a基础上加入reverse */ 8 main() 9 {10 int len;11 int i = 0, j = 0;12 char line_dat[MAXLINE];13 14 while ((len = getline(line_dat, MAXLINE)) >0) {15 reverse(line_dat);16 printf("%s", line_dat);17 }18 return 0;19 }20 21 int getline(char s[], int lim)22 {23 int c, i;24 25 for (i = 0; (c = getchar()) != EOF && c != '\n'; ++i) {26 if (i < lim - 2) {27 s[i] = c;28 }29 }30 if (c == '\n') {31 s[i] = c;32 i++;33 }34 s[i] = '\0';35 return i;36 }37 38 void reverse(char s[])39 {40 int i,j;41 int temp;42 43 i = 0;44 while (s[i++] != '\n');45 i--;46 /*47 //自己写的48 for (j = 0; j < (i+1 )/ 2; j++) {49 temp = s[i - j];50 s[i - j] = s[j];51 s[j] = temp;52 }53 */54 //答案写的,因为i--55 j = 0;56 while (j < i) {57 temp = s[j];58 s[j] = s[i];59 s[i] = temp;60 i--;61 j++;62 }63 }
1-19-2.c

答案和我的函数reverse不同之处只在于交换赋值的方法不同而已,实际运行效果相同。

 

1-20(和1-21一起看,做后面第5章的习题5-11和5-12需要回头看一下这里)

当时没看明白习题说的是什么意思,直接看的答案。

1 #include
2 3 #define TABING 4 4 5 /* 16/06/13 将输入中的制表符替换为适当数目的空格,参考了答案 */ 6 main() 7 { 8 int c; 9 int pos, nt;10 11 nt = 0; 12 pos = 1; //注意pos是从1开始统计的13 while ((c = getchar()) != EOF) {14 if (c == '\t') {15 nt = TABING - (pos - 1) % TABING; //这一句是核心16 while (nt > 0) {17 putchar(' ');18 pos++;19 nt--;20 }21 }22 else if (c == '\n') {23 putchar(c);24 pos = 1;25 }26 else {27 putchar(c);28 pos++;29 }30 }31 }
1-20-a.c

运行结果如下(TABING设置为4,第一行为输入行,两个空均是Tab,第二行为按下Enter后的输出结果):

可以看到刚开始按下Tab系统默认占8个空,按下Enter后则以四个空格位为单位进行填充的。TABING是符号常量,nt = TABING - (pos - 1) % TABING;是这一个程序的核心之处。

 

1-21

习题不太好理解,参考一下下面的两个链接。

http://www.cnblogs.com/wzm-xu/p/4200206.html

http://www.cnblogs.com/Capricorn-Black/p/4665587.html

1 #include
2 3 #define TABING 6 4 5 /* 16/06/16 这个程序应该是第1章最难理解的程序 */ 6 main() 7 { 8 int c, nb, nt, pos; 9 nb = 0;10 nt = 0;11 for (pos = 1; (c = getchar()) != EOF; ++pos) {12 if (c == ' ') {13 if (pos%TABING != 0)14 ++nb;15 else {16 nb = 0;17 nt++;18 }19 }20 else {21 for (; nt > 0; --nt)22 putchar('\t');23 if (c == '\t')24 nb = 0;25 else26 for (; nb > 0; --nb)27 putchar(' ');28 putchar(c);29 if (c == '\n')30 pos = 0;31 else if (c == '\t')32 pos = pos + (TABING - (pos - 1) % TABING) - 1;33 }34 }35 }
1-21-a.c

输出结果(注意define TABING 6)为

这里简单分析一下:

(1)hello world

hello和world之间有3个空格
先打印出hello,然后遇到了第一个空格,此时pos = 6,且pos在制表符终止位上,所以执行else,nb=0,nt++;
接下来遇到第二个空格,pos = 7,且pos不在制表符终止位上,所以执行if,nb++,第三个空格也是如此,nb=2;
直到pos = 9 时,根据此前的nt=1,nb=2打印1个Tab(仍是系统默认的8)和2个空格,所以一共5个空格;
随后打印出world,程序结束。

(2)he  is   a  boy

he后是一个tab,is后一个tab和两个空格,a后8个空格
这里不做分析。

(3)he  is   a   boy

he后是一个tab,is后一个tab和两个空格,a后8个空格一个tab
当pos =3时,遇到第一个tab,令nb = 0,然后根据公式:pos = pos+(TABINC-(pos-1)%TABINC)-1得出pos=6,既是直接打印一个制表符,并跳到TABINC处,接着打印出is。
pos=11时遇到tab,由公式得出pos=12,跳到第二个TABINC处。此时后面是两个空格,nb=2,然后打印完两个空格后遇到a,此时pos=15。
a后是8个空格,pos=16/17的空格使得nb=2,然后pos=18的空格执行了else导致nb=0,nt=1,接下来的5个空格使得nb=5;
接下来遇到第4个TABINC,先把nt=1的第3个Tabing打印出来,然后nb = 0,再打印这第4个Tabing,这样的话a和boy中间应该有13个空格(第3个Tabing的5个加第4个Tabing的8个);
最后打印出boy,程序结束。

 

1-22

先自己写了一个,

1 #include
2 3 #define LENGTH 10 4 #define MAXLINE 100 5 6 /* 16/06/13 编写一个程序,把较长的输入行折成短一些的两行或多行 */ 7 main() 8 { 9 int c;10 int nc;11 int i,j;12 char line[MAXLINE];13 14 nc = 0;15 j = 0;16 for (i = 0; i < MAXLINE; i++) {17 line[i] = 0;18 }19 while ((c = getchar()) != EOF) {20 line[j++]=c;21 nc++;22 if (nc >= LENGTH) {23 nc = 0;24 while (line[j--] == ' ');25 line[++j] = '\n';26 ++j;27 }28 }29 line[j] = '\0';30 printf("%s\n", line);31 }
1-22.c

输出结果如下,每行的折合数为10个字符

从答案来看,我原来写程序时把练习理解简单了。答案程序能够完成的功能包括:把制表符扩展为空格;每遇到一个换行符就将此前的输入文本打印出来;每当变量pos的值达到MAXCOL时,就会对输入行进行折叠

1 #include
2 3 #define MAXCOL 10 4 #define TABING 8 5 6 char line[MAXCOL]; 7 8 void printl(int pos); 9 int exptab(int pos);10 int findblnk(int pos);11 int newpos(int pos);12 13 /* 16/06/20 把制表符扩展为空格;每遇到一个换行符就将此前的输入文本打印出来;每当变量pos的值达到MAXCOL时,就会对输入行进行折叠*/14 main()15 {16 int c, pos;17 18 pos = 0;19 while ((c = getchar()) != EOF) {20 line[pos] = c;21 if (c == '\t')22 pos = exptab(pos);23 else if (c == '\n') {24 printl(pos);25 pos = 0;26 }27 else if (++pos >= MAXCOL) {28 pos = findblnk(pos);29 printl(pos);30 pos = newpos(pos);31 }32 33 }34 }35 36 void printl(int pos)37 {38 int i;39 for (i = 0; i < pos; i++)40 putchar(line[i]);41 if (pos > 0)42 putchar('\n');43 44 }45 46 int exptab(int pos)47 {48 line[pos] = ' ';49 for (++pos; pos < MAXCOL && pos%TABING != 0; ++pos)50 line[pos] = ' ';51 if (pos < MAXCOL)52 return pos;53 else {54 printl(pos);55 return 0;56 }57 }58 59 int findblnk(int pos)60 {61 pos--;62 while (pos > 0 && line[pos] != ' ')63 --pos;64 if (pos == 0)65 return MAXCOL;66 else return(pos + 1);67 }68 69 int newpos(int pos)70 {71 int i, j;72 73 if (pos <= 0 || pos >= MAXCOL)74 return 0;75 else {76 i = 0;77 for (j = pos; j < MAXCOL; j++,i++) {78 line[i] = line[j];79 }80 return i;81 }82 }
1-22-a.c

借助实例来理解程序会好一些,三个实例运行结果如下:

对实例①的分析如下:

实例②是函数exptab满足if(pos<MAXCOL)的情况,实例③是函数exptab满足else的情况。

还有一点是我觉得函数findblnk应该在前面加入pos--,比如上面的实例①中,pos=10的时候执行else if (++pos >= MAXCOL),但此时c被存入line[9],line[10]是空的。

 

1-23

自己写了一个,但是处理中间有*的程序诸如1-13.c在*会出错,这也是程序不完美的地方。

1 #include
2 #define MAXLINE 1000 3 4 int getline(char line[], int maxline, int pos); 5 6 /* 16/06/15 删除C程序中所有的注释语句,但不完美 */ 7 main() 8 { 9 int len;10 int i = 0, j = 0;11 char line_dat[MAXLINE];12 int position = 0;13 14 /* 下面的代码段将输入文本的内容保存在同一个数组line_dat里面,回车用\n取代 */15 while ((len = getline(line_dat, MAXLINE, position)) >0) {16 position = len;17 }18 line_dat[position] = '\0'; //整个文本输入完毕后,在保存数据的字组line_dat末尾加入\0表征字符串的结尾19 i = 0;20 printf("%s\n", line_dat);21 }22 23 int getline(char s[], int lim, int pos)24 {25 int c, i;26 for (i = pos; i < lim - 1 && (c = getchar()) != EOF&&c != '\n'; ++i) {27 if (c == '/') { 28 c = getchar();29 if (c == '*') { 30 while ((c = getchar()) != '*'); //一直读到下一个*为止31 if ((c = getchar()) == '/') break; //如果*的下一个字符是/,说明是/* */注释,可以删除32 else { 33 s[i++] = '*'; //如果*的下一个不是/,说明是其他用途比如乘号运算,需要保留34 s[i] = c;35 }36 }37 else if (c == '/') { 38 while ((c = getchar()) != '\n');39 break;40 }41 else { //除法运算需要保留/42 s[i++] = '/';43 s[i] = c;44 }45 }46 else s[i] = c;47 }48 if (c == EOF) return -1;49 if (c == '\n')50 s[i++] = c;51 return i;52 }
1-23.c

下面是1-13.c源代码,

处理结果如下

答案的程序大致看了一遍,确实是very good!

1 #include
2 3 void rcomment(int c); 4 void in_comment(void); 5 void echo_quote(int c); 6 7 /* 16/06/20 答案写的更好更清晰,但是不能删除//格式的注释,且是以行为单位输出 */ 8 main() 9 {10 int c;11 12 while ((c = getchar()) != EOF)13 rcomment(c);14 return 0;15 }16 17 void rcomment(int c)18 {19 int d;20 21 if (c == '/') {22 if ((d = getchar()) == '*')23 in_comment(); //如果是*/的话,就调用函数in_comment搜索注释语句的结束标志*/24 else if (d == '/') { //也就是说//格式的注释不会被删除25 putchar(c);26 rcomment(d); //这是函数嵌套调用27 }28 else { //符号/后面如果不是*的话说明不是注释内容29 putchar(c);30 putchar(d);31 }32 }33 else if (c == '\'' || c == '"') //还考虑到了单引号和双引号的情况34 echo_quote(c);35 else36 putchar(c);37 }38 39 void in_comment(void)40 {41 int c, d; //设立两个字符型变量,一次性存入两个字符,确实妙,我应该想到这一点42 c = getchar();43 d = getchar();44 while (c != '*' || d != '/') {45 c = d;46 d = getchar();47 }48 49 }50 51 void echo_quote(int c)52 {53 int d;54 putchar(c);55 while ((d = getchar()) != c) { //查找单/双引号的另一边56 putchar(d);57 if (d == '\\')58 putchar(getchar()); //不会把反斜号后面的引号看作是结束引号59 }60 putchar(d);61 }
1-23-a.c

运行结果如下:

 

 

转载于:https://www.cnblogs.com/custalex/p/5731996.html

你可能感兴趣的文章
关于监控工具的主动发起性能测试
查看>>
我的友情链接
查看>>
OpenSSL学习(十六):基础-指令rand
查看>>
KeyMob致力于打造国内领先的移动广告平台
查看>>
路由选路原则
查看>>
jvm 学习(一)
查看>>
JavaScript简介
查看>>
SQL Server附加数据库拒绝访问解决方法汇总
查看>>
SM2算法原理及实现
查看>>
RHCA教材翻译计划
查看>>
js-小括号在不同场合下的作用
查看>>
我的友情链接
查看>>
kvm中虚拟机的硬盘扩容
查看>>
Android (Launch Mode) 四种启动模式
查看>>
透视学理论(二)
查看>>
Dubbo/HSF在Service Mesh下的思考和方案
查看>>
Django form表单
查看>>
CTYL-9.14(tomcat端口与阿里云安全组,域名与tomcat配置,域名与反向代理)
查看>>
Java 多线程相关问题记录
查看>>
LNMP架构介绍、MySQL安装、PHP安装、 Nginx介绍
查看>>