《C程序设计语言》(《The C Programming Language》)第二版第一章练习题

1-1:
在你自己的系统中运行“hello world”程序,再有意去掉程序中的部分内容,看看会得到什么出错信息

#include<stdio.h>
int main()
{
	printf("Hello, World!\n");
	return 0;
}
/*自由删除程序中部分代码,查看运行结果*/

1-2:
做个实验,当printf函数的参数字符串中包含\c(其中c是上面的转义字符序列中未曾列出的某一个字符)时,观察一下会出现什么情况

#include<stdio.h>
int main()
{
	printf("Hello, World!\c");
	return 0;
}
/*打印结果为Hello, World!c,\c打印结果为c,\\c打印结果为\c*/

1-3:
修改温度转换程序,使之能在转换表的顶部打印一个标题

#include <stdio.h>
 
int main()
{
	float fahr, celsius;
	float lower, upper, step;
 
	lower = 0;
	upper = 300;
	step = 20;
 
	printf("温度转换程序\n");
	printf("华氏温度 \t 摄氏温度\n");
	
	fahr = lower;
	while (fahr <= upper)
	{
		celsius = (5.0 / 9.0) * (fahr - 32.0);
		printf("%5.0f \t\t %6.1f\n", fahr, celsius);
		fahr = fahr + step;
	}
	return 0;
}

1-4:
编写一个程序打印摄氏温度转换为相应华氏温度的转换表

#include <stdio.h>
 
int main()
{
	float fahr, celsius;
	float lower, upper, step;
 
	lower = 0;
	upper = 300;
	step = 20;
 
	printf("温度转换程序\n");
	printf("摄氏温度 \t 华氏温度\n");
	
	celsius = lower;
	while (celsius <= upper)
	{
		fahr = (9.0 * celsius) / 5.0 + 32.0;
		printf("%5.0f \t\t %6.1f\n", celsius, fahr);
		celsius = celsius + step;
	}
	return 0;
}

1-5:
修改温度转换程序,要求以逆序(即按照从300度到0度的顺序)打印温度转换表

#include <stdio.h>
 
int main()
{
	float fahr;
 
	printf("温度转换程序\n");
	printf("摄氏温度 \t 华氏温度\n");
	
	for(fahr = 300.0; fahr >= 0.0; fahr = fahr - 20.0)
		printf("%5.0f \t\t %6.1f\n", fahr, (5.0 / 9.0) * (fahr - 32.0));
	return 0;
}

1-6:
验证表达式getchar() != EOF的值是0还是1

#include <stdio.h>
 
int main()
{
	int c;

	while((c = getchar()) != EOF)
	{
		printf("%d ", c != EOF);
		putchar(c);
	}
	printf("%d ", c != EOF);
	return 0;
}

1-7:
编写一个打印EOF值的程序

#include <stdio.h>
int main()
{
	printf("EOF : %d\n", EOF);
	return 0;
}

1-8:
编写一个统计空格、制表符与换行符个数的程序

#include <stdio.h>
int main()
{
	int c, space, table, line;//space表示空格,table为制表符,line为换行符
	space = table = line = 0;
	while((c = getchar()) != EOF)
	{
		if(c == ' ')
			++space;
		else if(c == '\t')
			++table;
		else if(c == '\n')
			++line;
	}
	printf("space : %d \n table : %d \n line : %d \n", space, table, line);
	return 0;
}

1-9:
编写一个将输入复制到输出的程序,并将其中连续的多个空格用一个空格代替

#include <stdio.h>
int main()
{
	int c, status;
	status = 1;//将status初始化为1,可丢弃第一行非空格字符前的所有空格
	//如果不需要,就将其初始化为0
	while((c = getchar()) != EOF)
	{
		if(c == ' ')	
		{
			if(status == 0)
				putchar(c);

			status = 1;
		}
		else if(c != ' ')
		{
			putchar(c);
			status = 0;
		}
	}
	return 0;
}

1-10:
编写一个将输入复制到输出的程序,并将其中的制表符替换为\t,把回退符替换为\b,把反斜杠替换为\。这样就可以将制表符与回退符以可见的方式显示出来

#include <stdio.h>
int main()
{
	int c;
	while((c = getchar()) != EOF)
	{
		if(c == '\t')	
		{
			printf("\\t");
		}
		else if(c == '\b')
		{
			printf("\\b");
		}
		else if(c == '\\')
		{
			printf("\\\\");
		}
		else
			putchar(c);
	}
	return 0;
}

