/*
编写一个函数, 从标准输入一行一行地读取文本, 并完成如下任务:
如果文件中有两行或者多行相邻的文本内容相同, 那么就打印出其中一行, 其余的行不打印.你可以假设文件中的文本行在长度上不超过128个字符(127个字符加上用于终结文本行的环行符).
考虑如下输入文件:
This is the frist line.
Another line.
And another.
And another.
And another.
Still more.
Almost done now --
Almost done now --
Another line.
Still more.
Finished!
假定所有的行在尾部没有任何空白(它们在视觉上不可见, 但却可能使邻近两行在内容上不同), 根据这个输入文件, 程序应该产生下列输出:
And another.
Almost done now --
所有内容相同的相邻文本行只有一行被打印. 注意"Another line."和"Still more."并未被打印, 因为文件中它们虽然各占两行, 但相同文本行的位置并不相邻.
提示:
是由fgets函数读取输入行, 使用strcpy函数来复制它们. 有一个叫做strcmp的函数接受两个字符串参数并对他们进行比较. 如果两者相等, 函数返回0, 如果不等, 函数返回非0值.
*/
typedef struct tagLINE
{
char *str;
struct tagLINE *next;
}LINE;
void SaveStr( LINE *output, char *str );
void ShowStr( LINE *output );
void end(LINE *output);
#define MAX 128
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( void )
{
LINE * const output = (LINE*) malloc( sizeof( LINE ) ); //output是链表的头指针
if( output == NULL )
{
printf( "内存申请失败!\n" );
exit( 0 );
}
output->str = "输出:\n";
output->next = NULL;
char *buf = (char*) malloc( sizeof( char ) * MAX ); //存放当前输入文本行
if( buf == NULL )
{
printf( "内存申请失败!\n" );
exit( 0 );
}
char ( *str )[MAX] = ( char(*)[MAX] ) malloc( sizeof( char ) * MAX * 3 ); //str[3][MAX], 存放文本行
if( str == NULL )
{
printf( "内存申请失败!\n" );
exit( 0 );
}
//将str中的3个字符串初始化为空字符串
str[0][0] = '\0'; //存放的字符串非空时, 送入output最终打印出来
str[1][0] = '\0'; //存放相邻两行内容相同的文本行
str[2][0] = '\0'; //存放上一次输入文本行
while( fgets( buf, MAX, stdin ) != NULL )
{
if( strcmp( str[2], buf ) != 0 ) //如果当前文本行与上一行不同
{
strcpy( str[0], str[1] );
str[1][0] = '\0';
strcpy( str[2], buf );
}
else //如果当前文本行与上一行相同
{
if( strcmp( str[1], str[2] ) != 0 ) //如果上一行(当前文本行)与上一个相同文本行不同
{
strcpy( str[0], str[1] );
strcpy( str[1], str[2] );
}
}
if( str[0][0] != '\0' )
{
SaveStr( output, str[0] ); //把字符串str[0]存入链表
str[0][0] = '\0';
}
if( buf[0] == '\n' ) //用户输入空文本行(只有一个回车), 表示输入结束
{
break;
}
}
ShowStr( output ); //打印链表
end( output ); //释放之前申请的动态内存
free( buf );
free( str );
return 0;
}
void SaveStr( LINE *output, char *str )
{
LINE *p = (LINE*) malloc( sizeof( LINE ) ); //为新节点分配动态内存
if( p == NULL )
{
printf( "内存申请失败!\n" );
exit( 0 );
}
p->str = (char*) malloc( strlen( str ) + 1 ); //根据要存储字符串长度申请一块最小的动态内存
if( p->str == NULL )
{
printf( "内存申请失败!\n" );
exit( 0 );
}
strcpy( p->str, str ); //复制字符串到新节点
p->next = NULL; //存储的字符串都是从尾部插入链表, 所以申请动态内存成功后直接把新节点的next置空
while(output->next !=NULL) //遍历到链表尾节点
{
output = output->next;
}
output->next = p; //在链表尾部插入新节点
return;
}
void ShowStr( LINE *output )
{
for( ;output != NULL; output = output->next )
{
printf( "%s", output->str ); //fgets函数会在字符串末尾加上'\0', 假设每行输入不超过MAX, 那么最后一个有效字符一定是用户输入的'\n', 所以printf不需要再加换行符.
}
return;
}
void end( LINE *output )
{
LINE *delete = output; //delete用于释放节点占用的动态内存
for( output = output->next; output != NULL; output = output->next )
{
free( output->str ); //释放节点里面str指向的动态内存
free( delete ); //释放节点占用的动态内存
delete = output; //delete永远滞后output一个节点
}
free( delete ); //因为delete永远滞后output一个节点, 所以上面循环结束时, 还有最后一个节点占用的动态内存没有释放
return;
}
程序输出结果: