C程序设计语言--第一章 导言

1.1 入门

学习一门新程序设计语言的唯一途径就是使用它编写程序,我们第一个C语言程序:

#include <stdio.h>

main()
{
	printf("hello world\n");
}
    程序简单的一些说明:一个C语言程序,无论其大小如何,都是由函数和变量组成的。函数中包含一些语句,以指定所要执行的计算操作;变量则用于存储计算过程中使用的值。通常情况下,函数的命名没有限制,但main是一个特殊的函数名---每个程序都从main函数的起点开始执行,这意味着每个程序都必须在某个位置包含一个main函数。

    用双引号括起来的字符序列称为“字符串”或者“字符串常量”,而“\n”称为转义字符。

习题1-1,习题1-2略过。


1.2 变量与算数表达式

#include <stdio.h>

/* 当fahr = 0,20,...,300时,
分别打印华氏温度与摄氏度对照表
*/
main()
{
	int fahr, celsius;
	int lower, upper, step;

	lower = 0;
	upper = 300;
	step = 20;

	fahr = lower;
	while (fahr <= upper){
		celsius = 5 * (fahr - 32) / 9;
		printf("%d\t%d\n", fahr, celsius);
		fahr = fahr + step;
	}
}
1. 用/**/分割起来的是注释,它可以用于简单的用于解释程序,使程序更易阅读。

2. 所有变量必须先声明后使用。声明用于说明变量的属性,它由一个类型名和一个变量表组成。

3. 良好的编程习惯是:每行只写一条语句,并在运算符两边各加上一个空格字符。

为了更加精确的计算温度,我们需要将整型数替换为浮点数:

#include <stdio.h>

/* 当fahr = 0,20,...,300时,
分别打印华氏温度与摄氏度对照表
*/
main()
{
	float fahr, celsius;
	int lower, upper, step;

	lower = 0;
	upper = 300;
	step = 20;

	fahr = lower;
	while (fahr <= upper){
		celsius = (5.0 / 9.0) * (fahr - 32.0);
		printf("%3.0f\t%6.1f\n", fahr, celsius);
		fahr = fahr + step;
	}
}
1. 就算浮点型常量取值整型,也要加上一个小数点,强调浮点性质。

2. printf的一些格式:%o表示八进制数;%x表示十六进制数;%c表示字符;%s表示字符串;%%表示百分号(%)本身。

习题1-3:

#include <stdio.h>

/* 当fahr = 0,20,...,300时,
分别打印华氏温度与摄氏度对照表
*/
main()
{
	float fahr, celsius;
	int lower, upper, step;

	lower = 0;
	upper = 300;
	step = 20;

	printf("华氏温度转换为摄氏度\n");
	fahr = lower;
	while (fahr <= upper){
		celsius = (5.0 / 9.0) * (fahr - 32.0);
		printf("%3.0f\t%6.1f\n", fahr, celsius);
		fahr = fahr + step;
	}
}
习题1-4:
#include <stdio.h>

/* 当fahr = 0,20,...,300时,
分别打印摄氏度与华氏温度对照表
*/
main()
{
	float fahr, celsius;
	int lower, upper, step;

	lower = 0;
	upper = 300;
	step = 20;

	printf("摄氏度转换为华氏温度\n");
	celsius = lower;
	while (celsius <= upper){
		fahr = 32.0 + 9.0 / 5.0 * celsius;
		printf("%6.1f\t%3.1f\n", celsius, fahr);
		celsius = celsius + step;
	}
}
程序输出:

习题1-5:

#include <stdio.h>

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

	lower = 0;
	upper = 300;
	step = 20;

	fahr = upper;
	while (fahr >= lower){
		celsius = (5.0 / 9.0) * (fahr - 32.0);
		printf("%6.1f\t%3.1f\n", celsius, fahr);
		fahr = fahr - step;
	}
}
程序输出:

1.4 符号常量

使用幻数0,300,20并不是好的编程习惯,我们可以通过符号常量(宏定义)方式改写程序:

#include <stdio.h>

#define		LOWER	0
#define		UPPER	300
#define		STEP	20

main()
{
	int		fahr;
	for (fahr = LOWER; fahr <= UPPER; fahr += STEP){
		printf("%3d\t%6.1f\n", fahr, (5.0 / 9.0) * (fahr - 32.0));
	}
}

1.5 字符输入/输出

