使用C语言实现一个名单的初始化增删改查等基础操作,并完善其健壮性和优化体验。(基于顺序表算法)

⭐引用的头文件

①#include<stdio.h>

②#include<string.h>:这个头文件在处理字符串时用的,使用了strcmp和strncpy,strlen这三个函数

③#include<windows.h>:这个头文件用来引用sleep进行一个短暂的停顿

④#include<stdlib.h>:这个头文件用来引用system("cls")函数进行清屏

⭐本文中的一些宏定义

#define MaxSize 50:这个宏定义来规定顺序表的最大长度

#define MaxSize_Item 30:这个宏定义来规定数据项数组的最大长度

#define true 1  和  #define false 0:由于在C语言中没有bool类型,故用true和false代替1和0

接下来开始程序的解读

目录

⭐第一部分:定义一个顺序表以及顺序表中各个数据元素的数据项

①定义每个数据元素的数据项

②定义一个顺序表

⭐第二部分  函数部分(除了main函数)

(一)辅助函数

①函数NumJudge()用于判断字符串中是否全为数字,其实现方式如下:

②函数refresh主要实现清屏操作

⭐(二)对顺序表的操作函数

①初始化顺序表:InitList

②重置顺序表:ClearList

③判断顺序表是否为空表:ListEmpty

④查询顺序表中数据元素的个数:ListLength

⑤按位查找数据元素:GetElem

⑥按名字查找数据元素的位数:LocateElem

⑦按位数插入数据元素:ListInsert

⑧实现删除操作:ListDelete

⑨按名字删除数据元素:ListDelete_name

⑩输出顺序表:output_list

⭐第三部分:main函数部分

①解决当错误地输入了一个非纯数字的输入造成卡死的难题

②检测当输入的是纯数字时,输入是否合法

③菜单中操作的选择

⭐第四部分.整个程序


⭐第一部分:定义一个顺序表以及顺序表中各个数据元素的数据项

struct Data_Item
{
	char name[MaxSize_Item];
	char number[MaxSize_Item];
	char gender[MaxSize_Item];
	char age[MaxSize_Item];
	char class_and_grade[MaxSize_Item];
};//定义每个数据元素的数据项

typedef struct 
{
	Data_Item Item[MaxSize];
	int length;
}SeqList;//定义一个顺序表
/*定义了一个每个数据元素都有属于自己的多个数据项的顺序表*/

①定义每个数据元素的数据项:

 我们声明了一个结构体类型,结构体中的每个成员,都是一个数组,每个数组中储存一个字符串

②定义一个顺序表

⭐第二部分  函数部分(除了main函数)

(一)辅助函数

int NumJudge(const char Array[]);
//判断一个字符串中是否全为数字,若全为数字,返回true(也就是1),否则返回false(也就是0)
void refresh(void);
//刷新屏幕的函数

①函数NumJudge()用于判断字符串中是否全为数字,其实现方式如下:

int NumJudge(const char Array[MaxSize_Item])
{
	for (int i = 0; i < strlen(Array); i++)
	{
		int temp = (int)Array[i];

		if (temp >= 48 && temp <= 57)
		{
			continue;
		}//使用ASCⅡ码判断是否是数字,若是数字则接着进入IF语句
		else
		{
			return false;
		}//若不是纯数字则直接返回false
	}
	return true;//否则返回true
}//判断一个字符串中是否全为数字

原理:该函数的形参是一个字符串,用来接收一个字符串,我们我们用for循环遍历字符串数组中的每一个元素,检查元素是否是数字。使用的方法是ASCⅡ码进行检测,即检测元素的ASCⅡ码是否在{}[48,57]中,如果在,即说明元素是数字,接着在if语句中进行下个数组元素的判断,否则则说明不是纯数字,返回false(即0),当遍历完整个数组时且没有检测到非数字时,返回ture。

②函数refresh主要实现清屏操作

void refresh(void)
{
	printf("按回车键进入下一步并刷新屏幕");
	int temp = getchar();
	Sleep(1000); system("cls");
}

原理:其实在这里getchar()并不能识别回车,但是要进行下一个操作时一定需要敲回车,所以无论我们输入什么,必须要敲回车才能进行下一步操作,从而实现了“按回车键进入下一步并刷新屏幕”的功能,然后使用Sleep(1000)停顿1000ms,system("cls")进行清屏。

⭐(二)对顺序表的操作函数

void InitList(SeqList* L);
//①初始化顺序表
void ClearList(SeqList* L);
//②重置顺序表
int ListEmpty(SeqList L);
//③判断顺序表是否为空表
int ListLength(SeqList L);
//④计算顺序表长度
int GetELem(SeqList L, int i);
//⑤按位查找顺序表中
int LocateElem(SeqList L, const char name[]);
//⑥按名字查找顺序表中数据元素的位数
int ListInsert(SeqList* L, int i, const char name[], const char number[], const char gender[], const char age[], const char class_and_grade[]);
//⑦在顺序表中插入数据元素
int ListDelete(SeqList* L, int i);
//⑧在顺序表中删除数据元素
int ListDelete_name(SeqList* L, const char name[MaxSize_Item]);
//⑨在顺序表中按名字删除数据元素
int output_list(SeqList L);
//⑩输出顺序表

