《C程序设计语言》第二版 课后习题

作为一个刚入坑的 C语言初学者,我选择了《C程序设计语言》(谭浩强) 作为自学教材。课后的习题当然是要完成的。习题不便于保存在本机的 .c 文件里(至少当时的问题想法不方便),便有了这篇文章。

声明: 我使用的 IDE 是 C-Free。
Tip:篇幅很长,建议使用 Ctrl + F 搜索或者是看目录。搜索格式:习题 x-x
《C程序设计语言》第二版 课后习题_第1张图片

=========

习题 1-1

练习1-1
首先亮出 Hello,world 。

#include

int main()
{
	printf("Hello,world\n");
}

题目让我们删除一些内容,在看看会发生什么?
其实不论删除什么(除了Hello,world)中的任何一个令牌,都无法编译
这一题就这样吧。

=========

习题 1-2

练习1-2
题目的意思是在 Hello,world 的后面加上一个C语言中没有的转义字符。最后的结果是无法通过编译,编译器报错。

=========

习题 1-3

练习1-3
首先亮出温度转换程序(书中给的转换程序太多了,我随便选了一个。其实不论怎么样,加一个标题都是很简单的。)。

#include 

int main()
{
    int fahr, celsius; // fahr 为华氏度,celsius 为摄氏度
    int lower,upper,step;

    lower = 0;   // 温度的下限
    upper = 300;  // 温度的上限
    step = 20;  // 步长
    fahr = lower;
    
    while (fahr <= upper)
    {
        celsius = 5*(fahr-32)/9;
        printf ("%3d\t%3d\n",fahr,celsius);
        fahr = fahr + step;
    }
    return 0;
}

这里给出的程序和书中的不太一样。这是我个人的习惯。但意思和书上的差不多
执行结果:
《C程序设计语言》第二版 课后习题_第2张图片
题目要求我们打印一个标题,也就是在第一行显示出华氏度与摄氏度。我们只要在程序中加入一个 printf 就好了。具体实现见代码。
注意:这个 printf 一定不能加在 while块(for同理)中,不然会循环打印。

#include 

int main()
{
    int fahr, celsius; 
    int lower,upper,step;

    lower = 0; 
    upper = 300; 
    step = 20; 
    fahr = lower;
    
    //我们在这里加上表的标题。其实只要不加在循环中,加在哪里都是可以的。
    printf ("华氏度\t摄氏度\n") ;
    while (fahr <= upper)
    {
        celsius = 5*(fahr-32)/9;
        printf ("%3d\t%3d\n",fahr,celsius);
        fahr = fahr + step;
    }
	return 0;
}

执行结果:
《C程序设计语言》第二版 课后习题_第3张图片

=========

习题 1-4

练习1-4
题目让我们打印摄氏度度转换为华氏度的转换表。这个问题的很好处理。但是,因为摄氏度转为华氏度的计算中含有小数点,所以这里我们要把 fahr 与 celsius 改成 folat 类型。下面是我们要修改的地方。

  • 修改表的标题。
  • 修改 printf ("%3d\t%3d\n",fahr,celsius); 华氏度与摄氏度的位置。
  • 修改换算式子。
  • 修改 fahr 与 celsius 为 float 类型。

代码如下:

#include 

int main()
{
	float fahr,celsius;
	int lower,upper,step;
	
	lower = 0;
	upper = 300;
	step = 20;
	celsius = lower;
	
	printf ("摄氏度℃   华氏度℉\n");
	while (celsius <= upper)
		{
			fahr = celsius * 1.8 + 32.0;
			printf("%6.1f\t%10.2f\n",celsius,fahr);
			celsius = celsius + step;
		}
		return 0;
}

执行结果:
《C程序设计语言》第二版 课后习题_第4张图片
这个问题还是比较简单的。

=========

习题 1-5

练习1-5
题目要求我们逆序打印温度转换表。这个问题实现要修改的地方:

  • 修改 while 中的循环条件。
  • 修改华氏度的初始值。
  • 修改 fahr = fahr + step 为 fahr = fahr - step。

代码如下:(以 练习1-3 中的代码为例。)

#include 

int main()
{
    int fahr, celsius; 
    int lower,upper,step;

    lower = 0; 
    upper = 300; 
    step = 20; 
    fahr = upper;
    
    printf ("华氏度\t摄氏度\n") ;
    while (fahr >= lower)
    {
        celsius = 5*(fahr-32)/9;
        printf ("%3d\t%3d\n",fahr,celsius);
        fahr = fahr - step;
    }
	return 0;
}

执行结果:
《C程序设计语言》第二版 课后习题_第5张图片
这一题还是比较简单的。

=========

习题 1-6

练习1-6
拿到这个题目,我们要知道 getchar () != EOF 的值为多少,只需要用 printf 把它的值打印出来就好了。
在这里我加入了一个 word 变量来取代它的值。
思路:

  • 使用 getchar() 来获得字符串输入。
  • 用 while + printf 来打印出获得的字符串的 getchar() != EOF 的值。