标准库提供的输入/输出模型非常简单。无论文本从何处输入,输出到何处,其输入/输出都是按照字符流的方式处理。文本流是由多行字符构成的字符序列,而每行字符则由0个或多个字符组成,行末是一个换行符。

最基本的输入输出函数为:getchar()--读取单个字符,putchar(c)--打印字符c。

1.5.1 文件复制

#include <stdio.h>

main()
{
	int c;

	c = getchar();
	while (c != EOF){
		putchar(c);
		c = getchar();
	}
}
程序输入输出如下:

1. 这里c之所以声明为int而不是char,是因为我们要保证能够存储任何字符外还能存储特殊字符EOF(end of file).

2. c = getchar()之类的赋值操作是一个表达式,并且具有一个值,即赋值后左边变量保存的值。所以代码可以进行类似的简洁修改:

#include <stdio.h>

main()
{
	int c;

	while ((c = getchar()) != EOF){
		putchar(c);
	}
}
当处理长的表达式的时候,遇到算术符的优先级,加上括号是一个非常好的习惯。

习题1-6:

表达式getchar() != EOF永远为true,因为EOF本身无法用单个字符表示。EOF的值为-1,但是当你输入-1的时候,实际上输入了两个字符“-”,“1”。我们可以通过习题1-7知道EOF的准确值。

习题1-7:

#include <stdio.h>

main()
{
	printf("%d\n", EOF);
}
显示-1.

1.5.2 字符计数

#include <stdio.h>

main()
{
	long nc;

	nc = 0;
	while (getchar() != EOF)
	{
		++nc;
	}

	printf("%ld\n", nc);
}
程序输入输出:

我们可以用for循环简化(第一次看到这段代码的时候,我惊呆了)

#include <stdio.h>

main()
{
	double nc;

	for (nc = 0; getchar() != EOF; ++nc){
		;
	}

	printf("%.0f\n", nc);
}
程序输入输出:

我第一次明白,原来分号(“;”)可以这样用。

1.5.3 行计数

#include <stdio.h>

main()
{
	int c, nl;

	nl = 0;

	while ((c = getchar()) != EOF){
		if ('\n' == c){
			++nl;
		}
	}

	printf("%d\n", nl);
}
程序输入输出:

当然,我们也可以用下面的代码完成同样的工作(不推荐):

#include <stdio.h>

main()
{
	int c, nl;

	nl = 0;

	while ((c = getchar()) != EOF){
		if (10 == c){
			++nl;
		}
	}

	printf("%d\n", nl);
}
1. 单引号中的字符表示一个整型值,该值等于此字符在机器字符集中对应的数值,我们称之为字符常量。但是,它只不过是小的整型数的另一种写法而已(比如‘\n’代表10),但是‘\n’的意义更加清楚,且与特定的字符集无关。

习题1-8:

#include <stdio.h>

main()
{
	int c, ns, nt, nl;

	ns = 0;
	nt = 0;
	nl = 0;

	while ((c = getchar()) != EOF){
		if (' ' == c){
			ns++;
		}
		else if ('\t' == c){
			nt++;
		}
		else if ('\n' == c){
			nl++;
		}
	}

	printf("空格符为%d\n制表符为%d\n换行符为%d\n", ns, nt, nl);
}
程序输入输出:

习题1-9:

#include <stdio.h>

main()
{
	int		c;
	int	bSpace = 0;

	while ((c = getchar()) != EOF){
		if (' ' == c){
			bSpace = 1;
		}
		else{
			if (bSpace){
				putchar(' ');
				bSpace = 0;
			}
			putchar(c);
		}
	}
}
习题1-10:
#include <stdio.h>

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

#define	IN	1	/*在单词内*/
#define OUT	0	/*在单词外*/

main()
{
	int c, nl, nw, nc, state;

	state = OUT;
	nl = nw = nc = 0;
	while ((c = getchar()) != EOF){
		++nc; 
		if ('\n' == c){
			++nl;
		}

		if ((' ' == c) || ('\n' == c) || ('\t' == c)){
			state = OUT;
		}
		else if (state == OUT){
			state = IN;
			++nw;
		}
	}

	printf ("%d %d %d\n", nl, nw, nc);
}
程序输入输出:

习题1-12:

#include <stdio.h>

main()
{
	int c;

	int	nSpace = 0;
	while ((c = getchar()) != EOF){
		if ((' ' == c) || ('\t' == c)){
			nSpace = 1;
		}
		else{
			if (nSpace){
				nSpace = 0;
				putchar('\n');
			}
			putchar(c);
		}
	}
}
程序输入输出:


1.6 数组

#include <stdio.h>

main()
{
	int c, i, nwhite, nother;
	int ndigit[10];

	nwhite = nother = 0;
	for (i = 0; i < 10; i++){
		ndigit[i] = 0;
	}

	while ((c = getchar()) != EOF){
		if ((c >= '0') && (c <= '9')){
			++ndigit[c - '0'];
		}
		else if ((' ' == c) || ('\n' == c) || ('\t' == c)){
			++nwhite;
		}
		else{
			++nother;
		}
	}

	printf("digits =");
	for (i = 0; i < 10; ++i){
		printf(" %d", ndigit[i]);
	}
	printf(", white space = %d, other = %d", nwhite, nother);
}
只要明白,字符常量只是整型值的一种表达形式,那么这段代码将不难理解了。

习题1-13:

目前无法达到的一个高度是:通过EOF来显示所有的单词直方图结果,只要输入换行,则显示直方图的结果。

1-13-1: 水平直方图:

#include <stdio.h>

main()
{
	int c;

	int nCount = 0;	//单词的长度

	while ((c = getchar()) != EOF){
		if ((' ' != c) && ('\t' != c) && ('\n' != c)){
			putchar(c);
			nCount++;
		}
		else{
			if (nCount == 0)		//处理连续的空格符,制表符和换行符
				continue;
			putchar(':');
			while (--nCount >= 0){
				putchar('*');
			}
			putchar('\n');
			nCount = 0;		//这里进行计数的纠正,否则nCount会变成-1,导致计数不准确
		}
	}
}
程序输入输出:

垂直直方图:

#include <stdio.h>

int main(void)
{
	int c;
	int nSpace = 0;		//用于处理多空格,制表符情况
	int nCount = 0;		//用于处理:用*表示单词长度
	int nl = 0;			//用于判断显示是否换行

	char nArray[10][5];	//用于存储单词--每个单词的长度限制为5,因为要在屏幕上显示出来(当然,如果你的屏幕足够大,一个单词长度可以为100)
	char mArray[5][10];	//用于存储每个单词出现的星号
	int i = 0;
	int j = 0;
	for ( i = 0; i < 10; i++ ){
		for ( j = 0; j < 5; j++ ){
			nArray[ i ][ j ] = ' ';
		}
	}
	for ( i = 0; i < 5; i++ ){
		for ( j = 0; j < 10; j++ ){
			mArray[ i ][ j ] = ' ';
		}
	}

	i = j = 0;
	//显示单词和*的一个数组,比如二维数组的第一个元素是hello*****,后面加*号代表长度
	while ( ( c = getchar() ) != EOF ){
		if ( ( ' ' != c ) && ( '\t' != c ) && ( '\n' != c ) ){
			nSpace = 0;
			if ((j > 5) || (i > 9)){
				break;
			}
			nArray[i][j++] = c;
		}
		else{
			if (nSpace)			//说明是多空格,所以忽略,继续输入
				continue;
			nSpace = 1;
			nCount = j + 1;
			while ( --nCount ){
				mArray[ 5 - nCount ][ i ] = '*';	//这里的星号存放的顺序!!
			}
			i++;
			j = 0;
		}
	}

	for ( i = 0; i < 5; i++ ){
		for ( j = 0; j < 10; j++ ){
			printf("%c     ", mArray[ i ][ j ] );
		}
		printf("\n");
	}
	for ( i = 0; i < 10; i++ ){
		for ( j = 0; j < 5; j++ ){
			printf("%c", nArray[ i ][ j ] );
		}
		printf(" ");
	}

	return 0;
}

程序输出:

这里主要是为了适应输出的客观性,所以就限制了只能输出10个单词,每个单词的长度要小于等于5.当然,水平直方图也可以参考这个代码,可以输出的更漂亮一些.

PS:顺便吐槽一下买的<C程序设计语言>的参考书,什么破答案.还是自己写的比较有保障一些.

习题1-14:

#include <stdio.h>