①初始化顺序表:InitList

void InitList(SeqList* L)
{
	for (int i = 0; i < MaxSize; i++)
	{
		(*L).Item[i].name[0] = 0;
		(*L).Item[i].number[0] = 0;
		(*L).Item[i].gender[0] = 0;
		(*L).Item[i].age[0] = 0;
		(*L).Item[i].class_and_grade[0] = 0;
		//因为一个字符串的结尾是\0,所以在这个语境中,只需要字符型数字的第一个元素是0即可
	}
	(*L).length = 0;//将顺序表的长度变为0
}//①初始化顺序表

我们定义并使用函数InitList来完成这个操作,函数的形参是一个指针,用来接收&L,使得我们能在函数内修改顺序表中的内容(以下函数中的指针目的相同)。

利用for循环遍历每一个数据元素,令数据项数组的第一个元素为0的目的是,在字符数组的语境下,如果第一个元素为0,后面的元素就不会再读了(因为字符串的最后一定是存储的\0),令元素为0就代表着字符串在此元素的位置结束,从而实现字符型数组清空的目的。

最后使用(*L).Length=0;将顺序表长度变为0。

②重置顺序表:ClearList

void ClearList(SeqList* L)
{
	for (int i = 0; i <(*L).length; i++)
	{
		(*L).Item[i].name[0] = 0;
		(*L).Item[i].number[0] = 0;
		(*L).Item[i].gender[0] = 0;
		(*L).Item[i].age[0] = 0;
		(*L).Item[i].class_and_grade[0] = 0;
	}
	(*L).length = 0;
	//原理同初始化顺序表一样
	printf("\n该表已重置\n");
}//②重置表

我们定义并使用函数ClearList来完成这个操作,原理和 ①初始化顺序表 基本相同,最后输出提示,该表已重置。

③判断顺序表是否为空表:ListEmpty

⭐我们定义了一个计数器sum,我们读取数据项数组的首个元素,并用强制类型转换将其转化为整型,如果首个元素不为0(即数据项中有数据),计数器就加上一个数字,遍历完所有数据项中,如果各个数据项中皆没有存放数据,那么计数器sum==0,如果存放了哪怕一个元素,那么sum!=0。然后根据sum的数值和顺序表的长度输出提示,返回true和false。

int ListEmpty(SeqList L)
{
	int sum = 0;//定义了一个计数器
	for (int i = 0; i < L.length; i++)
	{
		sum=sum+(int)L.Item[i].name[0] ;
		sum=sum+(int)L.Item[i].number[0] ;
		sum=sum+(int)L.Item[i].gender[0] ;
		sum=sum+(int)L.Item[i].age[0] ;
		sum=sum+(int)L.Item[i].class_and_grade[0] ;
	}
	if (sum == 0 && L.length == 0)
	{
		printf("\n该表为空表\n");
		return true;
	}
	else
	{
		printf("\n该表不是空表\n");
		return false;
	}
	//如果每个数据项中没有数据,其值应该是0,最终sum=0,否则sum不为0
}//③判断是否顺序表是否为空表

④查询顺序表中数据元素的个数:ListLength

int ListLength(SeqList L)
{
	printf("\n该表中一共有%d个数据元素\n",L.length);
	return L.length;
	//该函数的原理是通过返回顺序表表厂得出顺序表中有多少个数据元素
}//④返回L中数据元素个数

我们使用函数ListLength输出并返回顺序表的元素个数,通过检测顺序表的长度来实现。

⑤按位查找数据元素:GetElem



int GetElem(SeqList L,int i)
{
	if (i<1 || i>L.length + 1)
	{
		printf("\n输入位数不合法\n");
		return false;
	}

	if (L.length >= MaxSize)
	{
		printf("\n输入位数不合法\n");
		return false;
	}
	
	if (i > L.length)
	{
		printf("\n输入位数不合法\n");
		return false;
	}
	//首先要判断输入的位数合不合法,即不超过现有顺序表的长度,也不小于1,同时也不超过顺序表的最大长度
	printf("\n_________________________________________________________\n");
	printf("|%s\t|%s\t\t|%s\t|%s\t|%s\t|\n", L.Item[i-1].name, L.Item[i-1].number, L.Item[i-1].gender, L.Item[i-1].age, L.Item[i-1].class_and_grade);
	printf("_________________________________________________________\n\n");
	//打印出查找出的数据元素
	return true;
}//⑤按位查找数据元素

首先要判断输入的位数合不合法,即不超过现有顺序表的长度,也不小于1,同时也不超过顺序表的最大长度,否则输出提示。当输入位数合法时,输出数据元素

⑥按名字查找数据元素的位数:LocateElem

int LocateElem(SeqList L, const char name[])
{
    for (int i = 0; i < L.length; i++)
	{
		if (!strcmp(L.Item[i].name, name))
		{
			printf("\n%s在第%d位\n", name, i + 1);
			return true;
		}//用strcmp函数判断数据项是否和需要查找的名字一致,若一致则返回true,并打印出其位次
	}//用for循环遍历顺序表中的所有数据元素
	printf("\n%s不在表内\n",name);
	return false;
}//⑥按姓名查找位数

