技术标签: 数据结构c
本程序要求完成一个简易文本编辑器,能够完成文本的录入、编辑、删除、查找,并能够完成文件的存取。
在文本编辑软件中把用户输入的所有文本内容作为一个字符串。虽然各种文本编辑软件的功能有强弱差别,但是基本操作都包括串的输入、修改、删除(包括整行删除和一行中的子串删除)、查找、输出等。通过分析,系统应该包括以下功能:
文本编辑器主要是针对文本进行编辑,文本的操作就是对字符的操作。文本编辑器可以从行、列两个方向进行编辑。
每一行可以看成一个线性表,线性表是一种线性结构,线性结构的特点是数据元素之间为线性关系,数据元素“一个接一个的排列”。在一个线性表中数据元素的类型是相同的,由于每一行可以存储的最大字数是相同的,行方向所有线性表的最大长度可以设置成相同的。行与行之间的关系也可以看成一个线性表。
2.采用的存储结构
线性表的存储分为两种:顺序存储和链式存储。
顺序存储是指在内存中用地址连续的一块存储空间顺序存放线性表的各元素,用这种存储形式存储的线性表称为顺序表。在程序设计语言中,一维数组在内存中占用的存储空间就是一组连续的存储区域,因此,用一维数组来表示顺序表的数据存储区域是再合适不过的。
链式存储是通过-组任意的存储单元来存储线性表中的数据元素的,为建立数据元系之间的线性关系,对每个数据元素除了存放数据元素自身的信息之外,还需要和一起存放其后继或前驱所在的存储单元的地址,这两部分信息组成一个“结点”,每个元素都如此。存放数据元素信息的称为数据域,存放其前驱或后继地址的称为指针域。只有一个存储单元地址的为单链表,有两个存储单元地址的为双链表。
考虑到实际的功能需求,每行的线性表可以用顺序存储方式,每个字符是一个节点。用数组的长度表示本行可以输入的最大字符。行与行之间的线性表采用双链表存储,每个节点包括四个区域,一个指针域prior指向上一行,一个指针域next指向下一行,一个数据域num是行号,一个数据域是本行的字符数组。程序以行和列标识文本位置,行采用双向链表存储行信息,用数组下标标识列信息,从而能够准确定位字符位置,然后进行查找、替换、插入、块移动、删除等多种操作。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_LEN 100
#define NOT_FOUND -1
//定义行结构体:
struct line
{
char text[MAX_LEN]; //本行文本
int num; //行号
struct line *next; //指向下一个行的指针
struct line *prior; //指向前一个行的指针
};
int lnum;
struct line *start; //指向线性表中第一行的指针
struct line *last; //指向线性表中最后一行的指针
struct line *find(int); //查找指定行是否存在
void patchup(int, int); //对当前行以后的每行的行号加1或
void delete_text(int); //删除一行文字
void list(); //显示文件的全部内容
void save(); //保存文件
void load(); //打开文件,初始化线性表
void insert(char str[], int linenum, int position); //插入文字到一行的中间
void printline(int linenum); //打印一行文字
void deletestr(int linenum, int position, int lenth); //删除一个字符串
int findstr(char * to_find); //查找字符串
int menu_select(); //显示主菜单
int menu_select_insert();//显示插入功能子菜单
int menu_select_delete();//显示删除功能子菜单
int menu_select_print(); //显示打印功能子菜单
int menu_select_move(); //显示移动功能子菜单
void enter(int linenum); //插入一行文字
void enter_empty(int linenum); //插入一个空白行
//下列函数是系统主函数,提供系统主界面,通过选择项转入执行插入、删除、查存盘、读人文件等功能的界面。
int main(void)
{
char str[MAX_LEN];
int choice;
int linenum = 1;
int number = 0;
start = NULL;
last = NULL;
load(); //打开文件,初始化线性表
do{
choice = menu_select();
switch (choice)
{
case 1: //执行插入功能
choice = menu_select_insert();//显示插入子菜单
switch (choice)
{
case 1: //插入一行
printf("\t行号:");
scanf("%d", &linenum);
enter(linenum);
break;
case 2: //插入到指定行的指定列
printf("输入插入位置一行号:");
scanf("%d", &linenum);
printf("输入插入位置-列号:");
scanf("%d", &number);
printf("要插入的字符串:");
scanf("%s", str);
insert(str, linenum, number);
break;
case 3: //退出插入
break;
}
break;
case 2: //执行删除功能
choice = menu_select_delete(); // 删除子菜单
switch (choice)
{
case 1: //删除指定行
printf("\t行号:");
scanf("%d", &linenum);
break;
case 2: //删除指定的字符串
printf("要删除的字符串:");
scanf("%s", str);
number = findstr(str);
if (number == NOT_FOUND)
printf("没有找到");
else
deletestr(lnum, number, strlen(str));
break;
case 3: //退出删除
break;
}
break;
case 3: //执行显示功能
choice = menu_select_print(); //显示子菜单
switch (choice) //显示指定行
{
case 1:
printf("\t行号:");
scanf("%d", &linenum);
printline(linenum);
break;
case 2: //显示全部
list();
break;
case 3: //退出显示
break;
}
break;
case 4: //执行查找功能
printf("输入想要查找的字符串:");
scanf("%s", str);
number = findstr(str);
if (number == NOT_FOUND)
printf("没有找到");
else
printf("要查找的字符串所在行号:%d,列号:%d\n", lnum, number + 1);
break;
case 5: //执行替换功能
printf("输入被替换的字符串:");
scanf("%s", str);
number = findstr(str);
if (number == NOT_FOUND)
printf("没有找到");
else
{
deletestr(lnum, number, strlen(str));
printf("要替换的字符串:");
scanf("%s", str);
insert(str, lnum, number + 1);
}
break;
case 6: //执行移动功能
choice = menu_select_move(); //移动子菜单
switch (choice)
{
case 1: // 向下移动一行
printf("输人要移动的字符串所在行号:");
scanf("%d", &linenum);
enter_empty(linenum);
break;
case 2: //向上移动一行
printf("输入要移动的字符串所在行号:");
scanf("%d", &linenum);
delete_text(linenum - 1);
break;
case 3: //向右移动一列
printf("输人要移动的字符串所在行号:");
scanf("%d", &linenum);
printf("输入要移动的字符串所在列号:");
scanf("%d", &number);
str[0] = ' ';
str[1] = '\0';
insert(str, linenum, number);
break;
case 4: //向左移动
printf("输入要移动的字符串所在行号:");
scanf("%d", &linenum);
printf("输入要移动的字符串所在列号:");
scanf("%d", &number);
if (number <= 0)
printf("该列不存在");
else
deletestr(linenum, number - 2, 1);
break;
case 5: //退出移动
break;
}
break;
case 7: //执行存盘功能
save();
break;
case 8: //执行读入文件功能
load();
break;
case 9: //执行退出功能
exit(0);
break;
}
} while (1);
return 0;
}
//下列函数是主菜单功能的提示界面,其功能是说明主菜单中选项
int menu_select()
{
int c;
printf("\n\t\t1.插入\n");
printf("\t\t2.删除\n");
printf("\t\t3.显示\n");
printf("\t\t4.查找\n");
printf("\t\t5.替换\n");
printf("\t\t6.移动\n");
printf("\t\t7.文件存盘\n");
printf("\t\t8.装入文件\n");
printf("\t\t9.退出\n");
do
{
printf("\n\n\t\t请按数字选择:");
scanf("%d", &c);
} while (!(c >= 1 && c <= 9));
return(c);
}
//下列函数是插入子菜单功能的提示界面,其功能是说明在插入菜单下选项的含义。
int menu_select_insert()
{
int c;
printf("\n\t\t1.插入一行文字\n");
printf("\t\t2.插入一段文字\n");
printf("\t\t3.返回上级菜单\n");
do{
printf("\n\n\t\t请按数字选择:");
scanf("%d", &c);
} while (!(c >= 1 && c <= 3));
return(c);
}
//下列函数是删除子菜单功能的提示界面,其功能是说明在删除子菜单下选项的含义。
int menu_select_delete()
{
int c;
printf("\n\t\t1.删除一行文字\n");
printf("\t\t2.删除一段文字\n");
printf("\t\t3.返回上级菜单\n");
do{
printf("\n\n\t\t请按数字选择:");
scanf("%d", &c);
} while (!(c >= 1 && c <= 3));
return(c);
}
//下列函数是显示子菜单功能的提示界面,其功能是说明在显示子菜单下选项的含义
int menu_select_print()
{
int c;
printf("\n\t\t1.显示一行\n");
printf("\t\t2.全部显示\n");
printf("\t\t3.返回上级菜单\n");
do{
printf("\n\n\t\t请按数字选择:");
scanf("%d", &c);
}while(!(c >= 1 && c <= 3));
return(c);
}
//下列函数是移动子菜单功能的提示界面,其功能是说明在移动子菜单下选项的含义
int menu_select_move()
{
int c;
printf("\n\t\t1.向下移动一行\n");
printf("\t\t2.向上移动一行\n");
printf("\t\t3.向右移动一列\n");
printf("\t\t4.向左移动一列\n");
printf("\t\t5.返回上级菜单\n");
do{
printf("\n\n\t\t请按数字选择:");
scanf("%d", &c);
} while (!(c >= 1 && c <= 5));
return(c);
}
//下列函数的功能是在指定的行号 linenum处插入一行文字。
void enter(int linenum)
{
struct line * info, * q, * p;
p = start;
q = NULL;
while (p && p->num != linenum) //找到插入行
{
q = p;
p = p->next;
}
if (p == NULL && (q->num + 1) != linenum) //指定行不存在,不能插入
{
printf("输入的行号不存在");
}
else // 指定行存在,进行插入
{
info = (struct line *)malloc(sizeof(struct line));
printf("输入要输入的字符串");
scanf("%s", info->text);
info->num = linenum;
if (linenum == 1) //插入在第一行
{
info->next = p;
p->prior = info;
info->prior = NULL;
start = info;
}
else if (q->num != linenum) //插入在最后一行
{
q->next = info;
info->next = p;
info->prior = q;
}
else //插入在其他行
{
q->next = info;
info->next = p;
p->prior = info;
info->prior = q;
}
while (p) //如果不是插入在最后一行,插入行后面的行号都加1
{
p->num = p->num + 1;
p = p->next;
}
}
}
//下列函数是为其他功能提供的一个辅助函数,它的功能是当文本内容插在文件中间时
//其下面的内容的行号必须增加1,而删除时,被删除的文本后面的行号必减1.
void patchup(int n, int incr)
{
struct line *i;
i = find(n);
i = i->next;
while (i)
{
i->num = i->num + incr;
i = i->next;
}
}
//下列函数的功能是在指定行处插入一个空白行。
void enter_empty(int linenum)
{
struct line *info, *p;
info = (struct line *)malloc(sizeof(struct line));
if (!info)
{
printf("\t!内存不够!\n");
exit(0);
}
info->text[0] = ' ';
info->text[1] = '\0';
info->num = linenum;
if (find(linenum)) //如果要插人的行号存在,则进行插入
{
p = start;
if (linenum == 1) //插入在首行
{
info->next = p;
start = info;
info->prior = NULL;
p->prior = info;
}
else //插入在其他行
{
while (p->next->num != linenum)
p = p->next;
info->next = p->next;
p->next->prior = info;
p->next = info;
info->prior = p;
}
patchup(linenum, 1);
}
else
printf("该行不存在");
}
//下列函数的功能是插入文字到一行的中间。要是插入位置和现有位置中间有间隔,会补全空格
void insert(char str[], int linenum, int position)
{
struct line * info;
int len, i;
int lenth;
char rest_str[MAX_LEN], nostr[2] = { " " };
info = start;
while (info && info->num != linenum) //查询要插入的行
{
info = info->next;
}
if (info == NULL)
printf("不存在该行!\n");
else if (position < 0)
printf("不存在该列!\n");
else //如果行和列都存在,则进行插入
{
lenth = strlen(info->text);
if (lenth < position) //插入列大于本行文件列数
{
len = position - lenth - 1;
for (i = 0; i < len; i++)
strcat(info->text, nostr); //将空余的部分插入空格符
strcat(info->text, str); //插入字符到列的未尾
}
else //插入列在本行文字的中间
{
strcpy(rest_str, &info->text[position - 1]);
strcpy(&info->text[position - 1], str);
strcat(info->text, rest_str);
}
}
}
//下列函数的功能是删除指定行、指定位置、长度为 lenth的一段文字。
void deletestr(int linenum, int position, int lenth)
{
struct line * info;
char rest_str[MAX_LEN];
info = find(linenum);
if (info == NULL)
printf("该行没有字符!n");
else
{
if (strlen(info->text) <= (position + lenth)) //本行的字符长度<=待删除的列号+删除长度,直接在当前位置插入'\0'
info->text[position] = '\0';
else
{
strcpy(rest_str, &info->text[position + lenth]);
strcpy(&info->text[position], rest_str);
}
}
}
//下列函数的功能是删除指定行号 lineup的文字。
void delete_text(int linenum)
{
struct line * info, *p;
info = start;
while ((info->num < linenum) && info)
info = info->next;
if (info->next == NULL)
printf("该行不存在");
else
{
p = info->next;
if (start == info) //如果删除的是第一行
{
start = info->next;
if (start) //如果删除后,不为空
start->prior = NULL;
else //删除后为空
last = NULL;
}
else
{
info->prior->next = info->next; //指定行的上一行指向指定行的下一行
if (info != last) //如果不是最后一行
info->next->prior = info->prior; //修改其下一行的指向头的指针
else //如果是最后一行,修改尾指针
last = info->prior;
}
free(info);
while (p)
{
p->num = p->num - 1;
p = p->next;
}
}
}
//下列函数的功能是查找一段文字。
int findstr(char * to_find)
{
struct line * info;
int i = 0, find_len, found = 0, position;
char substring[MAX_LEN];
info = start;
lnum = 0; //匹配到的行号
find_len = strlen(to_find);
while (info && !found) //查询
{
i = 0; //行间循环
while (!found && (i <= strlen(info->text) - find_len)) //行内查找循环
{
strcpy(substring, &info->text[i], find_len);
substring[find_len] = '\0';
if (strcmp(substring, to_find) == 0)
{
found = 1;
lnum = info->num;
}
else
++i;
}
info = info->next;
}
if (found) //查找成功
position = i;
else //查找不成功
position = NOT_FOUND;
return(position);
}
//下列函数的功能是查找指定行,如果查找成功返回结点所在的行指针。
struct line * find(int linenum)
{
struct line * info;
info = start;
while (info)
{
if (linenum != info->num)
info = info->next;
else
break;
}
return (info);
}
//下列函数的功能是显示指定行
void printline(int linenum)
{
struct line *info;
info = find(linenum);
if (info)
printf("%d:%s\n", info->num, info->text);
else
printf("该行不存在");
}
//下列函数的功能是显示线性表中的所有文本
void list()
{
struct line * info;
info = start;
while (info)
{
printf("%d:%s\n", info->num, info->text);
info = info->next;
}
printf("\n\n");
}
//下列函数的功能是把线性表中的所有文字保存到文件中
void save()
{
struct line * info;
char * p;
FILE * fp;
if ((fp = fopen("D:\\text.txt", "w")) == NULL){
printf("\t文件打不开!n");
exit(0);
}
printf("\t正在存入文件!\n");
info = start;
while (info)
{
p = info->text;
while (*p)
putc(*p++, fp);
putc('\n', fp);
info = info->next;
}
fclose(fp);
}
//下列函数的功能是把文本文件中的内容读入到线性表中。
void load()
{
struct line *info, *temp; //info指向当前行,temp指向info的前驱行
char c;
FILE *fp; //文件指针
int inct, i; //行计数器
temp = NULL;
if ((fp = fopen("D:\\text.txt", "r")) == NULL)
{
printf("\t文件打不开!\n");
exit(0);
}
printf("\n\t正装入文件!\n");
start = (struct line*)malloc(sizeof(struct line)); //动态生成一行的结点空间
info = start;
inct = 1;
while ((c = fgetc(fp)) != EOF)
{
i = 0;
info->text[i] = c;
i++;
while ((c = fgetc(fp)) != '\n') //从文件中读取一行字符到线性表中,文件中每一行以\n为结束标
{
info->text[i] = c;
i++;
}
info->text[i] = '\0'; //线性表中每行末尾的结束标志
info->num = inct++; //行号和计数器都加1
info->next = (struct line*)malloc(sizeof(struct line));
if (!info->next)
{
printf("\n\t内存已经用完!");
exit(0);
}
info->prior = temp;
temp = info;
info = info->next;
}
temp->next = NULL;
last = temp;
free(info);
start->prior = NULL;
fclose(fp);
}
文章浏览阅读331次。第一部分:准备工作1 安装虚拟机2 安装centos73 安装JDK以上三步是准备工作,至此已经完成一台已安装JDK的主机第二部分:准备3台虚拟机以下所有工作最好都在root权限下操作1 克隆上面已经有一台虚拟机了,现在对master进行克隆,克隆出另外2台子机;1.1 进行克隆21.2 下一步1.3 下一步1.4 下一步1.5 根据子机需要,命名和安装路径1.6 ..._创建一个hadoop项目
文章浏览阅读1.7k次。心脏滴血漏洞HeartBleed CVE-2014-0160 是由heartbeat功能引入的,本文从深入码层面的分析该漏洞产生的原因_heartbleed代码分析
文章浏览阅读1.4k次。前言ofd是国家文档标准,其对标的文档格式是pdf。ofd文档是容器格式文件,ofd其实就是压缩包。将ofd文件后缀改为.zip,解压后可看到文件包含的内容。ofd文件分析工具下载:点我下载。ofd文件解压后,可以看到如下内容: 对于xml文件,可以用文本工具查看。但是对于印章文件(Seal.esl)、签名文件(SignedValue.dat)就无法查看其内容了。本人开发一款ofd内容查看器,..._signedvalue.dat
文章浏览阅读1.8w次,点赞29次,收藏313次。整体系统设计本设计主要是对ADC和DAC的使用,主要实现功能流程为:首先通过串口向FPGA发送控制信号,控制DAC芯片tlv5618进行DA装换,转换的数据存在ROM中,转换开始时读取ROM中数据进行读取转换。其次用按键控制adc128s052进行模数转换100次,模数转换数据存储到FIFO中,再从FIFO中读取数据通过串口输出显示在pc上。其整体系统框图如下:图1:FPGA数据采集系统框图从图中可以看出,该系统主要包括9个模块:串口接收模块、按键消抖模块、按键控制模块、ROM模块、D.._基于fpga的信息采集
文章浏览阅读2.5w次。1.背景错误信息:-- [http-nio-9904-exec-5] o.s.c.n.z.filters.post.SendErrorFilter : Error during filteringcom.netflix.zuul.exception.ZuulException: Forwarding error at org.springframework.cloud..._com.netflix.zuul.exception.zuulexception
文章浏览阅读358次。1.介绍图的相关概念 图是由顶点的有穷非空集和一个描述顶点之间关系-边(或者弧)的集合组成。通常,图中的数据元素被称为顶点,顶点间的关系用边表示,图通常用字母G表示,图的顶点通常用字母V表示,所以图可以定义为: G=(V,E)其中,V(G)是图中顶点的有穷非空集合,E(G)是V(G)中顶点的边的有穷集合1.1 无向图:图中任意两个顶点构成的边是没有方向的1.2 有向图:图中..._给定一个邻接矩阵未必能够造出一个图
文章浏览阅读321次。(十二)、WDS服务器安装通过前面的测试我们会发现,每次安装的时候需要加域光盘映像,这是一个比较麻烦的事情,试想一个上万个的公司,你天天带着一个光盘与光驱去给别人装系统,这将是一个多么痛苦的事情啊,有什么方法可以解决这个问题了?答案是肯定的,下面我们就来简单说一下。WDS服务器,它是Windows自带的一个免费的基于系统本身角色的一个功能,它主要提供一种简单、安全的通过网络快速、远程将Window..._doc server2012上通过wds+mdt无人值守部署win11系统.doc
文章浏览阅读219次。python–xlrd/xlwt/xlutilsxlrd只能读取,不能改,支持 xlsx和xls 格式xlwt只能改,不能读xlwt只能保存为.xls格式xlutils能将xlrd.Book转为xlwt.Workbook,从而得以在现有xls的基础上修改数据,并创建一个新的xls,实现修改xlrd打开文件import xlrdexcel=xlrd.open_workbook('E:/test.xlsx') 返回值为xlrd.book.Book对象,不能修改获取sheett_xlutils模块可以读xlsx吗
文章浏览阅读8.2w次,点赞267次,收藏656次。运行Selenium出现'WebDriver' object has no attribute 'find_element_by_id'或AttributeError: 'WebDriver' object has no attribute 'find_element_by_xpath'等定位元素代码错误,是因为selenium更新到了新的版本,以前的一些语法经过改动。..............._unresolved attribute reference 'find_element_by_id' for class 'webdriver
文章浏览阅读198次。一:模态窗口//父页面JSwindow.showModalDialog(ifrmehref, window, 'dialogWidth:550px;dialogHeight:150px;help:no;resizable:no;status:no');//子页面获取父页面DOM对象//window.showModalDialog的DOM对象var v=parentWin..._jquery获取父window下的dom对象
文章浏览阅读1.7w次,点赞15次,收藏129次。算法(algorithm)是解决一系列问题的清晰指令,也就是,能对一定规范的输入,在有限的时间内获得所要求的输出。 简单来说,算法就是解决一个问题的具体方法和步骤。算法是程序的灵 魂。二、算法的特征1.可行性 算法中执行的任何计算步骤都可以分解为基本可执行的操作步,即每个计算步都可以在有限时间里完成(也称之为有效性) 算法的每一步都要有确切的意义,不能有二义性。例如“增加x的值”,并没有说增加多少,计算机就无法执行明确的运算。 _算法
文章浏览阅读1.5k次,点赞18次,收藏26次。网络安全的标准和规范是网络安全领域的重要组成部分。它们为网络安全提供了技术依据,规定了网络安全的技术要求和操作方式,帮助我们构建安全的网络环境。下面,我们将详细介绍一些主要的网络安全标准和规范,以及它们在实际操作中的应用。_网络安全标准规范