练习1-10
制表符替换为\t,回退符替换为\b,斜杠替换为\\。
难点是怎么输入回退符。
getchar没办法从输入流中获取回退符。有人说用getch代替getchar,我试了,但是失败了,换了好几个头文件都报错。
我采取的方法是程序从文件中读取数据,Linux Ctrl-V + Ctrl-H,window Ctrl-Q + Ctrl-H生成回退符。
练习1-12
每行一个单词打印输出。
标准答案在1.5.4代码基础上加了一些逻辑。我没看明白。
我采用的方法是,遇到空白符时先判断上一个字符是否是换行符,如果不是就换行,如果是,说明已经做过换行操作了,这就需要保存上一个字符。碰到非空白符直接输出。
1.5.4统计单词的代码值得好好看。
1
2
3
4
5
6
7
while((c=getchar()) != EOF)
{
if(c == || c == \t || c == \n)
state = OUT;
else if(state == OUT) //inside a word
state = IN;
}
练习2-3 十六进制转换为十进制
参考书中有atoi 代码。atoi曾是百度笔试题。
对于非法输入如何处理?返回一个整数?还是抛出一个异常?异常如何捕捉?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
int htoi(char s[])
{
//begin with 0x or 0X, a~f or A~F are acceptable
int i = 0, value = 0;
//s[0] = 0, s[1] = x || X
for(i = 2; (s[i] >= 0 && s[i] <= 9) || (s[i] >= a && s[i] <= z) || (s[i] >= A && s[i] <= Z); ++i)
{
value = value * 16;
if(s[i] >= 0 && s[i] <= 9)
value += s[i] - 0;
else if((s[i] >= a && s[i] <= z) || (s[i] >= A && s[i] <= Z))
{
switch(s[i])
{
case a:
case A: value += 10; break;
case b:
case B: value += 11; break;
case c:
case C: value += 12; break;
case d:
case D: value += 13; break;
case e:
case E: value += 14; break;
case f:
case F: value += 15; break;
}
}
}
return value;
}
练习2-4 将字符串 s1 中任何与字符串 s2 中字符匹配的字符都删除。
参考书中2.8代码squeeze。这道题是11年华为给我的笔试题。
1
2
3
4
5
6
7
8
9
void squeeze(char s[], int c)
{
int i, j;
for(i = j = 0; s[i] != \0; i++)
if(s[i] != c)
s[j++] = s[i];
s[j] = \0;
}
注意代码,匹配到了字符后,不是说把后面的字符往前移动。而是用一个索引 i 记录下一个不匹配字符 c 的位置,另一个索引 j 记录匹配 c 的位置,再用 i 位置的值覆盖 j 位置的值。如果没有匹配到字符 c,顶多是多做一次赋值。但是避免了数据的大量移动。
模仿这段代码,每次从s2中取出一个字符 c
1
2
3
4
5
6
7
8
9
10
11
12
13
void squeeze(char s1[], char s2[])
{
int i, j, k;
for(j = 0; s2[j] != \0; ++j)
{
for(i = k = 0; s1[i] != \0; ++i)
if(s1[i] != s2[j])
s1[k++] = s1[i];
s1[k] = \0;
}
}
待续