文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C语言如何实现简易文本编译器

2023-06-15 00:02

关注

这篇文章将为大家详细讲解有关C语言如何实现简易文本编译器,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

C语言是什么

C语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发,使用C语言可以以简易的方式编译、处理低级存储器。

数据结构课程设计之简易文本编译器(C语言实现)

需求分析

(1)具有图形菜单界面:显示实时年份,日期,星期及时间

(2)

 查找:查找文本中的字符串,显示其出现的行数,列数及总共出现次数

 替换(等长,不等长):对文本中的文本实现等长及不等长替换

 插入(插串,文本块的插入):插入一行或在具体行号列号处插入文本

 块移动(行块,列块移动):向下移动一行,向上移动一行,

                         具体行号列号处向左移动或向右移动

 删除:删除一行,删除莫一行,莫列,定长的内容

(3)可正确存盘、取盘;:可读取,保存文本;

(4)正确显示总行数。(行数不少于5行,每行字符数不少于80个字符)

采用的数据结构

采用的逻辑结构

文本编辑器主要是针对文本进行编辑,文本的操作就是对字符的操作。文本编辑器可以从行、

列两个方向进行编辑。

每一行可以看成一个线性表,线性表是一种线性结构,线性结构的特点是数据元素之间为线性

关系,据元素“一个接一个的排列”。在一个线性表中数据元素的类型是相同的,由于每一行

可以存储的最大字数是相同的,行方向所有线性表的最大长度可以设置成相同的。行与行之间

的关系也可以看成一个线性表。

采用的存储结构

线性表的存储分为两种:顺序存储和链式存储。

顺序存储是指在内存中用地址连续的一块存储空间顺序存放线性表的各元素,用这种存储形式

存储的线性表称为顺序表。在程序设计语言中,一维数组在内存中占用的存储空间就是一组连续

的存储区域,因此,用一维数组来表示顺序表的数据存储区域是再合适不过的。

链式存储是通过-组任意的存储单元来存储线性表中的数据元素的,为建立数据元系之间的线性

关系对每个数据元素除了存放数据元素自身的信息之外,还需要和一起存放其后继或前驱所在的

存储单元的地址,这两部分信息组成一个“结点”,每个元素都如此。存放数据元素信息的称为

数据域,存放其前驱或后继地址的称为指针域。只有一个存储单元地址的为单链表,有两个存储

单元地址的为双链表。

考虑到实际的功能需求,每行的线性表可以用顺序存储方式,每个字符是一个节点。用数组的长

度表示本行可以输入的最大字符。行与行之间的线性表采用双链表存储,每个节点包括四个区域,

一个指针域prior指向上一行,一个指针域next指向下一行,一个数据域num是行号,一个数据

域是本行的字符数组。程序以行和列标识文本位置,行采用双向链表存储行信息,用数组下标标识

列信息,从而能够准确定位字符位置,然后进行查找、替换、插入、块移动、删除等多种操作。

函数功能模块图:

C语言如何实现简易文本编译器

定义的结构体:

struct line{    char  text[MAX_LEN];      //本行的文本     int num;                 //行号    struct line *next;       //指向下一行的指针     struct line *prior;      //指向前一行的指针  };

代码如下(仅供参考)

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <math.h>#define MAX 240#define NOT_FOUND -1//函数声明  void HeadWord(void);      //输出大标题,永远出现在程序的最顶端。  void PrintWord(void);    //输出文本的内容 void printf_time();      //输出时间和日期,星期及年月日 void scanf_load();       //从键盘录入文本 void file_load();        //把文本文件的内容读到线性表中void findstr();          //查找字符串 void delete1(int linenum);//删除一行void delete2(int linenum,int position,int lenth);//删除莫一行,莫列,定长的内容 void insert1();           // 插入一行文字void insert2(char str[], int linenum, int position);//插入文字到文本莫一行莫一列void replace();          //替换void Mainmenu();          //主菜单void menu1();                //文件录入方式菜单void menu2();               //文本内容处理菜单void menu_move();          //移动菜单 //定义结构体struct line{ char text[MAX];      //该行的内容  int num;                 //用来记录行号 struct line *prior;      //用来指向前一行 struct line *next;       //用来指向下一行 };struct line *start;          //指向线性表的第一行struct line *last;           //指向线性表的最后一行//主函数 int main(){   Mainmenu(); return 0; }//输出标题,永远出现在程序的最顶端。 void HeadWord(){ printf("\t\t ____________________________________________________\n\n");printf("\t\t****    Welcom to use our TXT edition system!    ****\n");printf("\t\t ____________________________________________________\n");}//  输出链表的内容 void PrintWord(){  struct line *p = start; while(p != last) {  printf("\n\t\t第%d行|%s",p->num,p->text);  p = p->next; } printf("\n\t\t第%d行|%s",last->num,last->text);  printf("\n");}//输出时间和日期 void printf_time(){  time_t timep; struct tm *p; time (&timep); p=gmtime(&timep); //年月日  printf("\t\t|Data:%d-%d-%d  |",1900+p->tm_year,1+p->tm_mon,p->tm_mday);  //显示星期几  printf("Today is "); switch (p->tm_wday)    {    case 7:           printf("Sunday   |");        break;     case 1:           printf("Monday   |");        break;    case 2:           printf("Tuesday  |");        break;    case 3:          printf("Wednesday|");        break;    case 4:         printf("Thursday |");        break;    case 5:          printf(" Friday  |");        break;    case 6:          printf("Saturday |");        break;    default:        break; }  //让时间固定显示为 08:04:11类型,即当时,分,秒小于十时前加零  if(p->tm_hour+8<10&&p->tm_min>10&&p->tm_sec>10) printf("Time:0%d:%d:%d |",p->tm_hour+8,p->tm_min,p->tm_sec); else if(p->tm_hour+8<10&&p->tm_min<10&&p->tm_sec>10) printf("Time:0%d:0%d:%d |",p->tm_hour+8,p->tm_min,p->tm_sec);  else if(p->tm_hour+8<10&&p->tm_min<10&&p->tm_sec<10) printf("Time:0%d:0%d:0%d |",p->tm_hour+8,p->tm_min,p->tm_sec);  else if(p->tm_hour+8>=10&&p->tm_min<10&&p->tm_sec<10) printf("Time:%d:0%d:0%d |",p->tm_hour+8,p->tm_min,p->tm_sec); else if(p->tm_hour+8>=10&&p->tm_min>=10&&p->tm_sec<10)  printf("Time:%d:%d:0%d |",p->tm_hour+8,p->tm_min,p->tm_sec); else if(p->tm_hour+8>=10&&p->tm_min>=10&&p->tm_sec>=10) printf("Time:%d:%d:%d |",p->tm_hour+8,p->tm_min,p->tm_sec); else if(p->tm_hour+8>=10&&p->tm_min<10&&p->tm_sec>=10) printf("Time:%d:0%d:%d |",p->tm_hour+8,p->tm_min,p->tm_sec); else if(p->tm_hour+8<10&&p->tm_min>=10&&p->tm_sec<10) printf("Time:0%d:%d:0%d |",p->tm_hour+8,p->tm_min,p->tm_sec); } //把文本文件的内容读到线性表中void file_load(){ struct line *info,*temp;                 //行指针,info指向当前行,temp指向info的前驱行  char ch; temp = NULL; int linenum,i;          //行计数器,行字符数组下标  FILE *fp;                             //文件指针  char name[20]; printf("请输入要打开文件名字(例如c:\\a.txt)"); scanf("%s",name);   while ((fp=fopen(name,"r"))==NULL) {   printf("\n打开文件失败,请重新输入要打开的文件名:");   scanf("%s",name);    } start = (struct line*)malloc(sizeof(struct line));     //生成一行的结点空间  info = start; linenum = 1;  while((ch = fgetc(fp)) != EOF) {        i = 0;   info->text[i] = ch;   i++;   while((ch = fgetc(fp)) != '\n')      //从文件中读到一行字符到线性表中    {     info->text[i] = ch;    i++;   } info->num = linenum++; info->next = (struct line*)malloc(sizeof(struct line)); if (!info->next) {  printf("\n\t\t内存不足");   getchar();  exit(0); } temp = info; info = info->next; info->prior = temp;  }   last = info->prior;  printf("\t\t文件读入完毕\n");   fclose(fp);  }//从键盘录入文本 void scanf_load(){  struct line *info,*temp;                 //行指针,info指向当前行,temp指向info的前驱行  char ch; temp = NULL; int linenum,i;          //行计数器,行字符数组下标  FILE *fp;                                 //文件指针  temp = NULL; start = (struct line*)malloc(sizeof(struct line));     //生成一行的结点空间  info = start; linenum = 1; printf("\t\t请从键盘录入文本(输入时回车换行,输入结束后在新的一行输入#结束录入)\n\t\t");  while((ch = getchar()) !='#') {   i = 0;   info->text[i] = ch;   i++;   while((ch = getchar()) != '\n')      //从文件中读到一行字符到线性表中    {        info->text[i] = ch;    i++;      } printf("\t\t");   info->text[i] = '\0'; info->num = linenum++; info->next = (struct line*)malloc(sizeof(struct line)); if (!info->next) {  printf("\n\t\t内存不足");   getchar();  exit(0); } info->prior = temp; temp = info; info = info->next;  }   temp->next = NULL;  last = temp;  free(info);  start->prior = NULL;  }//文件保存void save(){    system("cls"); FILE *fp;    line *info=start; int i=0;    char name[20]; printf("\n请输入保存地址(例如: c:\\a.txt):"); scanf("%s",name);  while ((fp=fopen(name,"w+"))==NULL)  {   printf("文件不存在,请重新输入文件名:");   scanf("%s",name);  }  while(info) {           while(info->text[i]!='\n')    {fprintf(fp,"%c",info->text[i]);   i++;  }  info = info->next;  i = 0; }             fclose(fp);  printf("\n文件保存成功\n"); }  //查找字符串 void findstr(){ PrintWord(); char str[MAX]; getchar(); printf("\t\t 输入想要查找的字符串:"); gets(str); printf("\t\t|>>________________________________________________<<|\n");   struct line *info; int i = 0, find_len, found = 0, position; char substring[MAX]; info = start; int find_num = 0;             //匹配到的次数  find_len = strlen(str); while (info)   //查询 {     i = 0;  //行间循环  while (i <= (strlen(info->text) - find_len))  //行内查找循环  { int k=0;      for(int j=i;j<i+find_len;j++)   // 行内的字符串从第一个开始按定长find_len赋给substring    {     substring[k] = info->text[j];     k++;   }   if (strcmp(substring,str) == 0)   {     find_num++;       printf("\t\t|第%d次出现在:%d行%d列\n",find_num,info->num,(i+1+1)/2);    found = 1;   }    i++;  }  info = info->next; } if (found)  //查找成功  printf("\t\t|\t\t该内容出现的总次数为%d\n",find_num); else   //查找不成功  printf("\t\t该内容不存在\n"); printf("\t\t|>>________________________________________________<<|\n"); }//删除一行void delete1(int line_num){  struct line * info, *p; info = start; while ((info->num < line_num) && info)  //寻找要删除的行   info = info->next; if (info == 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;  } }}//删除莫一行,莫列,定长的内容 void delete2(int line_num,int position,int lenth){   struct line *info=start; char rest_str[MAX]; if(line_num == 1) info = start; else for(int i=1;i<line_num;i++)       //让info指向删除内容所在行  info = info->next;       if (info == NULL)  printf("该行没有字符!n"); else {  if (strlen(info->text) <= (position + lenth))  //本行的字符长度<=待删除的列号+删除长度,直接在当前位置插入'\0'   info->text[position] = '\0';  else  { int i;   for(i = position-1;info->text[i+lenth]!='\0';i++)   info->text[i]=info->text[i+lenth];   info->text[i]='\0';  } }}// 插入一行文字void insert1(){  int linenum;  printf("\t\t输入插入位置的行号:"); scanf("%d", &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("\t\t输入的行号不存在"); } else // 指定行存在,进行插入 {  info = (struct line *)malloc(sizeof(struct line));  printf("\t\t输入要插入的字符串:");  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;  } }}//插入文字到文本莫一行莫一列void insert2(char str[], int linenum, int position){  struct line * info; int len, i; int lenth; char rest_str[MAX],kongge[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, kongge);   //将空余的部分插入空格符   strcat(info->text, str);    //插入字符到列的未尾  }  else   //插入列在本行文字的中间  {   strcpy(rest_str, &info->text[position - 1]);   strcpy(&info->text[position - 1], str);   strcat(info->text, rest_str);  } }}  //替换void replace(){ PrintWord(); char str[MAX]; printf("\t\t输入想要替换的字符串:\t\t"); scanf("%s",&str); char replace[MAX];  printf("\t\t替换为:");  scanf("%s",&replace);   struct line *info; int i = 0, find_len, found = 0, position; char bijiao[MAX]; info = start; int find_num = 0;             //匹配到的次数  find_len = strlen(str); while (info)   //查询 {     i = 0;  //行间循环  while (i <= (strlen(info->text) - find_len))  //行内查找循环  { int k=0;      for(int j=i;j<i+find_len;j++)   // 行内的字符串从第一个开始按定长find_len赋给substring    {     bijiao[k] = info->text[j];     k++;   }   if (strcmp(bijiao,str) == 0)   {     find_num++;    delete2(info->num,i+1,find_len);    insert2(replace,info->num,i+1);    found = 1;   }    i++;  }  info = info->next; } if (found)  //查找成功  printf("\t\t该内容替换的总次数为%d\n",find_num); else   //查找不成功  printf("\t\t该内容不存在\n"); printf("\t\t经过替换后的内容为:\n"); PrintWord();   } //文件录入方式菜单void menu1(){  printf("\t\t|请选择录入方式    1:从键盘输入     2:从文件录入   |\n\t\t"); int i; scanf("%d",&i); getchar();  if(i>2||i<1)     {     printf("\t\t对不起,请输入正确的功能序号!\n"); } switch(i) {  case 1:   scanf_load();   system("cls");    break;  case 2:   file_load();   system("cls");    break;       } }//移动菜单 void menu_move(){   int choice; printf("\n\t\t|_____________________移动操作_______________________|\n"); printf("\n\t\t|----->1.    向下移动一行                <-----------|\n"); printf("\t\t|----->2.    向上移动一行                <-----------|\n"); printf("\t\t|----->3.    向右移动一列                <-----------|\n"); printf("\t\t|----->4.    向左移动一列                <-----------|\n"); printf("\t\t|----->5.    返回上级菜单                <-----------|\n"); printf("\t\t请选择"); scanf("%d",&choice);  int line_num,number; char str[2]; switch (choice)   {   case 1:   // 向下移动一行        printf("\t\t输人要移动的字符串所在行号:");    scanf("%d", &line_num);    struct line *info,*p;                    //新建一行空行     info = (struct line *)malloc(sizeof(struct line));    info->text[0] = ' ';    info->text[1] = '\0';    info->num = line_num;    if (line_num == 1)    //插入在首行    {      info->next = start;     start->prior = info;     start = info;     start->prior = NULL;     p=start->next;    }    else  //插入在其他行          {          p=start;       while (p->num != line_num)     p = p->next;                    //令p指向插入行     info->next=p;    info->prior=p->prior;    p->prior->next=info;    p->prior = info;}    while (p)   //插入行后面的行号都加1     {     p->num = p->num + 1;     p = p->next;     }    break;   case 2:   //向上移动一行    printf("\t\t输入要移动的字符串所在行号:");    scanf("%d",&line_num);    delete1(line_num-1);    break;   case 3:   //向右移动一列    printf("\t\t输人要移动的字符串所在行号:");    scanf("%d", &line_num);    printf("\t\t输入要移动的字符串所在列号:");    scanf("%d", &number);    str[0] = ' ';    str[1] = '\0';    insert2(str, line_num, number);    break;   case 4:   //向左移动    printf("\t\t输入要移动的字符串所在行号:");    scanf("%d", &line_num);    printf("\t\t输入要移动的字符串所在列号:");    scanf("%d", &number);    if (number <= 0)     printf("\t\t该列不存在");    else     delete2(line_num, number - 2, 1);    break;   case 5:   //退出移动    break;}  }//文本内容处理菜单void menu2(){   char str1[20]; char str2[20]; int a;do{ HeadWord(); printf_time();printf("\n\t\t ____________________________________________________\n");printf("\t\t|           文章内容处理菜单                         |\n");printf("\t\t|____________________________________________________|\n");printf("\t\t|---->  1、查找文章中的字符或者字符串                |\n");printf("\t\t|---->  2、删除文章中的字符或者字符串                |\n");printf("\t\t|---->  3、向文章中插入字符或者字符串                |\n");printf("\t\t|---->  4、移动文章字符或字符串                      |\n");printf("\t\t|---->  5、替换文章字符或字符串                      |\n");printf("\t\t|---->  6、返回主菜单                                |\n");printf("\t\t|---->  7、直接退出系统                              |\n");printf("\t\t|____________________________________________________|\n");printf("\t\t    请选择:"); scanf("%d",&a); switch(a) {  case 1:             system("cls");          HeadWord();           findstr();      printf("\t\t按回车键继续·····");    getchar();       getchar();    system("cls");       break;    case 2:          system("cls");           HeadWord();          printf("\t\t|    1:删除一行文字    2:删除莫一行,莫列,定长的内容|\n\t\t");          int delete_choice;             scanf("%d",&delete_choice);             getchar();             if(delete_choice == 1)            {       int linenum;       printf("\t\t当前文本为:\n");       PrintWord();                printf("\t\t请输入你删除行的行号:");          scanf("%d",&linenum);       getchar();                 delete1(linenum);   }             else if(delete_choice == 2)   {       int linenum, position,lenth;  //行,列,删除长度        printf("\t\t当前文本为:\n");       PrintWord();          printf("\t\t请输入要删除内容所在行,列,删除内容字节长度,中间用空格隔开\n");       printf("\t\t--->注意:汉字占两个字节\n\t\t");       scanf("%d %d %d",&linenum,&position,&lenth);       position = (position*2)-1;       getchar();       delete2(linenum,position,lenth);   }            printf("\t\t删除后的文章为:\n");            PrintWord();      printf("\t\t按回车键继续·····");   getchar();   getchar();   system("cls");      break;      case 3:                    system("cls");          HeadWord();            printf("\t\t|   1:插入一行文字      2:插入文字到文本到一行的中间|\n\t\t");            int insert_choice;            scanf("%d",&insert_choice);            if(insert_choice == 1)            {            printf("\t\t当前文本为:\n");   PrintWord();   insert1();}            else           {            printf("\t\t当前文本为:\n");   PrintWord();      char str[MAX]; int linenum; int position;      printf("\t\t输入插入位置一行号:");   scanf("%d", &linenum);   printf("\t\t输入插入位置-列号:");   scanf("%d", &position);   position = (position*2)-1;   printf("\t\t要插入的字符串:");   scanf("%s", str);   insert2(str,linenum,position);     }                       printf("\t\t插入字符或字符串后文章为:\n");            PrintWord();      printf("\t\t按回车键继续·····");   getchar();   getchar();   system("cls");      break;case 4:      system("cls");      HeadWord();   printf_time();      menu_move();      printf("\t\t移动后文本内容为:\n");   PrintWord();      printf("\t\t按回车键继续·····");   getchar();   getchar();   system("cls");      break;case 5:          system("cls");       HeadWord();      printf_time();      replace();      printf("\t\t按回车键继续·····");   getchar();   getchar();   system("cls");         break;}if(a==6)  { system("cls");  break;}if(a==7)  exit(0);    }while(1);        }//主菜单void Mainmenu(){  printf("\n\n\n\n\n\n\n\n\n\t\t\tWelcom to use our TXT edition system!\n"); printf("\n\n\t\t\t   欢迎您使用简易文本编辑器!\n"); printf("\n\n\n\n\n\n\n\n\npress Enter to continue..."); getchar(); system("cls"); int t; do{ HeadWord(); printf_time(); printf("\n"); printf("\t\t ____________________________________________________\n"); printf("\t\t|                 主菜单                             |\n"); printf("\t\t|                                                    |\n"); printf("\t\t|---->  1、输入文章内容                              |\n"); printf("\t\t|---->  2、进入文章内容处理菜单                      |\n"); printf("\t\t|---->  3、显示当前文章内容                          |\n"); printf("\t\t|---->  4、保存文本                                  |\n"); printf("\t\t|---->  5、退出文本编辑器                            |\n"); printf("\t\t|                                                    |\n"); printf("\t\t|    注:第一次运行本程序时请选择功能1               |\n"); printf("\t\t|____________________________________________________|\n"); printf("  \t\t  请选择:"); scanf("%d",&t); if(t>5||t<1) {     printf("对不起,无此功能,请输入正确的功能序号!\n"); } else switch(t) {       case 1:         system("cls");        HeadWord();       menu1();    printf("\t\t按回车键继续·····");    getchar();    getchar();    system("cls");             break;     case 2:         system("cls");        menu2();    break;  case 3:       system("cls");        HeadWord();    printf_time();    printf("\n\t\t ____________________文章内容为______________________\n");             PrintWord();    printf("\n");    printf("\t\t按回车键继续·····");    getchar();    getchar();    system("cls");    break;  case 4:    HeadWord();       save();       break;     }   if(t==5) break; }while(1);}

关于“C语言如何实现简易文本编译器”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