我们使用for循环遍历顺序表中所有数据元素中名为name的数据项,我们在这里使用strcmp来检测各个名为name的数据项是否与我们输入的字符串相同,当检测到相同时,输出位数提示,并返回true,否则输出不在表内的提示,并返回false。

⑦按位数插入数据元素:ListInsert

int ListInsert(SeqList* L, int i,const char name[],const char number[],const char gender[],const char age[],const char class_and_grade[])
{
	
	
	if (i<1 || i>(*L).length + 1)
	{
		printf("\n输入位数不合法\n");
		return false;
	}

	if ((*L).length >= MaxSize)
	{
		printf("\n输入位数不合法\n");
		return false;
	}
	//首先先检测输入的位数合不合法
	strncpy_s((*L).Item[i - 1].gender, gender, 9);
	strncpy_s((*L).Item[i - 1].age, age, 9);

	if (!(!strcmp((*L).Item[i-1].gender, "男")|| !strcmp((*L).Item[i-1].gender, "女")|| !strcmp((*L).Item[i-1].gender, "未知")))
	{
		
		
		printf("\n输入的性别不合法\n");

		(*L).Item[i-1].gender[0] = 0;//检测出不合法就将性别数据项归0
		return false;
	}//其次检测输入的性别合不合法,即只有男,女,未知三个选项
	if (NumJudge((*L).Item[i - 1].age)==false)
	{
		printf("\n输入的年龄%s不合法\n", (*L).Item[i - 1].age);

		(*L).Item[i - 1].age[0] = 0;//检测出不合法就将年龄数据项归零
		return false;
	}//最后检测输入的年龄合不合法,即是否是全数字,这里要用到辅助函数NumJudge

	for (int j = (*L).length; j >= i; j--)
	{
		(*L).Item[j] = (*L).Item[j - 1];
	}
	//插入点之后的数据元素全部后移一位
	strncpy_s((*L).Item[i-1].name, name, 9);
	strncpy_s((*L).Item[i-1].number, number, 9);
	strncpy_s((*L).Item[i-1].class_and_grade, class_and_grade, 9);
	//录入输入的数据项
	(*L).length++;
	printf("\n录入成功\n");
	//输出提醒
	return true;
}//⑦实现插入操作

这个函数比较复杂,首先检测输入的位数是否合法,即满足[1,顺序表长度]且位数小于顺序表储存上限

if (i<1 || i>(*L).length + 1)
	{
		printf("\n输入位数不合法\n");
		return false;
	}

	if ((*L).length >= MaxSize)
	{
		printf("\n输入位数不合法\n");
		return false;
	}
	//首先先检测输入的位数合不合法

然后我们检测输入的性别是否只有“男”,“女”,“未知“。我们使用strncpy_s将形式参数抄到数据项中,然后判断是否输入的字符串为”男“或”女“或”未知“。如果不是,输出提示,同时使gender对应的数据项清零并返回false。

strncpy_s((*L).Item[i - 1].gender, gender, 9);
	strncpy_s((*L).Item[i - 1].age, age, 9);

	if (!(!strcmp((*L).Item[i-1].gender, "男")|| !strcmp((*L).Item[i-1].gender, "女")|| !strcmp((*L).Item[i-1].gender, "未知")))
	{
		
		
		printf("\n输入的性别不合法\n");

		(*L).Item[i-1].gender[0] = 0;//检测出不合法就将性别数据项归0
		return false;
	}//其次检测输入的性别合不合法,即只有男,女,未知三个选项

 最后检测输入的年龄合不合法,即是否是全数字,这里要用到辅助函数NumJudge。当NumJudge返回false时,说明输入的不是纯数字,输入不合法。输出提示,同时使age对应的数据项清理并返回false。

if (NumJudge((*L).Item[i - 1].age)==false)
	{
		printf("\n输入的年龄%s不合法\n", (*L).Item[i - 1].age);

		(*L).Item[i - 1].age[0] = 0;//检测出不合法就将年龄数据项归零
		return false;
	}//最后检测输入的年龄合不合法,即是否是全数字,这里要用到辅助函数NumJudge

检测完毕后,我们就可以使用for循环使得插入位的元素向后移一位,并使用strncpy_s将输入的字符串写入数据项中,然后使顺序表长度+1,输出“录入成功”的字样


	for (int j = (*L).length; j >= i; j--)
	{
		(*L).Item[j] = (*L).Item[j - 1];
	}
	//插入点之后的数据元素全部后移一位
	strncpy_s((*L).Item[i-1].name, name, 9);
	strncpy_s((*L).Item[i-1].number, number, 9);
	strncpy_s((*L).Item[i-1].class_and_grade, class_and_grade, 9);
	//录入输入的数据项
	(*L).length++;
	printf("\n录入成功\n");
	//输出提醒

⑧实现删除操作:ListDelete

