顺序表应用——通讯录

在本篇之前的顺序表专题我们已经学习的顺序表的实现,了解了如何实现顺序表的插入和删除等功能,那么在本篇当中就要学习基于顺序表来实现通讯录,在通讯录当中能实现联系人的增、删、查改等功能,接下来就让我们一起来实现通讯录吧!
 


 1.实现通讯录前的分析

在实现通讯录的代码前我们要先思考在通讯录项目中能实现什么样的功能
(1)至少能够存储100个人的通讯信息
(2)能够保存用户信息:名字、性别、年龄、电话、地址等
(3)增加联系人信息
(4)删除指定联系人
(5)查找制定联系人
(6)修改指定联系人
(7)显示联系人信息

同时由于在之前的顺序表中使用的是动态顺序表,所以在实现通讯录项目中也基于的是动态顺序表

以下是该通讯录项目的程序文件设置以及各文件中所实现的内容

 

2.通讯录的实现 

2.1 联系人信息的设置以及顺序表内要做出的更改

 由于顺序表的底层就是数组,所以我们就是要利用数组来实现如以下所示的结构

在通讯录中由于我们要存储的是多个联系人的信息,因此要定义一个结构体来存储联系人的信息
以下定义结构体struct PersonIfon来存储联系人的信息,并且使用typedef将该结构体重命名为Persondef
并且在PersonIfon中的每个数组的大小用#define来定义

#define MAX_NAME 20
#define MAX_GENDER 10
#define MAX_TELE 20
#define MAX_ADRESS 50

typedef struct PersonIfon//联系人信息
{
	char name[MAX_NAME];//姓名
	char Gender[MAX_GENDER];//性别
	int age;//年龄
	char Tele[MAX_TELE];//电话
	char Adress[MAX_ADRESS];//地址

}PersonIfon;

同时由于要通讯录所以之前顺序表的Sqelist.h的数组类型也要更改,由用来的整型改变为PersonIfon,要实现该改变就需要在Seqlist.h内代码的头加上#define“contact.h”

这时Seqlist.h就变为以下形式

#pragma once
#define  _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>

typedef struct PersonIfon SLDataType;
typedef struct Seqlist
{
	SLDataType* arr;
	int size;//有效的数据个数
	int capacity;//空间大小

}SL;//将struct Seqlist重命名为SL

在之前的顺序表的结构体struct Seqlist被重命名为SL,但现在我们要实现的是通讯录这时这个名字就不太合适与直观,那该如何来在contact.h文件内对struct Seqlist进行重命名呢?
这时你可能想到是在contact.h内加上预处理指令#define“Seqlist.h”,
但这样就存在问题了,在之前的操作中我们已经在Seqlaist.h文件内包含了contact.h,如果在这再在contact.h内包含Seqlist.h就会存在头文件相互包含的问题,这时程序就会崩溃

所以正确的解决方法是什么呢?
其实这时只需要在contact.h中先声明以下struct Seqlist就可以对该结构体进行重命名了

struct Seqlist;
typedef struct Seqlist contact;

2.2  通讯录的初始化以及销毁


在以上完成联系人结构体的定义以及对顺序表内数组类型的更改,接下来就可以来实现通讯录初始化和销毁的函数了

在此先在contact.h内声明初始化函数以及销毁函数,由于在此要对通讯录内容进行更改,所以要进行传址调用,两个函数的参数都是结构体指针

void ContactInit(contact* con);//初始化通讯录
void ContactDestory(contact* con);//销毁通讯录

声明完之后就是在contact.c内实现以上两个函数,在此通讯录的初始化以及销毁内就可以直接调用之前顺序表的初始化以及销毁函数了

void ContactInit(contact* con)//通讯录初始化
{
	SLInit(con);
}
void ContactDestory(contact* con)//销毁通讯录
{
	SLDestory(con);
}

2.3通讯录的展示 

通讯录的展示就是将通讯录的信息都打印出来,实质就是要遍历一般数组
在此在printf中在占位符中的%后加入的最小宽度限制来让打印出的通讯录更有顺序