main()
{
	int ndigits[52];
	int c;
	int i;
	for (i = 0; i < 52; i++){
		ndigits[i] = 0;
	}
	while ((c = getchar()) != EOF){
		if (c >= 'a' && c <= 'z'){
			++ndigits[c - 'a'];
		}
		else if (c >= 'A' && c <= 'Z'){
			++ndigits[c - 'A' + 26];
		}
	}
	for (c = 'a'; c <= 'z'; c++){
		printf("%c:%d\n", c, ndigits[c - 'a']);
	}
	for (c = 'A'; c <= 'Z'; c++){
		printf("%c:%d\n", c, ndigits[c - 'A' + 26]);
	}
}
如果显示出垂直方向的直方图,我倒也不会写。

1.7 函数

我们通常把函数定义中圆括号列表中出现的变量称为形式参数,而把函数调用中与形式参数对应的值称为实际参数。

1.8 参数---传值调用

C语言中“通过值”传递,而在C++中,可以通过“引用”传递。

在C中,可以通过指针的概念达到类似“引用”传递的效果。

1.9 字符数组

读取并打印最长行:

#include <stdio.h>
#define MAXLINE 1000

int getline(char line[], int maxline);
void copy(char to[], char from[]);

main()
{
	int len;
	int max;
	char line[MAXLINE];
	char longest[MAXLINE];

	max = 0;
	while ((len = getline(line, MAXLINE)) > 0){
		if (len > max){
			max = len;
			copy(longest, line);
		}
	}

	if (max > 0){
		printf("%s", longest);
	}

	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 i;
	i = 0; 
	while ((to[i] = from[i]) != '\0'){
		++i;
	}
}

习题1-16:

通过链表可以达到无限制的输入:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct NODE{
	int				value;
	struct NODE		*next;
} Node;

void printNode( Node *node )
{
	while ( node ){
		printf("%c", node->value);
		node = node->next;
	}
	printf("\n");
}

int main(void)
{
	int		count = 0;		//当前行的长度
	int		maxLine = 0;	//最大行的长度
	int		ch;
	Node	*node1 = NULL;	//这里node1一定要初始化(PS:之前我经常忘记,因为用的是静态的节点,导致自动初始化)
	Node	*tempNode = NULL;
	Node	*resultNode = NULL;	
	while ( ( ch = getchar() ) != EOF ){
		if ( ch != '\n' ){
			count++;
			tempNode = malloc( sizeof( Node ) );
			tempNode->value = ch;
			tempNode->next = node1;
			node1 = tempNode;
		}
		else if( count > maxLine ){
			Node *newNode;
			Node *deleteNode;
			maxLine = count;
			count = 0;
			while ( resultNode ){
				deleteNode = resultNode;
				resultNode = resultNode->next;
				free( deleteNode );				//这里进行节点的删除的时候,一定要建立一个临时的变量进行存储节点,对临时的变量进行删除
			}
			while ( node1 ){
				newNode = malloc( sizeof( Node ) );
				newNode->value = node1->value;
				newNode->next = resultNode;
				resultNode = newNode;
				node1 = node1->next;
			}
		}
	}

	printNode( resultNode );

	return 0;
}
程序输出:

习题1-17:对习题1-16稍做修改即可,长度大于10的输出:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct NODE{
	int				value;
	struct NODE		*next;
} Node;

void printNode( Node *node )
{
	printf("the line is : ");
	while ( node ){
		printf("%c", node->value);
		node = node->next;
	}
	printf("\n");
}

int main(void)
{
	int		count = 0;		//当前行的长度
	int		maxLine = 0;	//最大行的长度
	int		ch;
	Node	*node1 = NULL;	//这里node1一定要初始化(PS:之前我经常忘记,因为用的是静态的节点,导致自动初始化)
	Node	*tempNode = NULL;
	Node	*resultNode = NULL;	
	while ( ( ch = getchar() ) != EOF ){
		if ( ch != '\n' ){
			count++;
			tempNode = malloc( sizeof( Node ) );
			tempNode->value = ch;
			tempNode->next = node1;
			node1 = tempNode;
		}
		else {
			Node *newNode;
			Node *deleteNode;
			while ( resultNode ){
				deleteNode = resultNode;
				resultNode = resultNode->next;
				free( deleteNode );				//这里进行节点的删除的时候,一定要建立一个临时的变量进行存储节点,对临时的变量进行删除
			}
			while ( node1 ){
				newNode = malloc( sizeof( Node ) );
				newNode->value = node1->value;
				newNode->next = resultNode;
				resultNode = newNode;
				node1 = node1->next;
			}
			if ( count > 10 ){
				count = 0;
				printNode( resultNode );
			}
		}
	}

	return 0;
}
程序输出:

1-18:

第二个hello world中包含了换行符和多余的空格:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXLINE 128

int main(void)
{
	int		i = 0;
	char	arr[ MAXLINE ];
	int		lineLen = 0;

	for ( i = 0; i < MAXLINE; i++ ){
		arr[ i ] = '\0';
	}

	while ( NULL != fgets( arr, MAXLINE, stdin ) ){
		for ( i = MAXLINE - 1; i >= 0; i-- ){
			if ( ' ' == arr[ i ] || '\n' == arr[ i ] || '\t' == arr[ i ] ){
				arr[ i ] = '\0';
			}
			else if ( arr[ i ] != '\0' ){
				break;
			}
		}
		for ( i = 0; i < MAXLINE; i++ ){
			if ( '\0' == arr[ i ] ){
				lineLen = i;
				break;
			}
			putchar( arr[ i ] );
		}
		printf("\nthe line length is:%d\n", lineLen );	//这里不要用i来代表长度
		for ( i = 0; i < MAXLINE; i++ ){				//要对arr进行删除操作
			arr[ i ] = '\0';
		}
	}

	return 0;
}
程序输出:

1-19:

#include <stdio.h>

void reverse( char *string )
{
	char *temp = string;
	while ( *temp ){
		temp++;
	}
	temp--;		//'\0'要省略
	while ( temp > string ){
		char ch = *temp;
		*temp-- = *string;
		*string++ = ch;
	}
}

int main(void)
{
	char str1[] = "hello";
	char str2[] = "world";
	reverse( str1 );
	reverse( str2 );

	printf("%s\n", str1 );		//str1本身就代表指针,不要输出*str1
	printf("%s\n", str2 );

	return 0;
}
程序输出:

1.10 外部变量与作用域

由于自动变量只在函数调用执行期间存在,因此,在函数的两次调用之间,自动变量不保留前次调用时的赋值,且在每次进入函数时都要显式为其赋值.如果自动变量没有赋值,则其中存放的是无效值.

外部变量必须定义在所有函数之外,且只能定义一次,定义后编译器程序将为它分配存储单元.在每个需要访问外部变量的函数中,必须声明相应的外部变量,此时说明其类型.声明时可以用extern语句显式声明,也可以通过上下文隐式声明.

#include <stdio.h>

#define MAXLINE 100		//允许的输入行的最大长度

int max;				//到目前为止发现的最长行的长度
char line[ MAXLINE ];	//当前的输入行
char longest[ MAXLINE ];//用于保存最长的行

int getline( void );
void copy( void );

int main(void)
{
	int len;
	extern int max;
	extern char longest[];

	max = 0;
	while ( ( len = getline() ) > 0 ){
		if ( len > max ){
			max = len;
			copy();
		}
	}
	if ( max > 0 ){
		printf("%s", longest );
	}

	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 ( '\n' == c ){
		line[ i ] = c;
		i++;
	}
	line[ i ] = '\0';

	return i;
}

void copy( void )
{
	int i;
	extern char line[], longest[];
	i = 0;
	while ( ( longest[ i ] = line[ i ] ) != '\0' ){
		i++;
	}
}
如果程序包含在多个源文件中,而某个变量在file1文件中定义,在file2和file3文件中使用,那么在文件file2与file3中就需要使用extern声明来建立该变量与其定义之间的联系.

"定义"表示创建变量或分配存储单元,而"声明"指的是说明变量的性质,但并不分配存储单元.

1-20:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
	int ch;
	int temp;
	int isTab = 0;
	while ( ( ch = getchar() ) != EOF ){
		temp = ch;
		if ( '\\' == ch && 0 == isTab ){
			isTab = 1;
		}
		else{
			if ( isTab ){
				if ( 't' == ch ){
					isTab = 0;
					putchar( '\t' );
					continue;
				}
				else if ( '\\' != ch ){
					isTab = 0;
					putchar( '\\' );
				}
			}
			putchar( ch );
		}
	}

	return 0;
}
程序输出:

但是答案似乎不是这样写,答案如下:

#include <stdio.h>

#define TABINC 8