1-11:
你准备如何测试单词计数程序?如果程序中存在某种错误,那么什么样的输入最可能发现这类错误

#include <stdio.h>
 
#define IN 1
#define OUT	0
 
int main()
{
	int c, n1, nw, nc, state;
 
	state = OUT;
	n1 = nw = nc = 0;
 
	while ((c = getchar()) != EOF)
	{
		++nc;
		if (c == '\n')
			++n1;
 
		if (c == ' ' || c == '\n' || c == '\t')
		{
			state = OUT;
		}
 
		else if (state == OUT)
		{
			state = IN;
			++nw;
		}
 
	}
 
	printf("%d %d %d \n", n1, nw, nc);
 
	return 0;
}
/*此程序对于单词的判定比较模糊,假设一个!标点左右都为空格时,这个标点也会被判定为单词,以后学习ctype.h后,可以对改程序进行改进*/

1-12:
编写一个程序,以每行一个单词的形式打印其输入

#include <stdio.h>
int main()
{
	int c, status;
	status = 1;//将status初始化为1,可丢弃第一行非空格字符前的所有空格和换行符
	while((c = getchar()) != EOF)
	{
		if(c == ' ' || c == '\n' || c == '\t')	
		{
			if(status == 0)
				putchar('\n');

			status = 1;
		}
		else if(c != ' ' && c != '\n' && c != '\t')
		{
			putchar(c);
			status = 0;
		}
	}
	return 0;

}

1-13、1-14:
编写一个程序,打印输入中单词长度以及各个字符出现的频度的直方图,水平方向的直方图比较容易绘制,垂直方向的直方图则要困难些

#include<stdio.h>

#define MAXLEN 20 //最大单词长度
#define MAXCHAR 128 //ASCII码表中字符数

int main(void)
{
	int c, i;
	int nc = 0;
	int wordlen[MAXLEN]; //统计单词长度
	int charnum[MAXCHAR]; //统计字符频率

	for(i = 0; i < MAXLEN; i++)
		wordlen[i] = 0;

	for(i = 0; i < MAXCHAR; i++)
		charnum[i] = 0;

	while((c = getchar()) != EOF)
	{
		if(c == ' ' || c == '\t' || c == '\n')
		{
			if(nc > 0)
			{
				++wordlen[nc - 1];//单词长度为i时,将其放在wordlen[i - 1]元素中
				nc = 0;//重置单词长度
			}
		}
		else
			++nc;//累计单词长度

		++charnum[c - 0];//累计字符出现频率
	}
	for(i = 0; i < MAXLEN; i++)
	{
		printf("单词长度为%2d: ", i + 1);

		while(wordlen[i] > 0)
		{
			printf("%c ", 22);//ASCII码表22的字符形式为一个方框
			wordlen[i]--;
		}
		
		putchar('\n');
	}

	for(i = 0; i < MAXCHAR; i++)
	{
		if(i < 32)
			printf("十进制非打印字符%d:", i);
		else
			printf("可打印字符%2c:", i);

		while(charnum[i] > 0)
		{
			printf("%c ", 22);
			charnum[i]--;
		}
		
		putchar('\n');
	}

	return 0;
}

1-15:
重新编写1.2节中的温度转换程序,使用函数实现温度转换计算

#include <stdio.h>
float transform(float fah);
int main()
{
	float fahr, celsius;
	float lower, upper, step;
 
	lower = 0;
	upper = 300;
	step = 20;
 
	printf("温度转换程序\n");
	printf("华氏温度 \t 摄氏温度\n");
	
	for(fahr = lower; fahr <= upper; fahr += step)
	{
		
		printf("%5.0f \t\t %6.1f\n", fahr, transform(fahr));
	}
	return 0;
}

float transform(float fah)
{
	return (5.0 / 9.0) * (fah - 32.0);
}

1-16:
修改打印最长文本行的程序的主程序main,使之可以打印任意长度的输入行的长度,并尽可能多地打印文本

/*此题的设计思路为将所有的输入行拷贝到一个字符数组中,每条输入行紧跟在上一输入行后面,同时统计所有输入行的总长度,防止总长超过最大长度,造成溢出*/
#include <stdio.h>
#define MAXLINE 1000
 
