源自《The C Programming Language》P22 pr1-18:
编写一个程序,删除每个输入行末尾的空格,制表符,并删除完全是空格的行
代码:
2
3 #define MAXLINE 10
4
5 int getLine( char s[], int lim);
6 void copy( char to[], char from[]);
7 int calcLen( char s[]);
8
9 int main()
10 {
11
12 int len, index, row;
13 char line[MAXLINE];
14 char post_line[MAXLINE][MAXLINE];
15
16 row = 0 ;
17 while ((len = getLine(line, MAXLINE)) > 0 )
18 {
19 if (line[len - 1 ] == ' \n ' ) // 判断读入的一行字符串的倒数第二个字符是否为'\n'
20 index = len - 2 ;
21 else
22 index = len - 1 ;
23 while (line[index] == ' ' || line[index] == ' \t ' ) // 消除字符串结尾处的' '和'\t'
24 {
25 line[index] = line[index + 1 ];
26 line[index + 1 ] = line[index + 2 ];
27 -- index;
28 }
29 if (index > - 1 )
30 copy(post_line[row ++ ], line); // 如果line是全空格字符串,对其进行消除字符串结尾处
31 // 操作使得line成为一个空字符串,故不将其(空字符串)
32 // 拷贝到post_line中。
33 }
34
35 for (index = 0 ; index < row; ++ index) // post_line针对其中每个字符串的倒数第二个字符是否为'\n'
36 // 在打印的时候做不同处理。
37 if (post_line[index][calcLen(post_line[index]) - 1 ] != ' \n ' )
38 printf( " %s\n " , post_line[index]);
39 else
40 printf( " %s " ,post_line[index]);
41
42 return 0 ;
43 }
44
45 int getLine( char s[], int lim)
46 {
47 int i;
48 char c;
49
50 for (i = 0 ; i < lim - 1 && (c = getchar()) != EOF && c != ' \n ' ; ++ i)
51 s[i] = c;
52 if (c == ' \n ' )
53 {
54 s[i] = c;
55 ++ i;
56 }
57 s[i] = ' \0 ' ;
58 fflush(stdin);
59
60 return i;
61 }
62
63 void copy( char to[], char from[])
64 {
65 int i;
66
67 i = 0 ;
68 while ((to[i] = from[i]) != ' \0 ' ) // 超过字符数组的容量,截断。
69 ++ i;
70 // if(i == MAXLINE-1)
71 // to[i] = '\0';
72 // fflush(stdin); // 每输入一行字符后(键入'\n'之后),清空输入缓冲区。
73 }
74
75 int calcLen( char s[])
76 {
77 int i;
78
79 i = 0 ;
80 while (s[i] != ' \0 ' )
81 ++ i;
82
83 return i;
84 }
分析:
1, 针对输入的字符串(line)的倒数第二个字符是否为'/n',分情况进行消除字符串末尾的空格及制表符处理。
2, 针对处理后的字符串(post_line[n])的倒数第二个字符是否为'/n',在打印的时候分情况进行处理。
3, getLine函数:读入一行字符后,将输入缓冲区清空,这样当超过字符数组line的界限的字符会被清除掉,
如果不清空,则在下次调用getLine函数时,上次超出的字符部分会被getchar函数直接
读到这次的line字符数组中,造成混乱。
参考代码:
2
3 #define MAXLINE 1000
4
5 int getLine( char line[], int maxline);
6 int remove( char s[]);
7
8 int main()
9 {
10
11 char line[MAXLINE];
12
13 while (getLine(line, MAXLINE) > 0 )
14 if (remove(line) > 0 )
15 printf( " %s " , line);
16
17 return 0 ;
18 }
19
20 int remove( char s[]) // 删除字符串s末尾的空格和制表符并返回它的新长度
21 {
22 int i;
23
24 i = 0 ;
25 while (s[i] != ' \n ' ) // 查找'\n'在s数组中对应的下标
26 ++ i;
27 -- i;
28 while (i >= 0 && (s[i] == '' || s[i] == ' \t ' )) // 从字符串末尾起向前查找字符值不是' '和'\t'的字符
29 // 所对应的下标
30 -- i;
31 if (i >= 0 )
32 {
33 ++ i;
34 s[i] = ' \n ' ;
35 ++ i;
36 s[i] = ' \0 ' ;
37 }
38
39 return i;
40 }
分析:
1, 对比于自己实现的代码,发现这段代码简洁多了,思路也很清晰和易懂。
2, 有点缺憾之处:(a),每次输入一行字符,处理结果会紧接着下一行输出,不太容易观看,
而上面那段代码就不存在这个问题。
(b),参考代码没有考虑一行字符串没有'/n'的情况,这和它将MAXLINE设成1000有关,
极端的情况是一个字符串就是1000个字符,并且倒数第二字符不是'/n',如果MAXLINE
的值比较小的话,这个问题就凸现出来了,相比于此,上段代码考虑了这种情况。
修改remove函数:
while(s[i] != '/n' && i < MAXLINE - 2)
++i;
if(i != MAXLINE - 2)
--i;
while(i >= 0 && (s[i] == ' ' || s[i] == '/t'))
--i;
if( i >= 0 && i < MAXLINE - 2)
{
++i;
s[i] = '/n';
++i;
s[i] = '/0';
}