int ListDelete(SeqList* L, int i)
{
	if (i<1 || i>(*L).length)
	{
		printf("\n输入位数不合法\n");
		return false;
	}//检测删除操作是否合法
	for (int j = i; j < (*L).length; j++)
	{
		(*L).Item[j - 1] = (*L).Item[j];
	}//删除数据元素之后的数据元素全部前移一位
	(*L).length--;//顺序表长度-1
	printf("\n删除成功\n");
	return ture;
}//⑧实现删除操作

先检测删除操作是否合法,再把删除的数据元素全部前移以为,顺序表长度-1,并打印出提示即可

⑨按名字删除数据元素:ListDelete_name

⭐我们在此又定义了一个计数器sum

int ListDelete_name(SeqList* L, const char name[MaxSize_Item])
{
	int sum = 0; int j;
	for (int i = 1; i <= (*L).length; i++)
	{

		if (!strcmp((*L).Item[i - 1].name, name))
		{
			for ( j = i; j <= (*L).length; j++)
			{
				(*L).Item[j - 1] = (*L).Item[j];
			}//删除数据元素之后的数据元素全部前移一位
			(*L).length--;//顺序表长度-1
			sum++;//计数器加一
			i = 0;//目的是让for循环重新从首位开始遍历,由于之后有i++,故设为0
		}
	}
	if (sum > 0)
	{
		printf("删除成功,删除了%d个数据元素",sum);
		return true;
	}//输出提示,并告诉用户删除了几个数据元素
	if (sum == 0)
	{
		printf("\n%s不在表内\n", name);
		return false;
	}//输出提示
	return false;
}//⑨实现按名字删除

先使用for循环查找与输入相同的name数据项并删除,之后通过计数器判断进行哪个输出提示。

⑩输出顺序表:output_list

int output_list(SeqList L)
{
	if (L.length == 0)
	{
		printf("\n该表为空表\n");
		return false;
	}
	else
	{
		printf("\n_________________________________________________________\n");
		printf("|姓名\t|学号\t\t|性别\t|年龄\t|所属\t\t|\n");
		for (int i = 0; i < L.length; i++)
		{
			printf("_________________________________________________________\n");
			printf("|%s\t|%s\t\t|%s\t|%s\t|%s\t|\n", L.Item[i].name, L.Item[i].number, L.Item[i].gender, L.Item[i].age, L.Item[i].class_and_grade);
		}
		printf("_________________________________________________________\n\n\n");
		return true;
	}
}//⑩输出顺序表

首先判断是否为空表,不是空表则输出表格

⭐第三部分:main函数部分

⭐main函数中所需要用到的变量: 

      ①choice:选择操作项目时用到;
      ②i:循环时作计数器用
      ③temp:配合getchar()清除缓冲区中的'\n'
      ④n:接受scanf_s的返回值

解决当错误地输入了一个非纯数字的输入造成卡死的难题

首先我们要解决的一个重点难题,当我们输入选择时,错误地输入了一个非纯数字的输入,这种情况该怎么办?

为了方便理解,在此展示一个错误写法

#include<stdio.h>
int main (void)
{
  int choice;
  do
  {
	fflush(stdin);
	n = scanf_s("%d". & choice);

  } while (n != 1);

  return 0;
}

当我们在键盘中输入一个123,时123就被放进了输入缓冲区中,此时scanf_s能够读取123这个数据,程序运行没有问题。但是当我们在键盘中输入xmx时,xmx被放入缓冲区,此时由于xmx并非纯数字,而scanf_s中的转换说明为%d且choice为整型变量,所以scanf_s没有读取走xmx,xmx从此就留在了缓冲区,哪怕我们设置循环也没有用,因为xmx一直在缓冲区,导致我们甚至没办法接着输入数据,由此造成了卡死的现象。

有人可能要说我们这里不是加了fflush(stdin)吗?实际上fflush(stdin)在任何情况下都没有意义,因为stdin是只读的,没有输入缓冲区,而fflush只能清空输入缓冲区,不得不说这种写法在某些平台和老的msvc上有清空输入缓冲的行为,但是这个行为是不标准的,所以我们不能这样写。(笔者在codeblocks上用上述错误代码成功运行了,visual studio 2022则失败)

下面展示正确写法

while (1)
		{
			n = scanf_s("%d", &choice);
			temp = getchar();//清除缓冲区的'\n'
			if (n == 1)//n==1时,说明输入的是纯数字,可被scanf_s全部读取
			{
				break;
			}
			else//n!=1时,说明输入的不是纯数字,不可被scanf_s全部读取,即输入不合法
			{
				printf("\n输入不合法,请输入1-10以内的数字\n");
				Sleep(1000);
				system("cls");
				//sleep()和system("cls")用作短暂停顿后清屏,与之前定义的refresh()原理相同
				printf("\n**************************\n");
				printf("请问你想进行的操作是?:\n");
				printf("①重置顺序表\n");
				printf("②判断表是否为空表\n");
				printf("③反回表中的数据元素个数\n");
				printf("④按位置查找数据元素\n");
				printf("⑤按姓名查找数据元素\n");
				printf("⑥在顺序表中插入指定数据元素\n");
				printf("⑦在顺序表中按位删除指定数据元素\n");
				printf("⑧在顺序表中按名字删除指定数据元素\n");
				printf("⑨输出指定顺序表\n");
				printf("⑩顺序添加元素\n");
				printf("**************************\n\n");
				printf("请输入1-10之内的数字选择操作:");
				//打印出菜单
				while (getchar() != '\n')
				{
					;
				}//该循环将不断地吞掉缓冲区的字符,直到读到换行符为止,这样即可保证缓冲区被清空
			}
		}