void ContactShow(contact* con)//展示通讯录
{
	printf("%-10s %-4s %-4s %15s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
	for (int i = 0; i < con->size; i++)
	{
		printf("%-10s %-4s %-4d %15s %-20s\n",
			con->arr[i].name,
			con->arr[i].Gender,
			con->arr[i].age,
			con->arr[i].Tele,
			con->arr[i].Adress);
	}
}

2.4通讯录各功能实现

在以上完成了通讯录的初始化和销毁接下来我们就来实现通讯录增、删、查、改的功能了

2.4.1 通讯录内添加联系人 

在此要实现通讯录中联系人的增加先在contact.h内对增加联系人函数进行声明,由于在此要对通讯录内容进行更改,所以要进行传址调用,函数的参数是结构体指针

void ContactAdd(contact* con);//通讯录内添加联系人

接下来就是在contact.c内完成添加联系人的函数
在此先创建一个结构体PersonIfon ifon,并且使用scanf来读取用户输入的此联系人的各信息存储在结构体ifon内,再调用顺序表中的插入函数将该结构体ifon插入到数组内,在此使用的是尾插函数,也可以使用其他插入方法

void ContactAdd(contact* con)//在通讯录内添加联系人
{
	PersonIfon ifon;
	printf("请输入联系人姓名:\n");
	scanf("%s", &ifon.name);
	printf("请输入联系人性别:\n");
	scanf("%s", &ifon.Gender);
	printf("请输入联系人年龄:\n");
	scanf("%d", &ifon.age);
	printf("请输入联系人电话:\n");
	scanf("%s", &ifon.Tele);
	printf("请输入联系人地址:\n");
	scanf("%s", &ifon.Adress);

	SLPushBack(con, ifon);
}

2.4.2 通讯录内删除联系人

在此要实现通讯录中联系人的删除先在contact.h内对删除联系人函数进行声明,由于在此要对通讯录内容进行更改,所以要进行传址调用,函数的参数是结构体指针

void ContactDel(contact* con);//通讯录内删除联系人

在声明完函数之后就是对该函数的实现,但在删除通讯录内的联系人要通讯录中存在要删除的联系人才能删除,所以在函数内还要先判断,但之后通讯录的其他功能可能还要用到查找联系人是否存在

所以可以直接在创建一个判断相关联系人是否存在的函数,在此根据的是名字来查找联系人

存在该联系人就返回相应的数组下标,不存在就返回-1

int FindbyName(contact* con, char* name)
{
	for (int i = 0; i < con->size; i++)
	{
		if (strcmp(con->arr[i].name, name)==0)
		{
			return i;
		}
	}
	return -1;
}

接下来就是在contact.c内完成删除联系人的函数
在此函数内先定义一个char类型的数组name,大小为MAX_NAME。用scanf将用户输入的联系人姓名存放在该数组内,之后再将指针con与name作为FindbyName的参数,通过FindbyName函数的返回值来得到要删除的联系人是否存在。若返回值小于0则说明该联系人不存在,之后就直接退出函数ContactDel,否则就调用顺序表中的任意位置的删除函数SLErase,这时tmp就是要删除的数组下标

void ContactDel(contact* con)//通讯录内删除联系人
{
	char name[MAX_NAME];
	printf("请输入要删除的联系人的姓名\n");
	scanf("%s", name);
	int tmp = FindbyName(con, name);
	if (tmp < 0)
	{
		printf("该联系人不存在,删除失败\n");
		return;
	}
	SLErase(con, tmp);
	printf("删除成功\n");

}

 2.4.3 通讯录内修改联系人

在此要实现通讯录中联系人的修改先在contact.h内对修改联系人函数进行声明,由于在此要对通讯录内容进行更改,所以要进行传址调用,函数的参数是结构体指针

void ContactModify(contact* con);//通讯录内修改联系人

 接下来就是在contact.c内完成修改联系人的函数
在该函数内和删除联系人函数一样也是先在此函数内先定义一个char类型的数组name,大小为MAX_NAME。用scanf将用户输入的联系人姓名存放在该数组内,之后再将指针con与name作为FindbyName的参数,通过FindbyName函数的返回值来得到要修改的联系人是否存在。若返回值小于0则说明该联系人不存在,之后就直接退出函数ContactDel。否则就使用scanf将用户输入的信息存放到原来联系人的数组位置

void ContactModify(contact* con)//修改联系人信息
{
	char name[MAX_NAME];
	printf("请输入要修改的联系人的姓名\n");
	scanf("%s", name);
	int tmp = FindbyName(con, name);
	if (tmp < 0)
	{
		printf("该联系人不存在,修改失败\n");
		return;
	}
	//直接修改
	printf("请输入新的联系人姓名:\n");
	scanf("%s", con->arr[tmp].name);
	printf("请输入新的联系人性别:\n");
	scanf("%s", con->arr[tmp].Gender);
	printf("请输入新的联系人年龄:\n");
	scanf("%d", &con->arr[tmp].age);
	printf("请输入新的联系人电话:\n");
	scanf("%s", con->arr[tmp].Tele);
	printf("请输入新的联系人地址:\n");
	scanf("%s", con->arr[tmp].Adress);

	
	printf("修改成功!\n");

}

 2.4.4 通讯录内查找联系人

 在此要实现通讯录中联系人的修改先在contact.h内对修改联系人函数进行声明,在此虽然查找联系人未对通讯录内数据进行修改,但在此还是将结构体作为函数的参数,原因通讯录其他函数都是传地址在此也保持一致性

void ContactFind(contact* con);//在通讯录内查找联系人

  接下来就是在contact.c内完成查找联系人的函数

在该函数内也是先定义一个char类型的数组name,再通过scanf函数将用户输入的字符串存储到数组内,在此并定义一个变量flag=-1再通过for循环遍历数组中的各个元素中的name是否和数组name相同相同就将flag赋值为1,相同就打印该元素的联系人信息,当遍历完时flag如果等于-1就打印查找不到联系人

void ContactFind(contact* con)//查找联系人
{
	char name[MAX_NAME];
	printf("请输入要查找的联系人的姓名\n");
	scanf("%s", name);
	int flag = -1;
	for (int i = 0; i < con->size; i++)
	{
		if (strcmp(con->arr[i].name, name) == 0)
		{
			flag = 1;
			printf("查找成功!\n");
			printf("%-10s %-4s %-4s %15s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
			
			printf("%-10s %-4s %-4d %15s %-20s\n",
				con->arr[i].name,
				con->arr[i].Gender,
				con->arr[i].age,
				con->arr[i].Tele,
				con->arr[i].Adress);
			
		}

	}
	if (flag == -1)
	{
		printf("你所要查找的联系人不存在!\n");
	}

}

 

3.通讯录test.c文件

在以上我们已经实现了通讯录各种功能,现在就需要在test.c内将这些设计好的功能给拼装起来,让程序能在运行窗口通过输入不同的数就可以实现通讯录的各功能
 

注:在test.c的开头要加上#include"SeqList.h"和#include"contact.h"

先在test.c内先创建main函数,同时要实现对通讯录的多次操作就需要用到循环,在此用的是do...while循环,在循环内在创建一个switch语句来实现用户输入不同的信息就进入不同的函功能。在switch语句内的case后的常量都使用枚举所定义的,这样会使得代码的可读性更高、同时shitch语句的case语句排序也可以是不按顺序来的。在不同的case语句内就调用不同的通讯录功能函数
 

在进入循环先初始化顺序表,退出循环就销毁顺序表 

#include"SeqList.h"
#include"contact.h"


void menu()
{
	printf("**************************************\n");
	printf("******1.添加联系人  2.删除联系人******\n");
	printf("******3.查找联系人  4.修改联系人******\n");
	printf("******5.展示通讯录  0.退出程序  ******\n");
	printf("**************************************\n");

}

enum option
{
	 ADD=1,
     DEL=2,
	 FIND=3,
     MODIFY=4,
     SHOW=5

};


int main()
{
	int input = 0;
	contact con;
	ContactInit(&con);
	do
	{
		menu();
		printf("请选择操作\n");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			 ContactAdd(&con);
			break;
		case DEL:
			ContactDel(&con);
			break;
		case FIND:
			ContactFind(&con);
			break;
		case MODIFY:
			ContactModify(&con);
			break;
		case SHOW:
			ContactShow(&con);
			break;
		default:
			printf("选择操作错误,请输入1~5内的数\n");
			break;

		}


	} while(input);//当输入的值为0时,input值也就也0,在此判断部分input就为假就会退出循环
	ContactDestory(&con);


	return 0;
}

 

4. 通讯录读取历史数据和保存数据

在之前已经实现了通讯录的各功能的数据只能在程序运行窗口打开的时候进行通讯录的增、删、查、改等功能。在关闭窗口后对通讯录进行的各项操作都不会保存,那么要怎么样才能让我们设计的通讯录在每次开始之前都读取之前的信息,在结束后都保存通讯录的信息呢?

在之前文件操作章节中讲解了如何将程序数据输出到文件中,将文件数据输入到程序当中,所以在通讯录中我们就可以用到文件操作的相关函数来实现通讯录数据的保存与读取。

 

4.1读取历史数据

要读取历史数据就要在通讯录每次初始化之后就输入文件的信息到所创建的通讯录中,也就是将输入到数组当中。

在此先在我们创建的程序的文件夹中创建一个con.txt文本,再使用fopen以读的方式打开文件,再创建一个PersonIfon ifon的变量,之后在使用到fread以二进制的形式输入文件的信息到创建的ifon中,再将ifon尾插到数组当中。

void ContactRead(contact* con)//从文件中读取历史数据
{
	FILE* pf = fopen("con.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return;
	}
	PersonIfon ifon;
	while (fread(&ifon, sizeof(PersonIfon), 1, pf))
	{
		SLPushBack(con, ifon);
	}
	printf("成功读取历史数据到通讯录中\n");
}

 

在通讯录初始化函数中调用SLInit函数后调用COntactRead就可以实现历史数据的读取

void ContactInit(contact* con)//通讯录初始化
{
	SLInit(con);
	ContactRead(con);
}

 

4.2 保存数据

要实现通讯录每次在退出程序后都能将数据保留,这就需要在每次销毁通讯录前将通讯录内的数据,也就是数组的所有元素都输出到con.txt文件内。

要把数组的所有元素都输出到con.txt文件内就需要先以写的方式打开文件,后在循环的使用fwrite将数组的数据以二进制的形式输出到文件当中

void ContactWrite(contact* con)//将通讯录数据读入文件中
{
	FILE* pf = fopen("con.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen\n");
		return;
	}
	
	for (int i = 0; i < con->size; i++)
	{
		fwrite(con->arr+i, sizeof(PersonIfon), 1, pf);

	}
	printf("通讯录数据保存成功\n");
}

 