代码如下:

#include 

int main()
{
	int word;
	
	while (word = getchar() != EOF)
		printf("%d",word);
	
	return 0;
}

执行结果:
《C程序设计语言》第二版 课后习题_第6张图片
这一题还是比较简单的。

题末

  1. 执行结果中的 ^z 是 Ctrl + z。C语言中 while(getchar() != EOF) 不会在输入文本之后自动退出。输入完文本按下回车之后,getchar() 又在新的一行等待输入。这个时候需要另起一行,按下 Ctrl + z 并回车结束输入。具体的解释比较复杂。
  2. 要记住 != 的优先级是大于 = 的,所以这里的 getchar() 不用打括号。

=========

习题 1-7

练习1-7
由于 EOF 的值在 stdio.h 头文件中已经定义,所以我们只需要用 printf 将它的值整形打印出来就行了。

  • 用 printf 将 EOF 的值打印出来。

代码如下:

  #include
  
  int main()
  {
  	printf("EOF = %d",EOF);
  }

执行结果:
《C程序设计语言》第二版 课后习题_第7张图片

=========

习题 1-8

练习 1-8
首先写出这个程序的思路。

  • 使用 getchar() 获得输入
  • 判断获得的输入是否是空格、制表符或者换行符。
  • 统计数据并打印出来。

代码如下:

#include 

int main()
{
	int TabCharNum,SpaceNum,LinefeedNum,word;
	TabCharNum = SpaceNum = LinefeedNum = 0;
	
	while((word = getchar()) != EOF)
	{
		if(word == '\t')
			++TabCharNum;
		
		if(word == ' ')
			++SpaceNum;
		
		if(word == '\n')
			++LinefeedNum;
	}
	printf("制表符=%d\n空格=%d\n换行符=%d\n",TabCharNum,SpaceNum,LinefeedNum);
	return 0;
} 

执行结果:
《C程序设计语言》第二版 课后习题_第8张图片
题末

  1. 输入的字符中没有制符表,但执行结果却显示有四个制表符。这是因为制表符它就是一个缩进(Tab)。main 函数中含有四个缩进,这就是四个制表符的来源。
  2. 结果中的代码是我省略的代码。这也是为什么复制我给出的代码却没有图中的执行效果(标题与"Press any key to exit".)。这些代码只是用来修改标题,添加一个结尾的,我认为它们有些太占地方,就没有放上来。

=========

习题 1-9

练习 1-9
首先,题目让我们把输入复制到输出,实际上就是输入什么就打印什么。多个空格用一个空格代替,这个我们先设置一个变量并初始为零,再判断输入的字符是不是空格。如果是空格,再判断下一个字符是不是空格。如果是,这个变量就加一,如果不是,这个变量就归零。再判断这个变量是否大于1。如果大于一,输出空,否则就输出下一个字符。

  • 使用 getchar() 获得输入。
  • 设置一个变量 = 0。
  • 判断输入是否是空格。如果是,再判断下一个字符是不是空格。
  • 如果下一个字符是空格,变量加一;否则,变量归零。
  • 判断变量是否大于一。如果大于一,则不输出;如果不大于一,输出字符。

代码如下:

#include 

int main()
{
	int SpaceNum,word;
	SpaceNum = 0;
	while((word = getchar()) != EOF)
	{
		if(word == ' ')
		{
			++SpaceNum;
		}
		else
		{
			SpaceNum = 0;
		}
		
		if(SpaceNum > 1)
		{
			;
		}
		else
		{
			putchar(word);
		}
	}
	return 0;
}

执行结果:
《C程序设计语言》第二版 课后习题_第9张图片
题末

  1. 程序其实可以再简化以下,直接用 putchar(word),这里的 word 的值其实是 ASCII 表中字符对应的值。

=========

习题 1-10

练习 1-10
这道题具体的思路和 习题 1-9 差不多。只要判断输入字符是不是这些转移字符,再 printf 出这个字符来就行了。

  • 使用 getchar() 获得输入。
  • 判断获得的输入是否为制符表,回退符,反斜杠。如果是,就用 printf 打印 \t \b \\,否则 putchar()。

代码如下:

#include 

int main()
{
	int word;
	while((word = getchar()) != EOF)
	{
		if(word == '\t')
			printf("\\t");
		if(word == '\\')
			printf("\\\\");
		if(word == '\b')
			printf("\\b");
		
		if(word != '\t' && word != '\\' && word != '\b')
			putchar(word);
	}
	return 0;
}

执行结果:
《C程序设计语言》第二版 课后习题_第10张图片

==========

习题 1-11

练习 1-11
这里先鸽一下。估计要鸽很久,至少要等到我高考完了之后(没准我心血来潮读了高四高五呢)。
下面我专门更新一下习题 1-13.

==========

习题 1-13