int getline(char line[], int maxline);
void copy(char to[], char from[], int len, int tol);
 
int main()
{		
	int length = 0;//当前行的长度
	int total = 0;//所有输入行总长
	char line[MAXLINE];		
	char all[MAXLINE];	

	while ((length = getline(line, MAXLINE)) > 0)//length记录当前字符串的长度
	{
		copy(all, line, length, total);//此时传入的total其实是当前字符串之前的字符串总长
		total = total + length;//将当前字符串长度计入总长,进入下一次迭代
	}
 
	if (total > 0)	
	{
		printf("%s", all);
	}
	return 0;
}
 
int getline(char s[], int lim)
{
	int c, i;
 
	for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
	{
			s[i] = c;
	}
	if (c == '\n')
	{
		s[i] = c;
		++i;//向后移一位,i的值其实等于字符串的实际长度,也就是说假如当前字符串为asdd,占用数组0-3总计4个元素,i的值为4
	}
	return i;
}
 
void copy(char to[], char from[], int len, int tol)
{
	int i;
	for(i = tol; i < len + tol; i++)//tol总是等于字符串的实际长度,作用是直接从上一字符串的末尾开始写入,同时可以擦除掉上一字符串末尾的空字符
	{
		to[i] = from[i - tol];

		if((len + tol) <= (MAXLINE - 1))//如果总长没有超过最大长度
		{
			to[len + tol] = '\0';//在所有字符串后面添加空字符,标记字符串结束
		}

		else//如果超过最大长度
		{
			to[MAXLINE - 1] = '\0';//将数组最后一个元素替换为空字符
		}
	}
}

1-17:
编写一个程序,打印长度大于80个字符的所有输入行

/*此题只需要在上一程序的基础上加入一个if语句就行了*/
#include <stdio.h>
#define MAXLINE 1000
 
int getline(char line[], int maxline);
void copy(char to[], char from[], int len, int tol);
 
int main()
{		
	int length = 0;
	int total = 0;
	char line[MAXLINE];		
	char all[MAXLINE];	

	while ((length = getline(line, MAXLINE)) > 0)
	{
		if(length > 10)
		{
			copy(all, line, length, total);
		    total = total + length;
		}
	}
 
	if (total > 0)	
	{
		printf("%s", all);
	}
	return 0;
}
 
int getline(char s[], int lim)
{
	int c, i;
 
	for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
	{
			s[i] = c;
	}
	if (c == '\n')
	{
		s[i] = c;
		++i;
	}
	return i;//返回的i值为字符串中所有字符的数量
}
 
void copy(char to[], char from[], int len, int tol)
{
	int i;
	for(i = tol; i < len + tol; i++)
	{
		to[i] = from[i - tol];

		if((len + tol) <= (MAXLINE - 1))
		{
			to[len + tol] = '\0';
		}

		else
		{
			to[MAXLINE - 1] = '\0';
		}
	}
}

1-18:
编写一个程序,删除每个输入行末尾的空格即制表符,并删除完全是空格的行

#include <stdio.h>
#define MAXLINE 1000
 
int getline(char line[], int maxline);
void copy(char to[], char from[], int len);
 
int main()
{
	int length;
	char line[MAXLINE];	
	char copyline[MAXLINE];
 
	while ((length = getline(line, MAXLINE)) > 0)
	{
		copy(copyline, line, length);
		
		if(copyline[0] == '\0')
			printf("无效行\n");
		else
			printf("%s", copyline);
	}

	return 0;
}
 
int getline(char s[], int lim)
{
	int c, i;
 
	for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
		s[i] = c;

	if (c == '\n')
	{
		s[i] = c;
		++i;
	}
 
	s[i] = '\0';
 
	return i;
}
 
void copy(char to[], char from[], int len)
{
	int i;

	for(i = len - 2; (from[i] == ' ' || from[i] == '\t') && i >= 0; i--)//从换行符的前一字符开始循环直到遇到非空格、非制表字符或者i小于0
		;//空语句
	
	if(i >= 0)//如果i大于等于0
	{
		from[i + 1] = '\n';
	    from[i + 2] = '\0';
	}
	else//如果i小于0
		from[0] = '\0';

	i = 0;
	while((to[i] = from[i]) != '\0')
		++i;
}