int main(void)
{
	int c, nb, pos;
	nb = 0;
	pos = 1;

	while ( ( c = getchar() ) != EOF ){
		if ( '\t' == c ){
			nb = TABINC - ( pos - 1 ) % TABINC;
			while ( nb > 0 ){
				putchar( ' ' );
				++pos;
				--nb;
			}
		}
		else if ( '\n' == c ){
			putchar( c );
			pos = 1;
		}
		else{
			putchar( c );
			++pos;
		}
	}
}
原来程序的含义是:将\t指定为8个(或者也可以4个)输出,看来我理解错误了.

1-21:题目没看懂其实.然后研究一下答案吧:

但是觉得这道程序貌似做无用功,把足够的空格符换成制表符输出,比如八个空格换成制表符,而一个制表符为4个空格,则只要输出4个空格就可以了.那为什么不直接计算有8个空格的时候,输出4个空格不就行了吗?

把答案粘贴出来吧,虽然我并不认可这种做法:

#include <stdio.h>

#define TABINC 8

int main(void)
{
	int c, nb, nt, pos;

	nb = 0;
	nt = 0;

	for ( pos = 1; ( c = getchar() ) != EOF; ++pos ){
		if ( ' ' == c ){
			if ( 0 != pos % TABINC ){
				++nb;
			}
			else{
				nb = 0;
				++nt;
			}
		}
		else{
			for ( ; nt > 0; --nt ){
				putchar( '\t' );
			}
			if ( '\t' == c ){
				nb = 0;
			}
			else{
				for ( ; nb > 0; --nb ){
					putchar( ' ' );
				}
			}
			putchar( c );
			if ( '\n' == c ){
				pos = 0;
			}
			else if ( '\t' == c ){
				pos = pos + ( TABINC - ( pos - 1 ) % TABINC ) - 1;
			}
		}
	}
}
1-22:

这是一种错误的思路,因为它严格按照书本上划分行了(我怀疑是书上翻译有问题的).第二段代码是自己个人觉得正确的代码.先把第一段代码copy上来:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXLINE 128

void showMulLine( char *string, int index )
{
	char *tempstr = string;
	int len = strlen( string );
	int tempLen;
	int realIndex = index;			//用于每次增加index

	if ( len <= index ){			//当一行的长度小于要分割的长度时,直接输出
		printf("%s\n", string );
		return;
	}
	
	while ( index < len ){
		tempLen = index;
		while ( tempLen ){
			if ( ' ' != string[ tempLen ] || '\t' != string[ tempLen ] ){		//略过空格和制表符
				break;
			}
			tempLen--;
		}
		while ( string < &tempstr[ tempLen ] ){		//这里有个隐藏的BUG,之前是写成string < &string[ tempLen ],但是string在循环体内变了,所以这个变成了死循环!!!
			putchar( *string );
			string++;
		}
		printf("\n");
		index += realIndex;
	}
	if ( index < len ){				//处理最后要分的行
		while ( len ){
			if ( ' ' != string[ len ] || '\t' != string[ len ] ){
				break;
			}
			len--;
		}
		while ( string < &tempstr[ len ] ){
			putchar( *string );
			string++;
		}
		printf("\n");
	}
}

int main(void)
{
	char arr[ MAXLINE ];
	while ( fgets( arr, MAXLINE, stdin ) != NULL ){
		showMulLine( arr, 10 );
	}

	return 0;
}
程序输出:

正确的代码应该可以将world单词放在第二行,而不是强行分开:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXLINE 128

void showMulLine( char *string, int index )
{
	char *tempStr = string;
	int	pos = 0;
	int tempPos = 0;	//临时的索引,用于处理分行中空格后面的连续空格和空格后存在单词的情况
	int tempIndex = 0;	//临时的索引,用于处理分行中空格出现的情况
	int isSpace = 0;	//判断是否出现空格
	int isMulSpace = 0;	//判断是否出现多个空格
	int isNewLine = 0;		//用于删除一行开头的空格
	while ( pos < index && '\n' != string[ pos ] ){
		if ( pos == index - 1 && ' ' != string[ pos ] ){	//用于处理超过一个单词超过index长度的情况
			putchar( string[ pos ] );
			string += pos;
			pos = 0;
			continue;
		}
		if ( ' ' == string[ pos ] ){
			isSpace = 1;
		}
		else{
			tempPos = pos;
			if ( !isSpace ){
				putchar( string[ pos ] );
			}
			else{
				isSpace = 0;
				tempIndex = index;
				//判断是否出现多个空格的情况
				while ( tempPos < tempIndex ){
					if ( ' ' == string[ tempIndex ] ){
						isMulSpace = 1;
						break;
					}
					tempIndex--;
				}
				if ( isMulSpace ){
					putchar( ' ' );		//存在多个空格情况下,补齐第一个空格
					isMulSpace = 0;
					while ( tempPos < tempIndex ){
						putchar( string[ tempPos ] );
						tempPos++;
					}
					tempPos++;	//存在多个空格情况下,将导致string的开头有个空格,故删除
				}
				putchar( '\n' );
				string += tempPos;
				pos = -1;	//因为最终pos都要执行自增,所以赋值为-1,导致下次循环从0开始
			}
		}
		pos++;
	}
}