在通讯录销毁函数中调用SLDestory函数前调用COntactWrite就可以实现数据输出到文件当中,也就将数据保留了下来

void ContactDestory(contact* con)//销毁通讯录
{
	ContactWrite(con);
	SLDestory(con);
}

 


通讯录完整代码 
 

注:在Seqlist.h和Seqlist.c内的查找和打印顺序表与以上代码不兼容,运行时会使得程序崩溃,所以将这些部分注释掉 

contact.h 

#pragma once
#define MAX_NAME 20
#define MAX_GENDER 10
#define MAX_TELE 20
#define MAX_ADRESS 50


typedef struct PersonIfon//联系人信息
{
	char name[MAX_NAME];//姓名
	char Gender[MAX_GENDER];//性别
	int age;//年龄
	char Tele[MAX_TELE];//电话
	char Adress[MAX_ADRESS];//地址

}PersonIfon;

struct Seqlist;
typedef struct Seqlist contact;
 
void ContactInit(contact* con);//初始化通讯录
void ContactDestory(contact* con);//销毁通讯录
void ContactAdd(contact* con);//通讯录内添加联系人
void ContactDel(contact* con);//通讯录内删除联系人
void ContactModify(contact* con);//通讯录内修改联系人
void ContactFind(contact* con);//在通讯录内查找联系人
void ContactShow(contact* con);//展示通讯录

void ContactRead(contact* con);//从文件中读取历史数据
void ContactWrite(contact* con);//将通讯录数据读入文件中

 

Seqlist.h

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>

typedef struct PersonIfon SLDataType;
typedef struct Seqlist
{
	SLDataType* arr;
	int size;//有效的数据个数
	int capacity;//空间大小

}SL;//将struct Seqlist重命名为SL

void SLInit(SL* ps);//初始化
void SLDestory(SL* ps);//销毁

void SLCheckCapacity(SL* ps);//检查空间是否足够
//void SLPrint(SL ps);//打印顺序表


void SLPushBack(SL* ps, SLDataType x);//尾插
void SLPushPront(SL* ps, SLDataType x);//头插


void SLPopBack(SL* ps);//尾删
void SLPopPront(SL* ps);//头删

void SLInsert(SL* ps, int pos, SLDataType x);//任意位置插入
void SLErase(SL* ps, int pos);//任意位置删除

//int SLFind(SL* ps, SLDataType x);//查找

 

 

Seqlist.c 

#include"SeqList.h"


void SLInit(SL* ps)//顺序表初始化
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

void SLDestory(SL* ps)//顺序表销毁
{
	if (ps->arr)
	{
		free(ps->arr);

	}
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}



void SLCheckCapacity(SL* ps)//检查空间是否足够,不足时增大空间大小
{
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity = newcapacity;

	}
}

//void SLPrint(SL ps)//打印
//{
//	int i = 0;
//	for (i; i < ps.size; i++)
//	{
//		printf("%d ", ps.arr[i]);
//	}
//	printf("\n");
//}


void SLPushBack(SL* ps, SLDataType x)//尾插
{
	assert(ps);
	SLCheckCapacity(ps);

	ps->arr[ps->size++] = x;
}

void SLPushPront(SL* ps, SLDataType x)//头插
{
	assert(ps);
	SLCheckCapacity(ps);
	for (int i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];   //pa->arr[1]=pa->arr[0]
	}
	ps->arr[0] = x;
	ps->size++;
}


void SLPopBack(SL* ps)//尾删
{
	assert(ps);
	assert(ps->size);
	ps->size--;
}

void SLPopPront(SL* ps)//头删
{
	assert(ps);
	assert(ps->size);
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];

	}
	ps->size--;
}


void SLInsert(SL* ps, int pos, SLDataType x)//任意位置插入
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SLCheckCapacity(ps);
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];//结束条件ps->arr[pos+1] = ps->arr[pos]
	}
	ps->arr[pos] = x;
	ps->size++;

}
 
void SLErase(SL* ps, int pos)//任意位置删除
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	for (int i = pos; i <= ps->size - 2; i++)
	{
		ps->arr[i] = ps->arr[i + 1];//结束条件ps->arr[ps->size-2] = ps->arr[ps->size-1]
	}
	--ps->size;
}


//int SLFind(SL* ps, SLDataType x)//查找
//{
//	assert(ps);
//	for (int i = 0; i < ps->size; i++)
//	{
//		if (ps->arr[i] == x)
//		{
//			return i;
//		}
//	}
//	return -1;
//
//}

 

contact.c 

#pragma once
#include "contact.h"
#include"SeqList.h"



void ContactRead(contact* con)//从文件中读取历史数据
{
	FILE* pf = fopen("con.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return;
	}
	PersonIfon ifon;
	while (fread(&ifon, sizeof(PersonIfon), 1, pf))
	{
		SLPushBack(con, ifon);
	}
	printf("成功读取历史数据到通讯录中\n");
}

void ContactInit(contact* con)//通讯录初始化
{
	SLInit(con);
	ContactRead(con);

}

void ContactWrite(contact* con)//将通讯录数据读入文件中
{
	FILE* pf = fopen("con.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen\n");
		return;
	}
	
	for (int i = 0; i < con->size; i++)
	{
		fwrite(con->arr+i, sizeof(PersonIfon), 1, pf);

	}
	printf("通讯录数据保存成功\n");
}







void ContactDestory(contact* con)//销毁通讯录
{
	ContactWrite(con);
	SLDestory(con);

}

void ContactAdd(contact* con)//在通讯录内添加联系人
{
	PersonIfon ifon;
	printf("请输入联系人姓名:\n");
	scanf("%s", &ifon.name);
	printf("请输入联系人性别:\n");
	scanf("%s", &ifon.Gender);
	printf("请输入联系人年龄:\n");
	scanf("%d", &ifon.age);
	printf("请输入联系人电话:\n");
	scanf("%s", &ifon.Tele);
	printf("请输入联系人地址:\n");
	scanf("%s", &ifon.Adress);

	SLPushBack(con, ifon);

}

int FindbyName(contact* con, char* name)
{
	for (int i = 0; i < con->size; i++)
	{
		if (strcmp(con->arr[i].name, name)==0)
		{
			return i;
		}
	}
	return -1;
}



void ContactDel(contact* con)//通讯录内删除联系人
{
	char name[MAX_NAME];
	printf("请输入要删除的联系人的姓名\n");
	scanf("%s", name);
	int tmp = FindbyName(con, name);
	if (tmp < 0)
	{
		printf("该联系人不存在,删除失败\n");
		return;
	}
	SLErase(con, tmp);
	printf("删除成功\n");


}

void ContactModify(contact* con)//修改联系人信息
{
	char name[MAX_NAME];
	printf("请输入要修改的联系人的姓名\n");
	scanf("%s", name);
	int tmp = FindbyName(con, name);
	if (tmp < 0)
	{
		printf("该联系人不存在,修改失败\n");
		return;
	}
	
	printf("请输入新的联系人姓名:\n");
	scanf("%s", con->arr[tmp].name);
	printf("请输入新的联系人性别:\n");
	scanf("%s", con->arr[tmp].Gender);
	printf("请输入新的联系人年龄:\n");
	scanf("%d", &con->arr[tmp].age);
	printf("请输入新的联系人电话:\n");
	scanf("%s", con->arr[tmp].Tele);
	printf("请输入新的联系人地址:\n");
	scanf("%s", con->arr[tmp].Adress);


	
	printf("修改成功!\n");

}



void ContactFind(contact* con)//查找联系人
{
	char name[MAX_NAME];
	printf("请输入要查找的联系人的姓名\n");
	scanf("%s", name);
	int flag = -1;
	for (int i = 0; i < con->size; i++)
	{
		if (strcmp(con->arr[i].name, name) == 0)
		{
			flag = 1;
			printf("查找成功!\n");
			printf("%-10s %-4s %-4s %15s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
			
			printf("%-10s %-4s %-4d %15s %-20s\n",
				con->arr[i].name,
				con->arr[i].Gender,
				con->arr[i].age,
				con->arr[i].Tele,
				con->arr[i].Adress);
			
		}

	}
	if (flag == -1)
	{
		printf("你所要查找的联系人不存在!\n");
	}


}

void ContactShow(contact* con)//展示通讯录
{

	printf("%-10s %-4s %-4s %15s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
	for (int i = 0; i < con->size; i++)
	{
		printf("%-10s %-4s %-4d %15s %-20s\n",
			con->arr[i].name,
			con->arr[i].Gender,
			con->arr[i].age,
			con->arr[i].Tele,
			con->arr[i].Adress);
	}
}

 

 test.c

#include"SeqList.h"
#include"contact.h"


void menu()
{
	printf("**************************************\n");
	printf("******1.添加联系人  2.删除联系人******\n");
	printf("******3.查找联系人  4.修改联系人******\n");
	printf("******5.展示通讯录  0.退出程序  ******\n");
	printf("**************************************\n");

}

enum option
{
	 ADD=1,
     DEL=2,
	 FIND=3,
     MODIFY=4,
     SHOW=5

};



int main()
{
	int input = 0;
	contact con;
	ContactInit(&con);
	do
	{
		menu();
		printf("请选择操作\n");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			 ContactAdd(&con);
			break;
		case DEL:
			ContactDel(&con);
			break;
		case FIND:
			ContactFind(&con);
			break;
		case MODIFY:
			ContactModify(&con);
			break;
		case SHOW:
			ContactShow(&con);
			break;
		default:
			printf("选择操作错误,请输入1~5内的数\n");
			break;

		}




	} while(input);
	ContactDestory(&con);


	return 0;
}

通讯录实现效果 
 

基于顺序表实现通讯录

 

以上就是本篇的所有内容了,希望能得到你的点赞与收藏,感谢支持!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/759158.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【SpringBoot】SpringBoot使用mail实现登录邮箱验证

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 目录 一、前期准备 1 开启邮箱服务 2 SpringBoot导入依赖 3 创建application.yml配置文件 4 创建数据库文件 5 配置redis服务 二、验证邮件发送功能 三、注册功能实现邮箱验证 1 创建User实体类 2 创建UserPa…

java spring 拦截器和过滤器+过滤器处理数据

java spring 拦截器和过滤器过滤器处理数据 介绍Spring拦截器&#xff08;Interceptor&#xff09;导入依赖完整代码 Java过滤器&#xff08;Filter&#xff09;完整代码分为 2 个文件&#xff0c;请看下面BodyReaderHttpServletRequestWrapper.javaMyFilter.java Spring过滤器…

初识HTML

HTML语法规范 1、HTML标签是由尖括号包围的关键字&#xff0c;例如<html>。 2、HTML标签通常成对出现&#xff0c;例如<html></html>&#xff0c;此为双标签&#xff0c;标签对的第一个标签是开始标签&#xff0c;第二个标签是结束标签。 3、有些特殊标签…

揭秘多年免费听音乐、直播、影视的自用方案:手机、电视、电脑多平台0成本实现媒体自由(内含相关资源)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 多媒体自由 📒🎧 音乐资源📱安卓平台🍎 苹果平台💻 PC平台🎥 影视资源📱 安卓平台🍎 苹果平台📺 电视盒子💻 PC平台📥 电影下载📺 直播资源📱 手机平台💻 PC平台📺 电视盒子⚓️ 相关链接 ⚓️�…

【Python实战因果推断】9_元学习器4

目录 Double/Debiased Machine Learning Double/Debiased Machine Learning Double/Debiased ML 或 R-learner 可以看作是 FrischWaugh-Lovell 定理的改进版。其思路非常简单--在构建结果和治疗残差时使用 ML 模型 结果和干预残差&#xff1a; , 预估&#xff0c;预估 由于 …

Golang-slice理解

slice golang-slice语雀笔记整理 slicego为何设计slice&#xff1f;引用传递实现扩容机制 go为何设计slice&#xff1f; 切片对标其他语言的动态数组&#xff0c;底层通过数组实现&#xff0c;可以说是对数组的抽象&#xff0c;底层的内存是连续分配的所以效率高&#xff0c;可…

【操作系统】进程管理——进程控制和进程通信(个人笔记)

学习日期&#xff1a;2024.6.30 内容摘要&#xff1a;进程控制的概念&#xff0c;进程控制相关的“原语”&#xff0c;进程通信 进程控制 原语 进程控制用“原语”实现。原语是一种特殊的程序&#xff0c;它的执行具有原子性&#xff0c;也就是说&#xff0c;这段程序的执行…

计算机网络原理及应用

第一章 计算机网络概述 【1】局域网 局域网是指在某一区域内由多台计算机互联而成的计算机通信网络。 【1】互通 两个网络之间可以交换数据。 第二章 计算机网络的体系结构 【1】语义 何时发出何种控制信息&#xff0c;完成何种动作以及做出何种响应。 【2】简述网络协…

【Linux】性能分析器 perf 详解(一):简介、安装、stat命令演示

1、简介 perf 是由 Linux 官方提供的系统性能分析工具 。它包含两部分: perf_events ,Linux 内核中的一个子系统perf 命令,用户空间的应用程序内核子系统 perf_events 提供了性能计数器(hardware performance counters)和性能事件的支持,它以事件驱动型的方式工作,通过…

DarkGPT:基于GPT-4-200k设计的人工智能OSINT助手

关于DarkGPT DarkGPT是一款功能强大的人工智能安全助手&#xff0c;该工具基于GPT-4-200k设计并实现其功能&#xff0c;可以帮助广大研究人员针对泄露数据库进行安全分析和数据查询相关的OSINT操作。 工具要求 openai1.13.3 requests python-dotenv pydantic1.10.12 工具安装 …

【机器学习】在【Pycharm】中的应用:【线性回归模型】进行【房价预测】

专栏&#xff1a;机器学习笔记 pycharm专业版免费激活教程见资源&#xff0c;私信我给你发 python相关库的安装&#xff1a;pandas,numpy,matplotlib&#xff0c;statsmodels 1. 引言 线性回归&#xff08;Linear Regression&#xff09;是一种常见的统计方法和机器学习算法&a…

miniconda 弹出黑窗

etc\conda\activate.d 和 envs 中不同环境中的 etc\conda\activated.d&#xff0c;只保留下图中的三个文件即可。

Facebook的投流技巧有哪些?

相信大家都知道Facebook拥有着巨大的用户群体和高转化率&#xff0c;在国外社交推广中的影响不言而喻。但随着Facebook广告的竞争越来越激烈&#xff0c;在Facebook广告上获得高投资回报率也变得越来越困难。IPIDEA代理IP今天就教大家如何在Facebook上投放广告的技巧&#xff0…

p2p、分布式,区块链笔记:试用ZeroTier组网

ZeroTier 是一种用于创建和管理虚拟局域网&#xff08;Virtual Local Area Network&#xff0c;VLAN&#xff09;的软件定义网络&#xff08;SDN&#xff09;解决方案。它可以通过互联网将多个设备安全地连接在一起&#xff0c;就像它们在同一个本地网络上一样。主要开发语言为…

zfile文件共享系统使用

1.简介 zfile是一款基于java开源的文件共享软件&#xff0c;有两种部署&#xff08;jar包和war包&#xff09;,非常适合广大的Java开发人员使用&#xff08;当然其他人员也可使用&#xff09;&#xff0c;或者你也可以称它为网盘&#xff0c;可以在Windows、MacOS、Linux上部署…

【操作系统期末速成】 EP01 | 学习笔记(基于五道口一只鸭)

文章目录 一、前言&#x1f680;&#x1f680;&#x1f680;二、正文&#xff1a;☀️☀️☀️1.1 考点一&#xff1a;操作系统的概率及特征 三、总结&#xff1a;&#x1f353;&#x1f353;&#x1f353; 一、前言&#x1f680;&#x1f680;&#x1f680; ☀️ 回报不在行动…

javaSE知识点整理总结(下)、MySQL数据库

目录 一、异常 1.常见异常类型 2.异常体系结构 3.异常处理 &#xff08;1&#xff09;finally &#xff08;2&#xff09;throws 二、JDBC 1.JDBC搭建 2.执行SQL语句两种方法 三、MySQL数据库 1.ddl 2.dml 3.dql &#xff08;1&#xff09;字符函数 &#xff08;…

Unidbg调用-补环境V3-Hook

结合IDA和unidbg,可以在so的执行过程进行Hook,这样可以让我们了解并分析具体的执行步骤。 应用场景:基于unidbg调试执行步骤 或 还原算法(以Hookzz为例)。 1.大姨妈 1.1 0x1DA0 public void hook1() {

Unity之自定义Text组件默认属性值

内容将会持续更新&#xff0c;有错误的地方欢迎指正&#xff0c;谢谢! Unity之自定义Text组件默认属性值 TechX 坚持将创新的科技带给世界&#xff01; 拥有更好的学习体验 —— 不断努力&#xff0c;不断进步&#xff0c;不断探索 TechX —— 心探索、心进取&#xff01;…

48 - 按日期分组销售产品(高频 SQL 50 题基础版)

48 - 按日期分组销售产品 -- group_concat 分组拼接selectsell_date,count(distinct product) num_sold,group_concat(distinct product order by product separator ,) products fromActivities group bysell_date;