1-19:
编写函数reverse(s),将字符串s中的字符顺序颠倒过来。使用函数编写一个程序,每次颠倒一个输入行中的字符顺序

#include <stdio.h>
#define MAXLINE 1000
 
int getline(char line[], int maxline);
void reverse(char s[]);
 
int main()
{
	int length;
	char line[MAXLINE];
 
	while ((length = getline(line, MAXLINE)) > 0)
	{
		reverse(line);
		printf("%s", line);
	}

	return 0;
}
 
int getline(char s[], int lim)
{
	int c, i;
 
	for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
		s[i] = c;

	if (c == '\n')
	{
		s[i] = c;
		++i;
	}
 
	s[i] = '\0';
	return i;
}
 
void reverse(char s[])
{
	int i, j, temp;
	
	for(i = 0; s[i] != '\0'; i++)//i跳出循环时是处于空字符
		;
	
	j = i - 2;//i - 2表示此时处于换行符的前一字符
	for(i = 0; i <= j / 2; i++)//循环不用迭代j次,只需要迭代j/2次就行了
	{
		temp = s[j - i];//temp是临时存储
		s[j - i] = s[i];
		s[i] = temp;
	}
}

1-20:
编写程序detab,将输入中的制表符替换成适当数量的空格,使空格充满到下一制表符终止位的地方。假设制表符终止位的位置是固定的,比如每隔n列就会出现一个制表符终止位。n应该作为变量还是常量符号呢

#include <stdio.h>
#define MAXLINE 1000
#define Tabsize 8//制表符的长度时固定的,在本系统中其长度为8个字符
 
int getline(char line[], int maxline);
 
int main()
{
	char line[MAXLINE];
	int i, size, all;
 
	while (getline(line, MAXLINE) > 0)
	{
		for(i = 0, all = 0; line[i] != '\0'; i++)
		{
			if(line[i] == '\t')
			{
				size = Tabsize - (all % Tabsize);//计算需要多少个空格填充制表符所占字符长度
				while(size > 0)
				{
					putchar(' ');
					all++;
					size--;
				}
			}
			else
			{
				putchar(line[i]);
				all++;
			}
		}
	}

	return 0;
}
 
int getline(char s[], int lim)
{
	int c, i;
 
	for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
		s[i] = c;

	if (c == '\n')
	{
		s[i] = c;
		++i;
	}
 
	s[i] = '\0';
	return i;
}

1-21:
编写程序entab,将空格串替换为最少数量的制表符和空格,但要保持单词之间的间隔不变,假设制表符终止位的位置与练习1-20的detab程序的情况相同。当使用一个制表符或者一个空格都可以到达下一制表符终止位时,选用哪一种替换字符比较好

/*这道题抄了一下其他博主的答案*/
#include <stdio.h>
#define MAXLINE 1000
#define Tabsize 8//制表符的长度时固定的,在本系统中其长度为8个字符
 
int getline(char line[], int maxline);
 
int main()
{
	char line[MAXLINE];
	int i, space;
 
	while (getline(line, MAXLINE) > 0)
	{
		for(i = 0, space = 0; line[i] != '\0'; i++)
		{
			if(line[i] == ' ')
			{
				if(i % Tabsize != 7)//i从0开始,因此第8*n个元素其下标求模8为7
					space++;//标记空格数

				else if(i % Tabsize == 7)//每经过一次制表符的终止位就打印一次制表符
				{
					space = 0;//将空格数清零
					putchar('\t');
				}
			}
			else
			{
				if(space > 0)//当空格没有超过制表符终止位时,打印空格
				{
					while(space > 0)
					{
						putchar(' ');
						space--;
					}
				}
				putchar(line[i]);
			}
		}
	}

	return 0;
}
 
int getline(char s[], int lim)
{
	int c, i;
 
	for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
		s[i] = c;

	if (c == '\n')
	{
		s[i] = c;
		++i;
	}
 
	s[i] = '\0';
	return i;
}

1-22:
编写一个程序,把较长的输入行“折”成短一些的两行或多行,折行的位置在输入行的第n列之前的最后一个非空格之后。要保证程序能够智能的处理输入行很长以及在指定位置的列前没有空格或制表符时的情况

#include <stdio.h>
#define MAXLINE 1000
#define SIZE 50    //长度阈值

int getline(char line[], int maxline);
 