这个写法的原理是如下:

用n读取scanf_s的返回值,当输入正确时,scanf_s返回一个正整数代表输入正确的参数的个数(此处是1)。当输入不合法时,scanf_s返回0。

那么我们假设我们此时在键盘上写出了1,这是一个合法操作,此时我们用temp=getchar();来吞掉缓冲区中遗留的'\n'。当我们输入了xmx时,这是一个非法操作,那么我们便可以用以下循环清除缓冲区

while (getchar() != '\n')
				{
					;
				}

该循环将不断地吞掉缓冲区的字符,直到读到换行符为止,这样即可保证缓冲区被清空。

此时我们就可以进行重新输入啦!

②检测当输入的是纯数字时,输入是否合法

if (choice > 10 || choice < 1)
		{
			printf("\n输入错误,请输入1-10以内的数字\n");
			Sleep(1000);
			system("cls");
		}
		//检测当键盘上输入的是纯数字的情况下,选择是否合法

此串代码的原理略

③菜单中操作的选择

switch (choice)
			{
			case 1:
			{
				ClearList(&L);
				
				refresh();
				//实现按回车后清屏,下同

				break;
			}
			case 2:
			{
				ListEmpty(L);

				refresh();
				break;
			}
			case 3:
			{
				ListLength(L);

				refresh();
				break;
			}
			case 4:
			{
				printf("请输入要查找对象的位数:\n\n");
				
				scanf_s("%d", &i);
				temp = getchar();
				
				GetELem(L, i);
				i = 0;
				
				refresh();
				
				break;
			}
			case 5:
			{
				printf("请输入要查找的姓名\n\n");
				scanf_s("%s", &name, 30);
				temp = getchar();
				
				LocateElem(L, name);
				name[0] = 0;
				i = 0;
				
				refresh();
				break;
			}
			case 6:
			{
				printf("请依次输入插入位数,姓名,编号,性别,年龄,所属:\n\n");
				scanf_s("%d%s%s%s%s%s", &i, &name, 30, &number, 30, &gender, 30, &age, 30, &class_and_grade, 30);
				temp = getchar();
				
				ListInsert(&L, i, name, number, gender, age, class_and_grade);
				
				name[0] = 0;
				number[0] = 0;
				gender[0] = 0;
				age[0] = 0;
				class_and_grade[0] = 0;
				i = 0;
				
				refresh();
				break;
			}
			case 7:
			{
				printf("请输入要删除的数据位数:\n\n");
				scanf_s("%d", &i);
				temp = getchar();
				ListDelete(&L, i);
				i = 0;
				
				refresh();
				break;
			}
			case 8:
			{
				printf("请输入要删除的名字:\n\n");
				scanf_s("%s", &name, 30);
				temp = getchar();
				ListDelete_name(&L, name);
				
				refresh();
				break;
			}
			case 9:
			{
				output_list(L); 
				
				refresh();
				break;
			}
			case 10:
			{
				printf("请依次输入插入姓名,编号,性别,年龄,所属:\n\n");
				scanf_s("%s%s%s%s%s", &name, 30, &number, 30, &gender, 30, &age, 30, &class_and_grade, 30);
				temp = getchar();
				
				ListInsert(&L, L.length + 1, name, number, gender, age, class_and_grade);
				name[0] = 0;
				number[0] = 0;
				gender[0] = 0;
				age[0] = 0;
				class_and_grade[0] = 0;
				
				refresh();
				break;
			}
			}

显然,我们可以使用switch函数来进行选择,具体操作略,值得注意的是我们要在每个scanf_s后面添加上temp=getchar();来吞掉缓冲区里的'\n',此外还需注意使用我们的refresh函数进行一个清屏操作。

⭐第四部分.整个程序

至此,整个程序介绍完毕,以下是完整程序:

#include<stdio.h>
#include<string.h>
#include <windows.h>
#include<stdlib.h>
//引用的所有头文件
#define MaxSize 50
#define MaxSize_Item 30
//规定数组大小的宏定义

#define ture 1
#define false 0
//因为C语言中没有bool类型,用1和0代替true 和 false



/*------------------------------------------------分割线----------------------------------------------------------*/
struct Data_Item
{
	char name[MaxSize_Item];
	char number[MaxSize_Item];
	char gender[MaxSize_Item];
	char age[MaxSize_Item];
	char class_and_grade[MaxSize_Item];
};//定义每个数据元素的数据项