习题 1-13
题目让我们编写一个程序,打印输入单词长度的直方图。实际上就是统计输入额内容中,单词长度为1的单词有多少个,单词长度为2的单词有多少个……然后再把结果打印出来。
首先我们给单词下一个定义(这里的定义是我自己的想法,不一定是正确的,也不一定是里奇的想法):
不包含\t \n与空格的一串连续的字母
有了定义就简单了。
首先,我们设置一个变量 WordLength,用于临时保存单词的长度,然后开始读取单词的长度,如果读到了 \t \n 或者是空格,就说明这个单词结束了,停止计算单词的长度,然后把读到的长度保存到一个变量里面去,临时保存长度的变量 WordLength 归零,重新开始新一轮的计算。等到所有内容都计算完后,开始打表。

  • 计算所有单词的长度并保存数据。
  • 打表。

1. 打水平直方图

水平直方图比较简单。下面我假设长度为 3 的单词有 5 个,且所有的单词长度都在区间 [1,20] 中。
首先我们可以设置一个变量 Num 变量,赋值1;设置一个 PrintChar 变量,赋值1。
打印表头3 |,表示这一行是长度为 3 的单词,并且用 | 将表头与表隔开来。
然后用 PrintChart 的值去与 5 比较,如果 PrintChart ≤ 5,就打印一个■表示1格,并且 PrintfChart 自加1。如果 PrintfChart >5,那么就打印 [5] 表示有 5 个单词的长度为 3。

  • 设置一个变量并赋值1,然后这个将变量与某个单词长度的个数去比较。如果这个变量小于等于个数,打印一个■,否则就打印个数,然后转行进行新一轮的打印。

代码如下:

#include  
#include 

int main()
{
	// 设置标题 
	SetConsoleTitle("统计单词长度-水平直方图");
	printf("提示:输入完文本后,另起一行按下 Ctrl + z 结束输入。\n");
	
	// 初始化 保存相应单词长度的单词数量 的数组 和其他变量 
	int WordLengthNum[21] = {0};
	int Num;
	int WordLength = 0;
	int PrintChart = 1;
	int word;
	
	// 获取单词长度并保存 
	while((word = getchar()) != EOF)
	{
		if(word == '\t'||word == '\n'||word == ' ')
		{
			++WordLengthNum[WordLength];
			WordLength = 0;
		}
		else
		{
			++WordLength;
		}
	}
	
	system("cls");// 清屏,把上面我们输入的内容清除 
	
	// 绘制直方图
	printf("==========\n下面是我们要打印的水平表\n==========\n");
	for(Num = 1;Num <= 20;++Num)
	{
		printf("%d |",Num);
		for(PrintChart = 1; PrintChart <= WordLengthNum[Num];++PrintChart)
		{
			printf("■");
		}
		printf("[%d]\n",WordLengthNum[Num]);
	} 
	printf("==========\n");
	printf("Press any key to exit.");
	system("pause>nul"); 
	return 0;
}

我们用下面的示例文本放到程序里面去。

a a a a a a a a a a
bb bb bb bb bb bb bb
ccc ccc ccc ccc
dddd dddd dddd dddd dddd dddd dddd
eeeee eeeee eeeee eeeee eeeee
ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
ggggggg ggggggg ggggggg

上面的文本中,a有10个,bb有7个,ccc有4个,dddd有7个,eeeee有5个,ffffff有8个,ggggggg有3个,它们分别对应着单词长度为1-7的单词数量。
执行结果:
《C程序设计语言》第二版 课后习题_第11张图片
完美运行。
但当我们输入的单词有几十个甚至是上百个上千个,很可能会出现下面的情况
《C程序设计语言》第二版 课后习题_第12张图片
那么这种情况要怎么解决呢?
根据我多年写批处理的经验,我们只需要添加一段代码,修改一下缓冲区的大小,把水平方向的缓冲区拉长就可以了。(不是修改这个窗口的大小!!)
具体怎么实现我也不知道,我百度了一下,找到了代码。
代码如下:

#include 

int main()
{
	// 设置缓冲区的大小 
	SMALL_RECT winPon={0,0,25,10};
	HANDLE con=GetStdHandle(STD_OUTPUT_HANDLE);
	COORD buf={10000,25};// 缓冲区长10000,高25 
	SetConsoleScreenBufferSize(con,buf);
}
// 包含头文件 windows.h 后直接把 main 中的代码插到程序的 main 中就行了。

修改之后就会发现,窗口底部多了个横着的滚动条,我们可以拖动滚动条来看数据。
最后的效果:
《C程序设计语言》第二版 课后习题_第13张图片
OK,水平表就这么打好了。

2. 打垂直直方图

垂直直方图比较困难。但不是不能实现。
C语言它是一行一行输入输出的,不能一列一列地输出(可能可以但我不知道)。那我们只能按着它的习惯来横着输出垂直的直方图。
先写到这,上课去了。

你可能感兴趣的:(C语言习题)