基本原理:
为此,可设置个输入缓冲区为一个栈结构,每当从终端接受一个字符后先作如下判别,如果它既不是退格符也不是退行符,则将该字符压入栈顶;如果是一个退格符,则从栈顶删除一个字符;如果它是一个退行符,则将字符栈清为空。
/*
这是一个利用栈来实现编辑的小程序,#时则前一个字符无效,@时表示输入的整行字符无效;
*/
#include <stdio.h>
#include <stdlib.h>
#define STACT_INIT_SIZE 10 //存储空间初始分配量
#define STACKINCREMNET 2 //存储空间分配增量
#define MAX 80
typedef int SElemType;
typedef enum {true = 1, false = 0}bool;
FILE *fp; //将文件指针fp声明为全局变量
//栈的结构类型
typedef struct SqStack
{
SElemType *base; //在构造之前和销毁之后,base的值为NULL
SElemType *top; //栈顶指针
int stacksize; //当前已分配的存储空间,以元素为单位
}SqStack;
static bool InitStack(SqStack *s);
static bool StackEmpty(SqStack *s);
static bool PushStack(SqStack *s, SElemType e);
static bool PopStack(SqStack *s, SElemType *value);
static bool ClearStack (SqStack *s);
static bool StackTraverse(SqStack *s, int *c);
static bool DestroyStack(SqStack *s);
static void LineEdit();
static bool copy (SElemType c);
int main(void)
{
fp = fopen("EDT.txt", "w"); //打开一个文件,如果没有,则创建
if (fp != NULL)
{
LineEdit();
fclose(fp);
}
else
{
puts("建立文件失败!");
}
return 0;
}
static bool InitStack(SqStack *s)
{
//分配存储空间,来存放SElemType类型的元素
s->base = (SElemType *) malloc (STACT_INIT_SIZE * sizeof(SElemType));
if (!s->base)
{
return false;
exit(-1);
}
//空栈时,栈顶指针和栈底指针指向同一个位置
s->top = s->base;
s->stacksize = STACT_INIT_SIZE;
return true;
}
static bool PushStack(SqStack *s, SElemType e)
{
//如果栈已满,则需要重新分配内存
if ((s->top-s->base) >= s->stacksize)
{
s->base = (SElemType *) realloc (s->base, (s->stacksize + STACKINCREMNET)*sizeof(SElemType));
if (!s->base)
{
return false;
exit(-1);
}
s->top = s->base + s->stacksize;
s->stacksize += STACKINCREMNET;
}
*s->top++ = e;
return true;
}
static bool PopStack(SqStack *s, SElemType *value)
{
if (s->top == s->base)
{
puts("stack is empty");
return false;
}
*value = *(--s->top);
printf("现在出栈的数值是:%c\n", *value);
return true;
}
static bool StackEmpty(SqStack *s)
{
if (s->top == s->base)
{
return true;
}
else
{
return false;
}
}
static bool ClearStack (SqStack *s)
{
s->top = s->base;
return true;
}
//栈必须从顶部开始出栈,
static bool StackTraverse(SqStack *s, int *c)
{
SElemType *p = NULL;
p = s->top; //是为了保护这个栈,不让这个栈变成空栈
while(s->top > s->base)
{
*c = *(--s->top);
printf("%d", *c);
}
s->top = p; //栈遍历结束后,将top重新指向栈顶的位置
putchar('\n');
return true;
}
//销毁这个栈
static bool DestroyStack (SqStack *s)
{
free(s->base);
s->base = NULL;
s->top = NULL;
s->stacksize = 0;
return true;
}
static bool copy (SElemType c)
{
//将字符送至fp所指的文件中
fputc(c, fp);
return true;
}
static void LineEdit()
{
/*为什么这里需要两个栈,因为存入第一个栈后,它的字母顺序为逆序的,为了正序输入,需要另外一个
栈来实行第二次的逆序
*/
SqStack s;
SqStack s_temp;
static SElemType pop_value = 0;
static SElemType temp_value = 0;
char ch; //用来存放终端输入的字符
int c;
InitStack(&s);
InitStack(&s_temp);
puts("请输入一个文本文件,~z结束输入:");
//从终端读入字符
ch = getchar();
while (ch != EOF) //如果是EOF则推出整个循环
{
while (ch!=EOF && ch!='\n')
{
switch(ch)
{
case '#':
if (!StackEmpty(&s)) //仅当栈非空时退栈
{
PopStack(&s, &c);
break; //跳出switch循环
}
else
{
puts("# error");
break;
}
case '@':ClearStack(&s); //重置s为空栈
break;
default:PushStack(&s, ch); //有效字符进栈
}
ch = getchar(); //从终端接收下一个字符
}
while (s.top > s.base)
{
//将从第一个栈底到栈顶的栈内字符传送至第二个栈
PopStack(&s, &pop_value);
PushStack(&s_temp, pop_value);
}
//将第二个栈的内容输入到文件中去
while(s_temp.top > s_temp.base)
{
PopStack(&s_temp, &temp_value);
fputc(temp_value, fp);
}
ClearStack(&s);
ClearStack(&s_temp);
fputc('\n', fp);
if (ch != EOF)
{
ch = getchar();
}
}
DestroyStack(&s);
DestroyStack(&s_temp);
}