第1章 导言
1.1 入门
书本非常详细,hello world程序,略。
练习1-1 略
练习1-2 “\c”并不属于转义字符,作者骗人的
1.2 变量与算术表达式
同样非常详细,不过有问题可以注意
作者为整型右对齐修改后的代码:
printf("%3d %6d\n",fahr,celsius);
这句话中输出celsius的值从-17到148,实际只需3个数字宽(注意负号和小数点都需要占1个数字宽)。因此代码改成
printf("%3d %3d\n",fahr,celsius);
即可达到右对齐效果。如果小于%3d,例如%2d,则数字宽为3的数依旧左对齐。
同理,浮点数右对齐中
printf("%3.0f %6.1f\n",fahr,celsius);
修改为
printf("%3.0f %5.1f\n",fahr,celsius);
也可达成目的。
练习1-3 略
练习1-4 略
1.3 for语句
详细,略。for语句和while语句翻译成汇编仅有少许差异,然而这并不是优化关键点,因此没必要为了他们的执行效率而只用一个。如何选择while和for?注意作者的一句话:“在实际编程中,可以选择while与for中的任意一种循环语句,主要要看使用哪一种更清晰。for语句比较适合初始化和增加步长都是单条语句并且逻辑相关的情形,因为它将循环控制语句集中放在一起,且比while语句更紧凑。”
练习1-5 略
1.4 符号常量
简单,略
1.5 字符输入/输出
1.5.1文字复制
注意EOF并不是真的打EOF进去……规定中在Windos 操作系统EOF是Ctrl+Z ;Linux系统下则是Ctrl + D。
练习1-6 犯了个很白痴的错误:printf(“%d”,c)中%d打成了%c,结果Termina输出了一个小方框……
练习1-7 EOF值是-1哟
1.5.2 字符计数
测试书本原代码时遇上一个很好玩的东西,如下:
当我输入“abdfdskfj”9个字符时,它会计算出10个字符。从这里可以看出,它是将换行符’\n’也计入了。经过网上搜索得出结论,getchar()先等待缓存区存入我们输入的字符,直到遇到回车键“\n”,开始每次从stdin流中取出一个数字赋给c,同时“\n”也会作为取出的字符。
那如果我不想计算’\n’呢,就可以将
for(nc = 0; getchar() != EOF; ++nc);
改为
for(nc = 0; getchar() != '\n'; ++nc);
但是这也会带来一个问题,就是当按下回车键时,也会跳出循环,就无法再接受下一次输入了。
1.5.3 行计数
略
练习1-8 略
练习1-9 答案中提供了3种思路。
第一是用一个标志inspace,值为0代表在空格外,值为1代表在空格内,当检测到空格同时inspace=1,则代表这是第一个空格,可以输出空格:
#include <stdio.h>
int main(void)
{
int c;
int inspace;
inspace = 0;
while((c = getchar()) != EOF){
if(c == ' ')
{//注意这里一定要有括号,否则底下的else会依照就近原则选择if语句
if(inspace == 0){
inspace = 1;
putchar(c);
}
}
else
{
inspace = 0;
putchar(c);
}
}
return 0;
}
第二种思路是通过比较本次输入值与前次输入值是否都为空格,如果都是的话则输出空格值:
#include <stdio.h>
int main()
{
int c, pc; //c为本次输入,pc为前次输入
/* set pc to a value that wouldn't match any character, in case
this program is ever modified to get rid of multiples of other
characters */
pc = EOF;
while ((c = getchar()) != EOF) {//注意不要漏括号
if (c == ' '){
if (pc != ' ')
putchar(c);
}
else{
putchar(c);
pc = c;
}
return 0;
}
第三种思路是遇到第一个空格后判断之后接受到的是否为非空格,是的话继续输出,否则原地等待。注意该思路容易有漏洞:
#include <stdio.h>
int main(void)
{
int c;
while ((c = getchar()) != EOF) {
if (c == ' ') {
putchar(c);
while((c = getchar()) == ' ' && c != EOF)//漏洞在这!!!等待同时要注意是否遇上了结束信号!!!
;//原地等待
}
if (c == EOF)
break; //如果遇上结束符号则跳出循环
putchar(c);//遇上字符打出字符
}
return 0
练习1-10 网上的课后答案两种方法本质是相同的,只是后一种方法用了符号常量,同时用了switch语句。应注意如果用putchar输出,每次只能输出一个字符。
1.5.4 单词计数
我们发现这里作者又用了标志量state来记录在单词内和在单词外的两种状态,这给我们一种启示,或许这种思路更容易写代码。有学过VHDL的人就更清楚状态转换这种东西。
练习1-11 这道题是锻炼我们单元测试的能力,课后答案如下:
0.inputfile contains zero words
1.inputfile contains 1 enormous word without any new lines
2.inputfile contains all white space without newlines
3.inputfile contains 66000 newlines
4.inputfile contains word /{huge sequence of white-space of different kinds}/ word
5.input file contains 66000 single letter words, 66 to the line
6.input file contains 66000 words without any newlines
7.input file is /usr/dictcontents (or equivalent)
8.input file is full collection of moby words
9.input file is binary (e.g. its own executable)
10.input file is /dev/nul (or equivalent)
我归纳了一下,是
0.一个单词都没有情况
1.单行超长单词
2.单行超长泛空格符
3.行数极限
4.词+超长泛空格+词
5.多行单字符词极限
6.单行多字符词极限
7.8.9.10是文件格式测试
然而我还没总结出思路是什么……其中选择6600是为了检测整型是否溢出。
接下来答案给出了生成输入文件0-6的代码,我就不贴了,感兴趣可以自己去看看。
练习1-12 跟练习1-9思路一致,只要把检测到第一个空格时输出空格换成输出换行符即可。
今天先写到这~