typedef struct 
{
	Data_Item Item[MaxSize];
	int length;
}SeqList;//定义一个顺序表
/*定义了一个每个数据元素都有属于自己的多个数据项的顺序表*/


/*------------------------------------------------分割线----------------------------------------------------------*/
int NumJudge(const char Array[]);
//判断一个字符串中是否全为数字,若全为数字,返回true(也就是1),否则返回false(也就是0)
void refresh(void);
//刷新屏幕的函数
void InitList(SeqList* L);
//①初始化顺序表
void ClearList(SeqList* L);
//②重置顺序表
int ListEmpty(SeqList L);
//③判断顺序表是否为空表
int ListLength(SeqList L);
//④计算顺序表长度
int GetELem(SeqList L, int i);
//⑤按位查找顺序表中
int LocateElem(SeqList L, const char name[]);
//⑥按名字查找顺序表中数据元素的位数
int ListInsert(SeqList* L, int i, const char name[], const char number[], const char gender[], const char age[], const char class_and_grade[]);
//⑦在顺序表中插入数据元素
int ListDelete(SeqList* L, int i);
//⑧在顺序表中删除数据元素
int ListDelete_name(SeqList* L, const char name[MaxSize_Item]);
//⑨在顺序表中按名字删除数据元素
int output_list(SeqList L);
//⑩输出顺序表
/*全体函数,除main函数外共12个*/
/*------------------------------------------------分割线----------------------------------------------------------*/

void InitList(SeqList* L)
{
	for (int i = 0; i < MaxSize; i++)
	{
		(*L).Item[i].name[0] = 0;
		(*L).Item[i].number[0] = 0;
		(*L).Item[i].gender[0] = 0;
		(*L).Item[i].age[0] = 0;
		(*L).Item[i].class_and_grade[0] = 0;
		//因为一个字符串的结尾是\0,所以在这个语境中,只需要字符型数字的第一个元素是0即可
	}
	(*L).length = 0;//将顺序表的长度变为0
}//①初始化顺序表

void ClearList(SeqList* L)
{
	for (int i = 0; i <(*L).length; i++)
	{
		(*L).Item[i].name[0] = 0;
		(*L).Item[i].number[0] = 0;
		(*L).Item[i].gender[0] = 0;
		(*L).Item[i].age[0] = 0;
		(*L).Item[i].class_and_grade[0] = 0;
	}
	(*L).length = 0;
	//原理同初始化顺序表一样
	printf("\n该表已重置\n");
}//②重置表

int ListEmpty(SeqList L)
{
	int sum = 0;//定义了一个计数器
	for (int i = 0; i < L.length; i++)
	{
		sum=sum+(int)L.Item[i].name[0] ;
		sum=sum+(int)L.Item[i].number[0] ;
		sum=sum+(int)L.Item[i].gender[0] ;
		sum=sum+(int)L.Item[i].age[0] ;
		sum=sum+(int)L.Item[i].class_and_grade[0] ;
	}
	if (sum == 0 && L.length == 0)
	{
		printf("\n该表为空表\n");
		return true;
	}
	else
	{
		printf("\n该表不是空表\n");
		return false;
	}
	//如果每个数据项中没有数据,其值应该是0,最终sum=0,否则sum不为0
}//③判断是否顺序表是否为空表

int ListLength(SeqList L)
{
	printf("\n该表中一共有%d个数据元素\n",L.length);
	return L.length;
	//该函数的原理是通过返回顺序表表厂得出顺序表中有多少个数据元素
}//④返回L中数据数据元素个数

int GetELem(SeqList L,int i)
{
	if (i<1 || i>L.length + 1)
	{
		printf("\n输入位数不合法\n");
		return false;
	}

	if (L.length >= MaxSize)
	{
		printf("\n输入位数不合法\n");
		return false;
	}
	
	if (i > L.length)
	{
		printf("\n输入位数不合法\n");
		return false;
	}
	//首先要判断输入的位数合不合法,即不超过现有顺序表的长度,也不小于1,同时也不超过顺序表的最大长度
	printf("\n_________________________________________________________\n");
	printf("|%s\t|%s\t\t|%s\t|%s\t|%s\t|\n", L.Item[i-1].name, L.Item[i-1].number, L.Item[i-1].gender, L.Item[i-1].age, L.Item[i-1].class_and_grade);
	printf("_________________________________________________________\n\n");
	//打印出查找出的数据元素
	return true;
}//⑤按位查找数据元素

int LocateElem(SeqList L, const char name[])
{
    for (int i = 0; i < L.length; i++)
	{
		if (!strcmp(L.Item[i].name, name))
		{
			printf("\n%s在第%d位\n", name, i + 1);
			return true;
		}//用strcmp函数判断数据项是否和需要查找的名字一致,若一致则返回true,并打印出其位次
	}//用for循环遍历顺序表中的所有数据元素
	printf("\n%s不在表内\n",name);
	return false;
}//⑥按姓名查找位数