int main()
{
	char line[MAXLINE];
	int len, i, j;
 
	while ((len = getline(line, MAXLINE)) > 0)
	{
		if (len <= SIZE)
			;

		else
		{
			for(i = SIZE - 1, j = 0; i <= len; j = i, i += SIZE)
			{
				while(line[i] != ' ' && line[i] != '\t' && i >= j)
					i--; //i值递减,直到查找到空格或者制表符
				line[i] = '\n';
			}
		}

		printf("%s", line);
	}

	return 0;
}
 
int getline(char s[], int lim)
{
	int c, i;
 
	for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
		s[i] = c;

	if (c == '\n')
	{
		s[i] = c;
		++i;
	}
 
	s[i] = '\0';
	return i;
}

1-23:
编写一个程序删除C语言程序中的所有注释语句。要正确处理带引号的字符串与字符常量。在C语言中,注释不允许嵌套

#include <stdio.h>
#define MAXLINE 1000

int getline(char line[], int maxline);
 
int main()
{
	char line[MAXLINE];
	int len, quote, i, j;

	while ((len = getline(line, MAXLINE)) > 0)
	{
		quote = 0;

		for(i = 0; i <= len; i++)
		{
			if(line[i] == '"')//进入双引号quote为1,出双引号quote为0
				quote = !quote;

			if(line[i] == '/' && line[i + 1] == '/' && quote == 0)
			{
				j = i;
				while(line[j] != '\n')
				{
					line[j] = ' ';
					j++;
				}
			}
			if(line[i] == '/' && line[i + 1] == '*' && quote == 0)
			{
				j = i;
				while(line[j] != '*' || line[j + 1] != '/')
				{
					line[j] = ' ';
					j++;
				}
				line[j] = ' ';
				line[j + 1] = ' ';
			}

		}
		for(i = 0; line[i] != '\0'; i++)
			printf("%c", line[i]);
	}

	return 0;
}
 
int getline(char s[], int lim)
{
	int c, i;
 
	for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
		s[i] = c;

	if (c == '\n')
	{
		s[i] = c;
		++i;
	}
 
	s[i] = '\0';
	return i;
}

1-24:
编写一个程序,查找C语言程序中的基本语法错误,如圆括号、方括号、花括号不配对等。要正确处理引号(包含单引号和双引号)、转义字符序列与注释(如果读者想把程序编写成完全通用的程序,难度会比较大)

/*这个程序有点麻烦,只写了很简单的*/
#include <stdio.h>
#define MAXLINE 1000

int getline(char line[], int maxline);
 
int main()
{
	char line[MAXLINE];
	int len, i, quote;
	int dan_yin = 0;      //单引号
	int shuang_yin = 0;   //双引号
	int fang_kuo = 0;     //方括号
	int yuan_kuo = 0;     //圆括号
	int hua_kuo = 0;      //花括号


	while ((len = getline(line, MAXLINE)) > 0)
	{
		quote = 0;

		for(i = 0; i <= len; i++)
		{
			if(line[i] == '/' && line[i + 1] == '*')//进入注释
				quote = 1;
			if(line[i] == '*' && line[i + 1] == '/')//出注释
				quote = 0;

			if(!quote)//不在注释的前提下
			{
				if(line[i] == '(')
					yuan_kuo++;
				if(line[i] == ')')
					yuan_kuo--;

				if(line[i] == '[')
					fang_kuo++;
				if(line[i] == ']')
					fang_kuo--;

				if(line[i] == '{')
					hua_kuo++;
				if(line[i] == '}')
					hua_kuo--;

				if(line[i] == '\'')
					dan_yin++;
				if(line[i] == '\'')
					dan_yin--;

				if(line[i] == '"')
					shuang_yin++;
				if(line[i] == '"')
					shuang_yin--;
			}

		}
		if(quote)
			printf("注释符号未配对");
		if(yuan_kuo)
			printf("圆括号未配对");
		if(hua_kuo)
			printf("花括号未配对");
		if(fang_kuo)
			printf("方括号未配对");
		if(dan_yin)
			printf("单引号未配对");
		if(shuang_yin)
			printf("双引号号未配对");
	}
	return 0;
}
 
int getline(char s[], int lim)
{
	int c, i;
 
	for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
		s[i] = c;

	if (c == '\n')
	{
		s[i] = c;
		++i;
	}
 
	s[i] = '\0';
	return i;
}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值