int main(void)
{
	char arr[ MAXLINE ];
	while ( fgets( arr, MAXLINE, stdin ) != NULL ){
		showMulLine( arr, 10 );
	}

	return 0;
}
程序输出:

1.

2.

新的代码如下:

void showMulLine(char *line)
{
	char		arr[MAXLINE][MAXLINE] = {'\0'};
	int			i = 0;
	int			j = 0;
	int			isEnd = 0;
	int			size;		//数组的个数
	int			len;
	int			index = 0;
		
	//将输入的一行数据分割成以空白字符分割的字符串数组:hello   world   i  love ,则数组中存储["hello   ", "world   ", "i  ", "love "];
	while (*line) {
		if ((' ' == *line || '\t' == *line || '\n' == *line)) {
			arr[i][j++] = *line;
			line++;
			isEnd =1;
			continue;
		}
		if (' ' != *line && '\t' != *line && '\n' != *line) {
			if (isEnd) {
				j = 0;
				i++;
				arr[i][j++] = *line;
				isEnd = 0;
			} else {
				arr[i][j++] = *line;
			}
			line++;
		}
	}

	size = i;
	len = 0;
	index = 0;
	//以LENGTH为长度进行分割操作
	for (i = 0; i <= size; i++) {
		len += strlen(arr[i]);
		if (len < LENGTH) {
			index++;
			printf("%s", arr[i]);
		}
		else {
			if (index == 0) {
				printf("%s", arr[i]);
			}
			else {
				i--;
			}
			printf("\n");
			len = 0;
		}
	}
}



1-23:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXSIZE 128
#define LINENUM	20

int	isDoubleSlash;		//出现注释符'//'
int isSlashStar;		//出现注释符/**/

void dealLine( char *line, char **mulLine, int index )
{
	int len = strlen( line );
	char *newLine = malloc( len * sizeof( char ));
	char *temp = newLine;
	while ( '\n' != *line ){		//备注:getline是以换行符/n结束,而不是以\0结束
		if ( '/' == *line && '/' == *( line + 1 ) ){
			isDoubleSlash = 1;
		}
		else if ( '/' == *line && '*' == *( line + 1 ) ){
			isSlashStar = 1;
		}
		if ( isDoubleSlash ){	//出现'//',直接忽略后面的注释字符串
			isDoubleSlash = 0;
			*line = '\0';
			break;
		}
		if ( isSlashStar && '*' == *line && '/' == *( line + 1 ) && '/' != *( line - 1 ) ){	//防止出现/*/的情况
			isSlashStar = 0;
			line += 2;
			continue;
		}
		if ( !isSlashStar ){
			*temp = *line;
			temp++;
		}
		line++;
	}
	*temp = '\0';
	mulLine[ index ] = newLine;
}

int main(void)
{
	int		ch;
	char	line[ MAXSIZE ];
	char	*mulLine[ LINENUM ];
	int		index = 0;
	int		i = 0;
	int		j = 0;

	for ( i = 0; i < MAXSIZE; i++ ){
		line[ i ] = '\0';
	}
	for ( i = 0; i < LINENUM; i++ ){
		mulLine[ i ] = "";
	}

	while ( NULL != fgets( line, MAXSIZE, stdin ) ){
		dealLine( line, mulLine, index );
		index++;
	}

	printf("\nthe text is:\n");
	for ( i = 0; i < LINENUM; i++ ){
		if ( '\0' != mulLine[ i ][ 0 ] ){		//不要进行"" != mulLine[ i ]的判断
			printf("%s\n", mulLine[ i ] );
		}
	}

	return 0;
}
程序输出:

1-24:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXSIZE 128
#define LINENUM	20

int	isDoubleSlash;		//出现注释符'//'
int isSlashStar;		//出现注释符/**/