int ListInsert(SeqList* L, int i,const char name[],const char number[],const char gender[],const char age[],const char class_and_grade[])
{
	
	
	if (i<1 || i>(*L).length + 1)
	{
		printf("\n输入位数不合法\n");
		return false;
	}

	if ((*L).length >= MaxSize)
	{
		printf("\n输入位数不合法\n");
		return false;
	}
	//首先先检测输入的位数合不合法
	strncpy_s((*L).Item[i - 1].gender, gender, 9);
	strncpy_s((*L).Item[i - 1].age, age, 9);

	if (!(!strcmp((*L).Item[i-1].gender, "男")|| !strcmp((*L).Item[i-1].gender, "女")|| !strcmp((*L).Item[i-1].gender, "未知")))
	{
		
		
		printf("\n输入的性别不合法\n");

		(*L).Item[i-1].gender[0] = 0;//检测出不合法就将性别数据项归0
		return false;
	}//其次检测输入的性别合不合法,即只有男,女,未知三个选项
	if (NumJudge((*L).Item[i - 1].age)==false)
	{
		printf("\n输入的年龄%s不合法\n", (*L).Item[i - 1].age);

		(*L).Item[i - 1].age[0] = 0;//检测出不合法就将年龄数据项归零
		return false;
	}//最后检测输入的年龄合不合法,即是否是全数字,这里要用到辅助函数NumJudge

	for (int j = (*L).length; j >= i; j--)
	{
		(*L).Item[j] = (*L).Item[j - 1];
	}
	//插入点之后的数据元素全部后移一位
	strncpy_s((*L).Item[i-1].name, name, 9);
	strncpy_s((*L).Item[i-1].number, number, 9);
	strncpy_s((*L).Item[i-1].class_and_grade, class_and_grade, 9);
	//录入输入的数据项
	(*L).length++;
	printf("\n录入成功\n");
	//输出提醒
	return true;
}//⑦实现插入操作

int ListDelete(SeqList* L, int i)
{
	if (i<1 || i>(*L).length)
	{
		printf("\n输入位数不合法\n");
		return false;
	}//检测删除操作是否合法
	for (int j = i; j < (*L).length; j++)
	{
		(*L).Item[j - 1] = (*L).Item[j];
	}//删除数据元素之后的数据元素全部前移一位
	(*L).length--;//顺序表长度-1
	printf("\n删除成功\n");
	return ture;
}//⑧实现删除操作

int ListDelete_name(SeqList* L, const char name[MaxSize_Item])
{
	int sum = 0; int j;
	for (int i = 1; i <= (*L).length; i++)
	{

		if (!strcmp((*L).Item[i - 1].name, name))
		{
			for ( j = i; j <= (*L).length; j++)
			{
				(*L).Item[j - 1] = (*L).Item[j];
			}//删除数据元素之后的数据元素全部前移一位
			(*L).length--;//顺序表长度-1
			sum++;//计数器加一
			i = 0;//目的是让for循环重新从首位开始遍历,由于之后有i++,故设为0
		}
	}
	if (sum > 0)
	{
		printf("删除成功,删除了%d个数据元素",sum);
		return true;
	}//输出提示,并告诉用户删除了几个数据元素
	if (sum == 0)
	{
		printf("\n%s不在表内\n", name);
		return false;
	}//输出提示
	return false;
}//⑨实现按名字删除

int output_list(SeqList L)
{
	if (L.length == 0)
	{
		printf("\n该表为空表\n");
		return false;
	}
	else
	{
		printf("\n_________________________________________________________\n");
		printf("|姓名\t|学号\t\t|性别\t|年龄\t|所属\t\t|\n");
		for (int i = 0; i < L.length; i++)
		{
			printf("_________________________________________________________\n");
			printf("|%s\t|%s\t\t|%s\t|%s\t|%s\t|\n", L.Item[i].name, L.Item[i].number, L.Item[i].gender, L.Item[i].age, L.Item[i].class_and_grade);
		}
		printf("_________________________________________________________\n\n\n");
		return true;
	}
}//⑩输出顺序表

/*-----------------------------------------分割线-------------------------------------------------------------*/
/*辅助函数*/
int NumJudge(const char Array[MaxSize_Item])
{
	for (int i = 0; i < strlen(Array); i++)
	{
		int temp = (int)Array[i];

		if (temp >= 48 && temp <= 57)
		{
			continue;
		}//使用ASCⅡ码判断是否是数字,若是数字则接着进入IF语句
		else
		{
			return false;
		}//若不是纯数字则直接返回false
	}
	return true;//否则返回true
}//判断一个字符串中是否全为数字

void refresh(void)
{
	printf("按回车键进入下一步并刷新屏幕");
	int temp = getchar();
	Sleep(1000); system("cls");
}

/*-----------------------------------------分割线-------------------------------------------------------------*/

