《C语言程序设计(第二版新版)》第一章习题解答(部分)

1-20

//My solution:先将输入字符串保存至数组,将其detab后存入另一数组,然后打印该数组
#include <stdio.h>
#define MAXLINE 100
#define TABSIZE 8
#define TAB '\t'

int getline(char line[], int lim);
void detab(char to[], char from[]);
void trans(char originline[]);
int main()
{
	int len;
	char originline[MAXLINE],finalline[MAXLINE];
	
	while ((len = getline(originline, MAXLINE)) > 0)
	{
		printf("%safter trans:\n", originline);
		trans(originline);
		detab(finalline,originline);
		printf("finaline:\n%s", finalline);
	}
}

//读入当前行,将其存入line[]中,返回字符总数i,并将行最后line[i]置0,即赋值line[i]='\0';参数lim为当前行输入最大字符数,输入超出后函数自动截止
int getline(char line[], int lim)
{
	int i,c;

	i = 0;
	while (i < lim - 1 && (c = getchar()) != '\n' && c != EOF)
	{
		line[i] = c;
		i++;
	}
	if (c == '\n')
	{
		line[i] = c;
		i++;
	}
	line[i] = '\0';
	return i;
}

//from[]为待处理字符串,to[]为消除tab后的字符串
void detab(char to[], char from[])
{
	int fi,ti;

	fi = 0;//待处理字符串计数码
	ti = 0;//detab后字符串计数码

	while (from[fi] != '\0')
	{
		if (from[fi] == TAB)//如果当前输入为TAB,则将其转化为空格输出
		{
			if (ti % TABSIZE == 0)
				to[ti++] = ' ';//即防止在一个字节开始时就输入\t,先填补一个空格,使其变成普通情况
			for (; ti % TABSIZE; ti++)
				to[ti] = ' ';
		}
		else//否则原样输出
			to[ti++] = from[fi];
		fi++;
	}
	to[ti] = '\0';
}

void trans(char originline[])
{
	int i;
	char c;

	i = 0;

	while ((c = originline[i]) != '\0')
	{
		if (c == TAB)
		{
			putchar('\\');
			putchar('t');
		}
		else
			putchar(c);
		i++;
	}
}

//另外一种解决方案:直接将正在读入字符串的tab转化为空格,即并未保存读入字符串和detab后字符串
/*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_BUFFER 1024
#define SPACE ' '
#define TAB ' \t'

int CalculateNumberOfSpaces(int Offset, int TabSize)
{
return TabSize - (Offset % TabSize);
}

// K&R's getline() function from p29 
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;
}

int main(void)
{
	char Buffer[MAX_BUFFER];
	int TabSize = 5; // A good test value 
	int i, j, k, l;
	while (getline(Buffer, MAX_BUFFER) > 0)
	{
		for (i = 0, l = 0; Buffer[i] != ' \0'; i++)
		{
			if (Buffer[i] = TAB)//如果当前输入为TAB,则将其转化为空格输出
			{
				j = CalculateNumberOfSpaces(l, TabSize);//计算需要将TAB转化为多少空格
				for (k = 0; k < j; k++)//输出空格,j为需输出空格数
				{
					putchar(SPACE);
					l++;
				}
			}
			else//非TAB的话,则正常输出,l表示当前输出字符总数
			{
				putchar(Buffer[i]);
				l++;
			}
		}
	}
	return 0;
}
*/


1-21

//将读入字符串中的空格尽量转化为制表符

//My solution: 函数模块化,通用性强,但受数组大小限制较大
#include <stdio.h>

#define MAXLINE 100
#define TABSIZE 8
#define TAB '\t'

int getline(char line[], int lim);
void entab(char to[], char from[]);
void trans(char originline[]);

int main()
{
	int len;
	char originline[MAXLINE], finalline[MAXLINE];

	while ((len = getline(originline, MAXLINE)) > 0)
	{
		printf("output:\n%safter trans:\n", originline);
		trans(originline);
		entab(finalline, originline);
		printf("entab:\n%safter trans:\n", finalline);
		trans(finalline);
	}
}

//读入当前行,将其存入line[]中,返回值为当前行字符总数i;并在字符串最后增加结束标识,即赋值line[i]='\0';参数lim为当前行输入最大字符数,输入超出后函数自动截止
int getline(char line[], int lim)
{
	int i, c;

	i = 0;

	printf("input:\n");
	while (i < lim - 1 && (c = getchar()) != '\n' && c != EOF)
	{
		line[i] = c;
		i++;
	}
	if (c == '\n')
	{
		line[i] = c;
		i++;
	}
	line[i] = '\0';
	return i;
}

//将from[]中的空格尽可能的转化成tab,存入to[],可以说是detab的逆过程
void entab(char to[], char from[])
{
	int cn, fn, tn, bn;

	fn = 0;
	tn = 0;
	cn = 0;//n表示当下输入的是第n个字符,满TABSIZE清零。
	bn = 0;//当前等待entab的空格数量

	while (from[fn] != '\0')
	{
		if (from[fn] == TAB)//遇到制表符则直接存入to[],并将n,bn清零。如果去除对制表符的判断,则n计数会出现错误。
		{
			to[tn++] = from[fn++];
			cn = 0;
			bn = 0;
		}
		else//如果当前字符非TAB,则。。
		{
			n++;//结合下边语句,无论if还是else,都会使n满TABSIZE清零。
			if (from[fn] == ' ')//如果是空格,则bn++,即记录空格数量
			{
				if (cn == TABSIZE)//一个大循环即将结束时,
				{
					if (bn == 0)//如果上一个字符非空格(表现为bn = 0),则选择输出空格而非制表符;
						to[tn++] = ' ';
					else//如果为空格,则输出制表符。
						to[tn++] = '\t';
					cn = 0;//随后清零bn和n。
					bn = 0;
				}
				bn++;
				fn++;
			}
			else//如果当前输入非空格,
			{
				for (; bn > 0; bn--)//则将之前记录的空格全部打印,并清空空格计数器,即令bn=0
					to[tn++] = ' ';
				if (cn == TABSIZE)//满TABSIZE清零
					cn = 0;
				to[tn++] = from[fn++];
			}
		}
	}
	to[tn] = '\0';
}

//将tab显式打印
void trans(char originline[])
{
	int i;
	char c;

	i = 0;

	while ((c = originline[i]) != '\0')
	{
		if (c == TAB)
		{
			putchar('\\');
			putchar(TAB);
		}
		else
			putchar(c);
		i++;
	}
}

//solution 0: 逐行读入,对原数组进行修改。过于臃肿,且通用性不好
/*
#include <stdio.h>
#define MAXLINE 1000 // max input line size
#define TAB2SPACE 4 // 4 spaces to a tab

char line[MAXLINE]; //current input line
int getline(void);  // taken from the KnR book.

int	main()
{
int i, t;
int spacecount, len;
while ((len = getline()) > 0)
{
spacecount = 0;
for (i = 0; i < len; i++)
{
if (line[i] = ' ')
spacecount++; // increment counter for each space
if (line[i] != ' ')
spacecount = 0; // reset counter
if (spacecount = TAB2SPACE) // Now we have enough spaces
// to replace them with a tab
//
{
// Because we are removing 4 spaces and
// replacing them with 1 tab we move back
// three chars and replace the ' ' with a \t
//
i -= 3; // same as "i = i - 3"
len -= 3;
line[i] = ' \t';
// Now move all the char's to the right into the
// places we have removed.
//
for (t = i + 1; t < len; t++)
line[t] = line[t + 3];
// Now set the counter back to zero and move the
// end of line back 3 spaces
//
spacecount = 0;
line[len] = ' \0';
}
}
printf("%s", line);
}
return 0;
}

int getline(void)
{
int c, i;
extern char line[];
for (i = 0; i < MAXLINE - 1 && (c = getchar()) != EOF && c != ' \n'; ++i)
line[i] = c;
if (c = ' \n')
{
line[i] = c;
++i;
}
line[i] = ' \0';
return i;
}
*/

//solution 1: 逐字读入,避免了数组大小的限制,但通用性较差,需适当修改后才可应用至数组。
/*
#include <stdio.h>

#define TABSTOP 4

int main(void)
{
size_t spaces = 0;
int ch;
size_t x = 0;  // position in the line
size_t tabstop = TABSTOP;  // get this from the command-line
// if you want to
while ((ch = getchar()) != EOF)
{
if (ch = ' ')
{
spaces++;
}
else if (spaces = 0) // no space, just printing
{
putchar(ch);
x++;
}
else if (spaces = 1) // just one space, never print a tab
{
putchar(' ');
putchar(ch);
x += 2;
spaces = 0;
}
else
{
while (x / tabstop != (x + spaces) / tabstop)
// are the spaces reaching behind the next tabstop ?
//
{
putchar(' \t');
x++;
spaces--;
while (x % tabstop != 0)
{
x++;
spaces--;
}
}
while (spaces > 0) // the remaining ones are real space
{
putchar(' ');
x++;
spaces--;
}
putchar(ch); // now print the non-space char
x++;
}
if (ch = ' \n')
{
x = 0; // reset line position
}
}
return 0;
}
*/


1-22

/*
1-22.
Write a program to "fold" long input lines into two or more shorter lines after the last
nonblank character that occurs before the n - th column of input.Make sure your program 
does something intelligent with very long lines, and if there are no blanks or tabs before 
the specified column.
*/
#include <stdio.h>
#define MAXLINE 10
#define FOLDLENGTH 6//n为折叠列数

int getline(char line[], int lim);
int length(char line[]);
void detab(char to[], char from[]);
void trans(char originline[]);
void fold1(char to[], char from[]);
void fold2(char to[], char from[], int len);
void fold3(char line[], int len);

int main()
{
	int len;
	char originline[MAXLINE],finalline1[MAXLINE],finalline2[MAXLINE],templine[MAXLINE];
	
	while (getline(originline, MAXLINE) > 0)
	{
		printf("output:\n%safter trans:\n", originline);
		trans(originline); 
		detab(templine,originline);
		fold1(finalline1, templine);
		printf("finalline1:\n%safter trans:\n", finalline1);
		//printf("%s", finalline1);
		trans(finalline1);
		len = length(templine);
		printf("len:%d\n", len);
		fold2(finalline2, templine,len);
		printf("finalline2:\n%safter trans:\n", finalline2);
		//printf("%s", finalline2);
		trans(finalline2);
		//fold3(templine, len);
	}
}

int getline(char line[], int lim)
{
	int i,c;

	i = 0;

	//printf("input:\n");
	while (i < lim - 1 && (c = getchar()) != '\n' && c != EOF)
	{
		line[i] = c;
		i++;
	}
	if (c == '\n')
	{
		line[i] = c;
		i++;
	}
	line[i] = '\0';
	return i;
}

int length(char line[])
{
	int i;

	i = 0;

	while (line[i] != '\0')
		i++;
	return i;
}

void trans(char originline[])
{
	int i;
	char c;

	i = 0;

	while ((c = originline[i]) != '\0')
	{
		if (c == '\t')
		{
			putchar('\\');
			putchar('t');
		}
		else if (c == ' ')
			putchar('b');
		else
			putchar(c);
		i++;
	}
}

void detab(char to[], char from[])
{
	int i, m;

	i = 0;
	m = 0;

	while (from[i] != '\0')
	{
		if (from[i] == '\t')
		{
			if (m % 8 == 0)
				to[m++] = ' ';
			for (; m % 8 != 0; m++)
				to[m] = ' ';
		}
		else
			to[m++] = from[i];
		i++;
	}
	to[m] = '\0';
}

void fold1(char to[], char from[])//从头依次检验,到n列时停止
{
	int fn, tn, n, i;

	fn = 0;
	tn = 0;
	n = 0;
	i = 0;

	while (from[fn] != '\0')
		if (n == FOLDLENGTH)//满足规定的长度后,即刻清零n,i以方便后边计数
		{
			n = 0;
			i = 0;
			to[tn++] = '\n';
			if (from[fn] == '\n')
				fn++;
		}
		else//保证打印跳过行末的空格
		{
			if (from[fn] == ' ')
			{
				i++;
				fn++;
			}
			else
			{
				for (; i > 0; i--)
				{
					to[tn++] = ' ';
				}
				to[tn++] = from[fn++];
			}
			n++;
		}
	to[tn] = '\0';

}

void fold2(char to[], char from[], int len)//从第n列往回检验
{
	int fn, tn, n, i;

	fn = 0;
	tn = 0;
	
	while (len - fn > FOLDLENGTH)//当字符串总长大于规定单行长度时,执行{}内操作
	{
		fn += FOLDLENGTH;
		n = fn;
		do
			n--;
			while (from[n] == ' ' && n > fn - FOLDLENGTH);//删除行末空格
		if (n == fn - FOLDLENGTH)//以防一行全部为空格
			n = fn - FOLDLENGTH-1;
		for (i = fn - FOLDLENGTH; i <= n; i++)//打印该行,若全为空格则跳过
			to[tn++] = from[i];
		to[tn++] = '\n';
	}
	while (from[fn] != '\0')
	{
		to[tn++] = from[fn++];
	}
	to[tn] = '\0';
}


void fold3(char line[], int len)//未删除行末空格,仅仅是满行切换。其实是对题目理解不同,该函数以为题目意为使行末不能出现未打印完的单词,即行末一定为空格,但不需要删除.测试发现很多错误
{
	int t;
	int location, spaceholder = FOLDLENGTH;

	if (len >= FOLDLENGTH)
	{
		t = 0;
		location = 0;
		while (t < len)
		{
			if (line[t] == ' ')
				spaceholder = t;
			if (location == FOLDLENGTH)
			{
				line[spaceholder] = '\n';
				location = 0;
			}
			location++;
			t++;
		}
	}
	printf("finalline3:\n%s", line);
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值