//对注释进行处理
void dealLine( char *line, char **mulLine, int index )
{
	int len = strlen( line );
	char *newLine = malloc( len * sizeof( char ));
	char *temp = newLine;
	while ( '\n' != *line ){		//备注:getline是以换行符/n结束,而不是以\0结束
		if ( '/' == *line && '/' == *( line + 1 ) ){
			isDoubleSlash = 1;
		}
		else if ( '/' == *line && '*' == *( line + 1 ) ){
			isSlashStar = 1;
		}
		if ( isDoubleSlash ){	//出现'//',直接忽略后面的注释字符串
			isDoubleSlash = 0;
			*line = '\0';
			break;
		}
		if ( isSlashStar && '*' == *line && '/' == *( line + 1 ) && '/' != *( line - 1 ) ){	//防止出现/*/的情况
			isSlashStar = 0;
			line += 2;
			continue;
		}
		if ( !isSlashStar ){
			*temp = *line;
			temp++;
		}
		line++;
	}
	*temp = '\0';
	mulLine[ index ] = newLine;
}

//对方括号进行处理
int dealSquareBrackets( char *line )
{
	int bracketNum = 0;
	while ( '\0' != *line ){
		if ( '[' == *line  && 0 == bracketNum ){
			bracketNum++;
		}
		else if ( ']' == *line && 0 != bracketNum ){
			bracketNum--;
		}
		if ( bracketNum < 0 ){
			return 1;
		}
		line++;
	}
	return bracketNum;
}

//对圆括号和花括号进行处理
int dealBrackets( char **mulLine )
{
	char *temp;
	int parenthesisNum = 0;	//判断圆括号的次数
	int braceNum = 0;		//判断花括号的次数
	int i = 0;
	int countNum = 0;
	int countParenthesisNum = 0;	//计算左圆括号出现的位置
	int countBraceNum = 0;			//计算左花括号出现的位置
	for ( i = 0; i < LINENUM; i++ ){
		temp = mulLine[ i ];
		while ( '\0' != *temp ){
			countNum++;
			if ( '(' == *temp ){
				countParenthesisNum = countNum;
				parenthesisNum++;
			}
			else if ( ')' == *temp ){
				parenthesisNum--;
			}
			else if ( '{' == *temp ){
				countBraceNum = countNum;
				braceNum++;
			}
			else if ( '}' == *temp ){
				braceNum--;
			}
			//右圆括号和右花括号不可出现在左圆括号和左花括号之前
			if ( parenthesisNum < 0 || braceNum < 0 ){
				return 1;
			}
			//圆括号中不可包含花括号
			if ( 0 != parenthesisNum && 0 != braceNum && ( countParenthesisNum < countBraceNum ) ){
				return 1;
			}
			//圆括号中不可出现分号';'
			if ( 0 != parenthesisNum && ';' == *temp ){
				return 1;
			}
			countNum = 0;
			countParenthesisNum = 0;
			countBraceNum = 0;
			temp++;
		}
	}
	//判断圆括号和花括号是否匹配
	if ( 0 != parenthesisNum || 0 != braceNum ){
		return 1;
	}

	return 0;
}

int main(void)
{
	char	line[ MAXSIZE ];
	char	*mulLine[ LINENUM ];
	int		index = 0;
	int		i = 0;
	int		j = 0;
	int		isOK = 0;

	for ( i = 0; i < MAXSIZE; i++ ){
		line[ i ] = '\0';
	}
	for ( i = 0; i < LINENUM; i++ ){
		mulLine[ i ] = "";
	}

	//对注释进行处理
	while ( NULL != fgets( line, MAXSIZE, stdin ) ){
		dealLine( line, mulLine, index );
		index++;
	}

	//对方括号进行处理
	for ( i = 0; i < LINENUM; i++ ){
		isOK = dealSquareBrackets( mulLine[ i ] );
		if ( isOK ){
			perror("1--brackets error:");
			break;
		}
	}

	//对圆括号和花括号进行处理
	isOK = dealBrackets( mulLine );
	if ( isOK ){
		perror("2--brackets error:");
	}

	printf("\nthe text is:\n");
	for ( i = 0; i < LINENUM; i++ ){
		if ( '\0' != mulLine[ i ][ 0 ] ){		//不要进行"" != mulLine[ i ]的判断
			printf("%s\n", mulLine[ i ] );
		}
	}

	return 0;
}
程序输出:


转载于:https://my.oschina.net/voler/blog/160204

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值