int main(void)
{
	SeqList L; InitList(&L);
	//建立并初始化顺序表
	
	char name[MaxSize_Item]; char number[MaxSize_Item]; char gender[MaxSize_Item]; char age[MaxSize_Item]; char class_and_grade[MaxSize_Item];
	//初始化数据项

	int choice; int i = 0; int temp = 0; int n;
	//初始化所需用到的变量
	/*
	  ①choice:选择操作项目时用到;
	  ②i;循环时作计数器用
	  ③temp;配合getchar()清除缓冲区中的'\n'
	  ④n;接受scanf_s的返回值
	*/

	while (1)
	{
		printf("\n**************************\n");
		printf("请问你想进行的操作是?:\n");
		printf("①重置顺序表\n");
		printf("②判断表是否为空表\n");
		printf("③反回表中的数据元素个数\n");
		printf("④按位置查找数据元素\n");
		printf("⑤按姓名查找数据元素\n");
		printf("⑥在顺序表中插入指定数据元素\n");
		printf("⑦在顺序表中按位删除指定数据元素\n");
		printf("⑧在顺序表中按名字删除指定数据元素\n");
		printf("⑨输出指定顺序表\n");
		printf("⑩顺序添加元素\n");
		printf("**************************\n\n");
		printf("请输入1-10之内的数字选择操作:");
		//打印出菜单
		
		while (1)
		{
			n = scanf_s("%d", &choice);
			temp = getchar();//清除缓冲区的'\n'
			if (n == 1)//n==1时,说明输入的是纯数字,可被scanf_s全部读取
			{
				break;
			}
			else//n!=1时,说明输入的不是纯数字,不可被scanf_s全部读取,即输入不合法
			{
				printf("\n输入不合法,请输入1-10以内的数字\n");
				Sleep(1000);
				system("cls");
				//sleep()和system("cls")用作短暂停顿后清屏,与之前定义的refresh()原理相同
				printf("\n**************************\n");
				printf("请问你想进行的操作是?:\n");
				printf("①重置顺序表\n");
				printf("②判断表是否为空表\n");
				printf("③反回表中的数据元素个数\n");
				printf("④按位置查找数据元素\n");
				printf("⑤按姓名查找数据元素\n");
				printf("⑥在顺序表中插入指定数据元素\n");
				printf("⑦在顺序表中按位删除指定数据元素\n");
				printf("⑧在顺序表中按名字删除指定数据元素\n");
				printf("⑨输出指定顺序表\n");
				printf("⑩顺序添加元素\n");
				printf("**************************\n\n");
				printf("请输入1-10之内的数字选择操作:");
				//打印出菜单
				while (getchar() != '\n')
				{
					;
				}//该循环将不断地吞掉缓冲区的字符,直到读到换行符为止,这样即可保证缓冲区被清空
			}
		}
		
		if (choice > 10 || choice < 1)
		{
			printf("\n输入错误,请输入1-10以内的数字\n");
			Sleep(1000);
			system("cls");
		}
		//检测当键盘上输入的是纯数字的情况下,选择是否合法
		else
		{
			switch (choice)
			{
			case 1:
			{
				ClearList(&L);
				
				refresh();
				//实现按回车后清屏,下同

				break;
			}
			case 2:
			{
				ListEmpty(L);

				refresh();
				break;
			}
			case 3:
			{
				ListLength(L);

				refresh();
				break;
			}
			case 4:
			{
				printf("请输入要查找对象的位数:\n\n");
				
				scanf_s("%d", &i);
				temp = getchar();
				
				GetELem(L, i);
				i = 0;
				
				refresh();
				
				break;
			}
			case 5:
			{
				printf("请输入要查找的姓名\n\n");
				scanf_s("%s", &name, 30);
				temp = getchar();
				
				LocateElem(L, name);
				name[0] = 0;
				i = 0;
				
				refresh();
				break;
			}
			case 6:
			{
				printf("请依次输入插入位数,姓名,编号,性别,年龄,所属:\n\n");
				scanf_s("%d%s%s%s%s%s", &i, &name, 30, &number, 30, &gender, 30, &age, 30, &class_and_grade, 30);
				temp = getchar();
				
				ListInsert(&L, i, name, number, gender, age, class_and_grade);
				
				name[0] = 0;
				number[0] = 0;
				gender[0] = 0;
				age[0] = 0;
				class_and_grade[0] = 0;
				i = 0;
				
				refresh();
				break;
			}
			case 7:
			{
				printf("请输入要删除的数据位数:\n\n");
				scanf_s("%d", &i);
				temp = getchar();
				ListDelete(&L, i);
				i = 0;
				
				refresh();
				break;
			}
			case 8:
			{
				printf("请输入要删除的名字:\n\n");
				scanf_s("%s", &name, 30);
				temp = getchar();
				ListDelete_name(&L, name);
				
				refresh();
				break;
			}
			case 9:
			{
				output_list(L); 
				
				refresh();
				break;
			}
			case 10:
			{
				printf("请依次输入插入姓名,编号,性别,年龄,所属:\n\n");
				scanf_s("%s%s%s%s%s", &name, 30, &number, 30, &gender, 30, &age, 30, &class_and_grade, 30);
				temp = getchar();
				
				ListInsert(&L, L.length + 1, name, number, gender, age, class_and_grade);
				name[0] = 0;
				number[0] = 0;
				gender[0] = 0;
				age[0] = 0;
				class_and_grade[0] = 0;
				
				refresh();
				break;
			}
			}
		}
	}

	return 0;
}//main函数

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值