【C语言期末项目-通讯录】-终级版本-可动态申请内存、可存储数据到文件(手把手详细过程,期末评分A+的项目,答辩辅助神博文,建议三连点赞收藏)

news2024/11/25 2:55:39

目录

​编辑

前言:

 1.项目功能需求分析 

2.文件框架说明 

3.程序主框架实现 

4.创建联系人结构体类型和通讯录结构体类型 

4.1创建通讯录 

5.程序功能实现--封装功能函数实现不同功能 

5.1通讯录初始化

 5.2增加联系人 

 5.3显示所有联系人的信息

5.4删除指定联系人的信息 

5.5查找指定联系人 

 5.6修改联系人的信息

 6.释放通讯录

7.保存通讯录信息

8.源码及结语


前言:

对于这个项目,是前面数组基础版本的通讯录的升级版本,大家如果一步理解有困难,一定先点击我的主页了解一下前几篇博客的内容做一个铺垫,我这里罗列一下关联最大的几篇:

①动态内存详解

②通讯录基础数组版本

③C语言结构体详解

C语言文件详解

 1.项目功能需求分析 

实现一个通讯录:
通讯录保存个人信息

 名字,年龄 性别 电话 住址    用保存人的信息的结构体实现

1.通讯录空间不固定,可以先存放一部分的信息,当用户还要存入信息的时候可以自动增加容量。

(比如默认先存放3个联系人的信息,不够了,就每次增加两个联系人信息的空间给用户)
 2.添加联系人
3.删除指定联系人
4.查找指定联系人
5.显示所有人的信息
6.排序功能

7.可以修改指定联系人的信息

8.退出程序后,录入的信息可以保存在硬盘文件中,下次打开通讯录程序还可以查询到。

2.文件框架说明 

test.c 主菜单文件,用于功能测试

contact.c 函数具体实现文件

contact.h 存放函数和类型的声明和必要头文件

3.程序主框架实现 

我们希望在程序中实现不同的操作,比如上述的增删查改联系人的信息,而不是执行一次程序就结束,用户可以选择退出。接下来我们就实现一下主体框架,包含主页面菜单显示。

void menu()
{
	printf("----------------------------------\n");
	printf("|***0.Exit       1.ADD***********|\n");
	printf("|***2.DEL       3.SEARCH*********|\n");
	printf("|***4.MODIFY    5.SHOW***********|\n");
	printf("|***6.SORT       ****************|\n");
	printf("----------------------------------\n");
	 
}
void test()
{
	int  input = 0;
	
	
	do
	{
		menu();
		printf("请选择:》");
		scanf("%d", &input);
		switch (input)
		{
			
		case 1:
			
			break;
		case 2:
			break;
		case 3:
			break;
		case 4:
			break;
		case 5:
			break;
		case 6:
			break;
		case 0:
			printf("退出程序成功\n");
			break;
		default:
			printf("选择错误,请根据菜单选项进行功能选择,谢谢配合\n");
			break;


		}
	} while (input);
}

int main()
{
	test();
	return 0;
}

case后面的选项是1,2,3,4,5,那么我们想可不可以利用枚举,让case后面的选项既能表示我们的功能含义又能表示功能选择数字,这样的代码可读性就会更高一些,我们就可以修改如下 :

首先定义选择枚举类型:

enum OPtion
{
	EXIT,//0
	ADD,//1
	DEL,//2
	SEARCH,
	MODIFY,
	SHOW,
	SORT

};

这个依然是放在我们的头文件中去定义,这样代码的整体美观些,接下来的结构修改为:

void menu()
{
	printf("----------------------------------\n");
	printf("|***0.Exit       1.ADD***********|\n");
	printf("|***2.DEL       3.SEARCH*********|\n");
	printf("|***4.MODIFY    5.SHOW***********|\n");
	printf("|***6.SORT       ****************|\n");
	printf("----------------------------------\n");
	 
}
void test()
{
	int  input = 0;
	Contact con;
	InitContact(&con);
	
	do
	{
		menu();
		printf("请选择:》");
		scanf("%d", &input);
		switch (input)
		{
			
		case ADD:
			
			break;
		case DEL:
			break;
		case SEARCH:
			break;
		case MODIFY:
			break;
		case SHOW:
			break;
		case SORT:
			break;
		case EXIT:
			printf("退出程序成功\n");
			break;
		default:
			printf("选择错误,请根据菜单选项进行功能选择,谢谢配合\n");
			break;


		}
	} while (input);
}

int main()
{
	test();
	return 0;
}

4.创建联系人结构体类型和通讯录结构体类型 

由于通讯录存储的是每一个联系人的基本信息,名字、电话、性别、住址等,所以我们可以封装一个联系人结构体类型用于描述每一个联系人。

typedef struct PeoInfo
{
	char name[20];
	int age;
	char sex[5];
	char telepnumber[12];
	char addr[30];

} PeoInfo;

为了后续书写的方便将struct PeoInfo类型重定义为PeoInfo

我们现在需要一块空间来存储我们联系人的信息,这块空间的起始地址交给我们的一个联系人结构体类型的指针。

PeoInfo* data;//指向了存放数据的空间

由于,我们后续会对通讯录进行增删操作,就会改变数组的大小,为了方便查看或者显示或者为了方便操作我们可以定义一个SZ来记录数组的大小,增加一个联系人,sz+1.......

int sz;//记录的是当前有效元素的个数

这,当我们起始有三个联系人类型那么大的空间的时候,还没有存入联系人的信息,此时我们的sz=0,那么我们什么时候开始扩大我们的空间呢,所以我们专门设计一个变量来记录我们通讯录的数据空间容量,起始容量为3,当sz 等于我们的容量的时候,就可以扩容了。

int  capacity;//记录当前存放数据空间的容量

数据区,容量和联系人数目都是通讯录的属性,我们可以设计一下通讯录类型结构体:

typedef struct Contact
{
	PeoInfo* data;//指向了存放数据的空间
	int sz;//记录的是当前有效元素的个数
	int  capacity;//记录当前存放数据空间的容量

	
}Contact;

为了以后书写方便,用typedef重定义通讯录结构体类型为:Contact类型。

4.1创建通讯录 

当我们的通讯录类型有了过后,我们就可以创建一个通讯录:

5.程序功能实现--封装功能函数实现不同功能 

5.1通讯录初始化

初始化函数,首先要为我们的data数据区申请3个PeoINfo类型的空间,将sz也初始化为0.将容量初始化3,起始的容量不一定设置为3,方便不同的伙伴来设置,我们将容量的大小也设置为宏.我们传参使用了结构体地址传参,接收参数使用了结构体指针,内存占用少。

void Initcontact(Contact* pc)
{
	assert(pc);
		pc->data = (PeoInfo*)malloc(CAPICITY * sizeof(PeoInfo));
		if (pc->data == NULL)
		{
			perror("Initcontact");
		}
	pc->sz = 0;
	pc->capacity = CAPICITY;
}

②由于我们的数据后续是要存储到我们的文件中的,那么就意味着当我们启动程序的时候是不是应该先把文件中的数据加载到程序中来,所以我们还需要实现一个加载函数,将文件中的数据读到我们的程序中来。

int ChekCapacity(Contact* pc);//提前声明我们的检查增容函数
void LoadContact(Contact* pc)
{
	//首先用二进制读的方式打开文件
	FILE* pf = fopen("contact.dat", "rb");
	if (pf == NULL)
	{
		//打开失败就不继续了
		perror("loadcontact");
		return;
	}
	//读文件
	PeoInfo tmp = { 0 };//创建一个联系人结构体来存储读到的信息
	while (fread(&tmp, sizeof(PeoInfo), 1, pf))//fred返回的是读到的个数,读完返回0
	{
		if (0 == ChekCapacity(pc))//这里因为要把读到的信息放到通讯录中,就要考虑增容
			return;//增容失败就不往下执行了
		//增容成功,将数据加载到通讯录
		pc->data[pc->sz] = tmp;
		pc->sz++;//加载一个联系人信息,sz++

	}
	//关闭文件
	fclose(pf);
	pf = NULL;

}
void Initcontact(Contact* pc)

放到最后将通讯录信息保存写完后一起测试。

 5.2增加联系人 

在动态版本中,我们不用考虑通讯录满没满。而是应该考虑通讯录申请的空间是否够了,不够就要扩容,每录入一个联系的信息,sz就+1,当我们的sz与我们的容量相等的时候,就要考虑扩容,所以我们进入增加函数第一步就应该先判断是否要增容。

为了代码方便,我们将检查是否要增容这一步封装为一个函数:

int ChekCapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
	PeoInfo* ptr =(PeoInfo * )realloc(pc->data, (pc->capacity + 2 * sizeof(PeoInfo)));
	if (ptr == NULL)
	{
		perror("ChekCapaticy");
		return  0;

	}
	else
	{
		pc->data = ptr;
		pc->capacity += 2;
	}
	
	}
	return 1;
}

函数返回1,说明增容成功,函数返回0说明增容失败。当然,也不一定每次只增加两个空间,我们还是将增加的空间数目定义为宏,方便伙伴们修改:

#define ADDC 2
void Initcontact(Contact* pc)
{
	assert(pc);
		pc->data = (PeoInfo*)malloc(CAPICITY * sizeof(PeoInfo));
		if (pc->data == NULL)
		{
			perror("Initcontact");
		}
	pc->sz = 0;
	pc->capacity = CAPICITY;
}
int ChekCapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
	PeoInfo* ptr =(PeoInfo * )realloc(pc->data, (pc->capacity + ADDC * sizeof(PeoInfo)));
	if (ptr == NULL)
	{
		perror("ChekCapaticy");
		return  0;

	}
	else
	{
		pc->data = ptr;
		pc->capacity += ADDC;
         printf("增容成功\n");
return1;
	}
	
	}
	return 1;
}

我们的增加联系人的函数为:

void AddContact(Contact* pc)
{
	assert(pc);//断言防止传入空指针
	//首先判断通讯录满每满
	if (0 == ChekCapacity(pc))
	{
		return;
	}
	printf("请输入联系人的名字>\n");
	scanf("%s", pc->data[pc->sz].name);//由于name是数组名这里就不要&符号了
	printf("请输入联系人的年龄>\n");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入联系人的性别>\n");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入联系人的电话>\n");
	scanf("%s", pc->data[pc->sz].telepnumber);
	printf("请输入联系人的地址>\n");
	scanf("%s", pc->data[pc->sz].addr); 

		//添加联系人成功,我们sz++
		pc->sz++;
	printf("添加联系人成功\n");

}

测试一下:

先往通讯录里面放入三个联系人信息:

下一步增容:

增容成功,我们展现一下通讯录然后我们查找一下2号联系人:

功能正常。

 5.3显示所有联系人的信息

为了看一下我们添加联系人或者删除联系人的效果,我们这里就先写显示函数

用于我们只是显示通讯录信息,并不将参数内容进行修改所以参数最好使用const进行修饰,防止出错,这一步不理解的伙伴可以点击我的主页看一下我讲解const的博文。

这个函数我们只用循环打印我们data数组内容就行

void ShowContact(const Contact* pc)
{
	assert(pc);//断言一下防止传入空指针
	int i = 0;
	printf("————————————————————————————————————————————————————————————————————————————————————————\n");
	printf("|%-20s\t|%-4s\t|%-5s\t|%-12s\t|%-30s|\n", "名字", "年龄", "性别", "电话", "地址");
		for (i = 0; i < pc->sz; i++)
		{
			printf("|%-20s\t|%-4d\t|%-5s\t|%-12s\t|%-30s|\n", 
				pc->data[i].name,
				pc->data[i].age,
				pc->data[i].sex,
				pc->data[i].telepnumber,
				pc->data[i].addr);
			printf("————————————————————————————————————————————————————————————————————————————————————————\n");
		}
		printf("————————————————————————————————————————————————————————————————————————————————————————\n");

我们来看一下前两个函数执行的效果:

5.4删除指定联系人的信息 

首先,如果通讯录为空,我们就没有删除的东西

第二,要删除对应联系人的信息,实现思想是先找到对应联系人的名字匹配相同将后面的内容前移覆盖完成删除。

void DelCotact(Contact* pc)
{
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	char name[DATAMAX] = { 0 };
	assert(pc);//断言,防止传入空指针
	printf("请输入要删除的人的名字:》\n");
	scanf("%s", name);
	//遍历找到要删除的人
	int i = 0;
	int del = 0;
	int flag = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			del = i;
			flag = 1;
			break;
		}
		
	}
	if (flag == 0)
	{
		printf("找不到要删除的人,请检查名字是否输入正确\n");
		return;
	}
	//找到了,删除联系人
	for (i = del; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("成功删除联系人\n");
}

由于我们后面修改呀等等都会用到查找这个函数,所以我们将其封装为一个查找函数,那我们就可以改造代码如下:

int Findbyname(Contact* pc, char name[])
{
	assert(pc);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;//找到了
		}

	}
	return -1;//找不到
}
void DelCotact(Contact* pc)
{
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	char name[DATAMAX] = { 0 };
	assert(pc);//断言,防止传入空指针
	printf("请输入要删除的人的名字:》\n");
	scanf("%s", name);
	//遍历找到要删除的人
	int i = 0;
	int del = 0;
	del = Findbyname(pc, name);
	if (del == -1)
	{
		printf("找不到要删除的人,请检查名字是否输入正确\n");
		return;
	}
	//找到了,删除联系人
	for (i = del; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("成功删除联系人\n");
}

我们来看一下效果:

5.5查找指定联系人 

这里我们就实现一下通过名字查找,之所以单独写一个查找函数是因为在功能中,查找到过后还要显示出来。

看实现:

void SearchContact(Contact* pc)
{
	assert(pc);
	char name[DATAMAX] = { 0 };
	printf("请输入要查找的人的名字:》\n");
	scanf("%s", name);
	int pos = Findbyname(pc, name);
	if (pos == -1)
	{
		printf("要查找的人不存在,请检查名字是否输入正确\n");

	}
	else
	{
		printf("————————————————————————————————————————————————————————————————————————————————————————\n");
		printf("|%-20s\t|%-4s\t|%-5s\t|%-12s\t|%-30s|\n", "名字", "年龄", "性别", "电话", "地址");
		printf("————————————————————————————————————————————————————————————————————————————————————————\n");
		printf("|%-20s\t|%-4d\t|%-5s\t|%-12s\t|%-30s|\n",
			pc->data[pos].name,
			pc->data[pos].age,
			pc->data[pos].sex,
			pc->data[pos].telepnumber,
			pc->data[pos].addr);
		printf("————————————————————————————————————————————————————————————————————————————————————————\n");

	}
}

这里查找也可以根据其他的比如号码等,可以利用Switch来实现。看一下效果:

 5.6修改联系人的信息

通过名字来找到要修改信息的联系人,然后重新录入信息

void 	ModifyContact(Contact* pc)
{
	assert(pc);
	char name[DATAMAX] = { 0 };
	printf("请输入要修改人的名字:>\n");
	scanf("%s", name);
	int pos = Findbyname(pc, name);
	if (pos == -1)
	{
		printf("要修改的人不存在,请检查名字是否输入正确\n");

	}
	else
	{
		printf("请输入要修改人的名字>\n");
		scanf("%s", pc->data[pos].name);//由于name是数组名这里就不要&符号了
		printf("请输入要修改人的年龄>\n");
		scanf("%d", &(pc->data[pos].age));
		printf("请输入要修改人的性别>\n");
		scanf("%s", pc->data[pos].sex);
		printf("请输入要修改人的电话>\n");
		scanf("%s", pc->data[pos].telepnumber);
		printf("请输入要修改人的地址>\n");
		scanf("%s", pc->data[pos].addr); \

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

	}
}

我们看一下效果:

 6.释放通讯录

由于我们的通讯录空间是malloc来的,所以在最后程序结束应该将空间释放,防止造成内存泄漏。

那我们就在退出选项后面增加一个销毁函数:

void DestoryContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
}

7.保存通讯录信息

在销毁通讯录前,通过文件读写的方式保存通讯录的信息

void Savecontact(Contact* pc)
{
	FILE* pf = fopen("contact.dat", "wb");
	if (pf == NULL)
	{
		perror("SaveContact");
		return;
	}
	//写数据
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

看一下效果:

由于是二进制存储我们使用编译器来查看:

成功写入,我们搭配加载看一下是不是我们上一次添加的信息:

当通讯录再次启动就有我们上次写入的信息了。

8.源码及结语

这是一个综合C语言百分之五六十的知识的一个项目,大家可以配合我之前的文章进行理解,希望这篇文章对大家的期末有所帮助。下面附上源码,创作不易,如果可以大家可以点赞三连收藏,对于项目有问题欢迎一起交流。谢谢大家的关注。

contact.h

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


#define DATAMAX 100
#define CAPICITY 3
#define ADDC 2


enum OPtion
{
	EXIT,//0
	ADD,//1
	DEL,//2
	SEARCH,
	MODIFY,
	SHOW,
	SORT

};

//类型的声明
typedef struct PeoInfo
{
	char name[20];
	int age;
	char sex[5];
	char telepnumber[12];
	char addr[30];

} PeoInfo;


//typedef struct Contact
//{
//	PeoInfo data[DATAMAX];
//	int sz;
//}Contact;
typedef struct Contact
{
	PeoInfo* data;//指向了存放数据的空间
	int sz;//记录的是当前有效元素的个数
	int  capacity;//记录当前存放数据空间的容量


}Contact;

//初始化函数
void Initcontact(Contact* pc);//函数声明
void AddContact(Contact* pc);//增加联系人函数
void ShowContact(const Contact* pc);//显示通讯录信息
void DelCotact(Contact* pc);//删除联系人信息
void SearchContact(Contact* pc);//查找联系人的信息
void 	ModifyContact(Contact* pc);//修改联系人的信息
void DestoryContact(Contact* pc);//销毁通讯录
void Savecontact(Contact* pc);//保存通讯录到文件

test.c

#include"contact.h"

//通讯录空间不固定,大小1可以调整
// 默认放3个人的信息,不够,每次增加两个


void menu()
{
	printf("----------------------------------\n");
	printf("|***0.Exit       1.ADD***********|\n");
	printf("|***2.DEL       3.SEARCH*********|\n");
	printf("|***4.MODIFY    5.SHOW***********|\n");
	printf("|***6.SORT       ****************|\n");
	printf("----------------------------------\n");

}
void test()
{
	int  input = 0;
	Contact con;
	Initcontact(&con);

	do
	{
		menu();
		printf("请选择:》");
		scanf("%d", &input);
		switch (input)
		{

		case ADD:
			AddContact(&con);

			break;
		case DEL:
			DelCotact(&con);
			break;
		case SEARCH:
			SearchContact(&con);
			break;
		case MODIFY:
			ModifyContact(&con);
			break;
		case SHOW:
			ShowContact(&con);
			break;
		case SORT:

			break;
		case EXIT:
			Savecontact(&con);
			DestoryContact(&con);
			printf("退出程序成功\n");
			break;
		default:
			printf("选择错误,请根据菜单选项进行功能选择,谢谢配合\n");
			break;


		}
	} while (input);
}

int main()
{
	test();
	return 0;
}

contact.c

#include"contact.h"
int Findbyname(Contact* pc, char name[])
{
	assert(pc);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;//找到了
		}

	}
	return -1;//找不到
}
int ChekCapacity(Contact* pc);//提前声明我们的检查增容函数
void LoadContact(Contact* pc)
{
	//首先用二进制读的方式打开文件
	FILE* pf = fopen("contact.dat", "rb");
	if (pf == NULL)
	{
		//打开失败就不继续了
		perror("loadcontact");
		return;
	}
	//读文件
	PeoInfo tmp = { 0 };//创建一个联系人结构体来存储读到的信息
	while (fread(&tmp, sizeof(PeoInfo), 1, pf))//fred返回的是读到的个数,读完返回0
	{
		if (0 == ChekCapacity(pc))//这里因为要把读到的信息放到通讯录中,就要考虑增容
			return;//增容失败就不往下执行了
		//增容成功,将数据加载到通讯录
		pc->data[pc->sz] = tmp;
		pc->sz++;//加载一个联系人信息,sz++

	}
	//关闭文件
	fclose(pf);
	pf = NULL;

}
void Initcontact(Contact* pc)
{
	assert(pc);
	pc->data = (PeoInfo*)malloc(CAPICITY * sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("Initcontact");
	}
	pc->sz = 0;
	pc->capacity = CAPICITY;
	LoadContact(pc);
}
int ChekCapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + ADDC * sizeof(PeoInfo)));
		if (ptr == NULL)
		{
			perror("ChekCapaticy");
			return  0;

		}
		else
		{
			pc->data = ptr;
			pc->capacity += ADDC;
			printf("增容成功\n");
			return 1;
		}

	}
	return 1;
}

void AddContact(Contact* pc)
{
	assert(pc);//断言防止传入空指针
	//首先判断通讯录满每满
	if (0 == ChekCapacity(pc))
	{
		return;
	}
	printf("请输入联系人的名字>\n");
	scanf("%s", pc->data[pc->sz].name);//由于name是数组名这里就不要&符号了
	printf("请输入联系人的年龄>\n");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入联系人的性别>\n");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入联系人的电话>\n");
	scanf("%s", pc->data[pc->sz].telepnumber);
	printf("请输入联系人的地址>\n");
	scanf("%s", pc->data[pc->sz].addr);

	//添加联系人成功,我们sz++
	pc->sz++;
	printf("添加联系人成功\n");

}
void ShowContact(const Contact* pc)
{
	assert(pc);//断言一下防止传入空指针
	int i = 0;
	printf("————————————————————————————————————————————————————————————————————————————————————————\n");
	printf("|%-20s\t|%-4s\t|%-5s\t|%-12s\t|%-30s|\n", "名字", "年龄", "性别", "电话", "地址");
	printf("————————————————————————————————————————————————————————————————————————————————————————\n");
	for (i = 0; i < pc->sz; i++)
	{
		printf("|%-20s\t|%-4d\t|%-5s\t|%-12s\t|%-30s|\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].telepnumber,
			pc->data[i].addr);
		printf("————————————————————————————————————————————————————————————————————————————————————————\n");
	}
	printf("————————————————————————————————————————————————————————————————————————————————————————\n");

}

void DelCotact(Contact* pc)
{
	if (pc->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	char name[DATAMAX] = { 0 };
	assert(pc);//断言,防止传入空指针
	printf("请输入要删除的人的名字:》\n");
	scanf("%s", name);
	//遍历找到要删除的人
	int i = 0;
	int del = 0;
	del = Findbyname(pc, name);
	if (del == -1)
	{
		printf("找不到要删除的人,请检查名字是否输入正确\n");
		return;
	}
	//找到了,删除联系人
	for (i = del; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("成功删除联系人\n");
}

void SearchContact(Contact* pc)
{
	assert(pc);
	char name[DATAMAX] = { 0 };
	printf("请输入要查找的人的名字:》\n");
	scanf("%s", name);
	int pos = Findbyname(pc, name);
	if (pos == -1)
	{
		printf("要查找的人不存在,请检查名字是否输入正确\n");

	}
	else
	{
		printf("————————————————————————————————————————————————————————————————————————————————————————\n");
		printf("|%-20s\t|%-4s\t|%-5s\t|%-12s\t|%-30s|\n", "名字", "年龄", "性别", "电话", "地址");
		printf("————————————————————————————————————————————————————————————————————————————————————————\n");
		printf("|%-20s\t|%-4d\t|%-5s\t|%-12s\t|%-30s|\n",
			pc->data[pos].name,
			pc->data[pos].age,
			pc->data[pos].sex,
			pc->data[pos].telepnumber,
			pc->data[pos].addr);
		printf("————————————————————————————————————————————————————————————————————————————————————————\n");

	}
}


void 	ModifyContact(Contact* pc)
{
	assert(pc);
	char name[DATAMAX] = { 0 };
	printf("请输入要修改人的名字:>\n");
	scanf("%s", name);
	int pos = Findbyname(pc, name);
	if (pos == -1)
	{
		printf("要修改的人不存在,请检查名字是否输入正确\n");

	}
	else
	{
		printf("请输入要修改人的名字>\n");
		scanf("%s", pc->data[pos].name);//由于name是数组名这里就不要&符号了
		printf("请输入要修改人的年龄>\n");
		scanf("%d", &(pc->data[pos].age));
		printf("请输入要修改人的性别>\n");
		scanf("%s", pc->data[pos].sex);
		printf("请输入要修改人的电话>\n");
		scanf("%s", pc->data[pos].telepnumber);
		printf("请输入要修改人的地址>\n");
		scanf("%s", pc->data[pos].addr); \


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

	}
}

void DestoryContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
}

void Savecontact(Contact* pc)
{
	FILE* pf = fopen("contact.dat", "wb");
	if (pf == NULL)
	{
		perror("SaveContact");
		return;
	}
	//写数据
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

BBC英式口语~发音练习~笔记整理

参考资料 原视频地址&#xff1a; https://www.bilibili.com/video/BV1D7411n7bS/?spm_id_from333.1245.0.0&vd_source5986fc7c8e6d754f3ca44233573aeaff 笔记图片

root MUSIC 算法补充说明

root MUSIC 算法补充说明 多项式求根root MUSIC 算法原理如何从 2 M − 2 2M-2 2M−2 个根中确定 K K K 个根从复数域上观察 2 M − 2 2M-2 2M−2 个根的分布 这篇笔记是上一篇关于 root MUSIC 笔记的补充。 多项式求根 要理解 root MUSIC 算法&#xff0c;需要理解多项式求…

DSA 经典数据结构与算法 学习心得和知识总结(三) |有向无环图及其应用

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《算法导论》第三版 就是这本被封神的杰作&#xff0c;就是它&#x1f926; 2、参考书籍&#xff1a;《数据结构》严奶奶版 3、参考书…

Java学习笔记------static

static 创建Javabean类 public class student {private int age;private String name;private String gender;public student() {}public student(int age, String name, String gender) {this.age age;this.name name;this.gender gender;}/*** 获取* return age*/public…

论文解读:Masked Generative Distillation

文章汇总 话题 知识蒸馏 创新点 带掩盖的生成式蒸馏 方法旨在通过学生的遮罩特征来生成老师的特征(通过遮盖学生部分的特征来生成老师的特征)&#xff0c;来帮助学生获得更好的表现 输入:老师:&#xff0c;学生:&#xff0c;输入:&#xff0c;标签:&#xff0c;超参数: 1:使…

CTFshow web(文件上传158-161)

web158 知识点&#xff1a; auto_append_file 是 PHP 配置选项之一&#xff0c;在 PHP 脚本执行结束后自动追加执行指定的文件。 当 auto_append_file 配置被设置为一个文件路径时&#xff0c;PHP 将在执行完脚本文件的所有代码后&#xff0c;自动加载并执行指定的文件。 这…

【springboot+vue项目(十四)】基于Oauth2的SSO单点登录(一)整体流程介绍

场景&#xff1a;现在有一个前后端分离的系统&#xff0c;前端框架使用vue-element-template&#xff0c;后端框架使用springbootspringSecurityJWTRedis&#xff08;登录部分&#xff09;现在需要接入到已经存在的第三方基于oauth2.0的非标准接口统一认证系统。 温馨提示&…

【STM32 CubeMX】I2C查询方式

文章目录 前言一、CubeMX配置IIC二、查询方式的使用2.1 分析一种情况2.2 Master模式2.3 Mem模式 总结 前言 在STM32 CubeMX环境中&#xff0c;I2C&#xff08;Inter-Integrated Circuit&#xff09;通信协议的查询方式是一种简单而常见的通信方式。通过查询方式&#xff0c;微…

代码随想录 Leetcode45. 跳跃游戏 II

题目&#xff1a; 代码(首刷看解析 2024年2月15日&#xff09;&#xff1a; class Solution { public:int jump(vector<int>& nums) {if (nums.size() 1) return 0;int res 0;int curDistance 0;int nextDistance 0;for (int i 0; i < nums.size(); i) {nex…

6、内网安全-横向移动WmiSmbCrackMapExecProxyChainsImpacket

用途&#xff1a;个人学习笔记&#xff0c;有所借鉴&#xff0c;欢迎指正&#xff01; 前言&#xff1a; 在内网环境中&#xff0c;主机192.168.3.31有外网网卡能出网&#xff0c;在取得该主机权限后上线&#xff0c;搭建web应用构造后门下载地址&#xff0c;利用该主机执行相…

Windows系统VMware创建多个CentOS7虚拟机 NAT网络配置 ssh连接

主要目标: 1.创建3个虚拟机, centos7系统 2.虚拟机之间互相访问 3.物理机访问各虚拟机, 通过xshell建立ssh连接 4.物理机网络变化时,仍能访问 用途: NoSQL课程使用, 课前环境搭建,个人备忘 基本信息&#xff1a; 物理机&#xff1a; windows 11 操作系统 虚拟机软件&#xff…

前端工程化面试题 | 10.精选前端工程化高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

OpenCV Mat实例详解 三

OpenCV Mat实例详解 一、二介绍了&#xff0c;OpenCV Mat类构造函数及其公共属性。下面继续介绍OpenCV Mat类公有静态成员函数 OpenCV Mat类公有静态成员函数&#xff08;Static Public Member Functions&#xff09; static CV_NODISCARD_STD Mat diag (const Mat &d)&…

CSP-201903-2-二十四点

CSP-201903-2-二十四点 一、中缀表达式转后缀表达式 中缀表达式是一种常见的数学表达式书写方式&#xff0c;其中操作符位于相关的操作数之间&#xff0c;如 A B。而后缀表达式&#xff08;逆波兰表示法&#xff09;则是一种没有括号&#xff0c;操作符跟随操作数之后的表示…

TIM输出比较 P2

D触发器&#xff1f; 一、输出比较 二、PWM 1、简介 2、结构 三、外部设备 1.舵机 2.直流电机 我的理解是xO1 xIN1 & PWMx; xO2 xIN2 & PWMx;引入PWMx可以更方便的控制特定的电路。 四、函数学习 /*****单独设置输出比较极性*****/ void TIM_OC1PolarityConfig(…

CSS篇--transform

CSS篇–transform 使用transform属性实现元素的位移、旋转、缩放等效果 位移 // 语法 transform:translate(水平移动距离&#xff0c;垂直移动距离) translate() 如果只给一个值&#xff0c;表示x轴方法移动距离 单独设置某个方向的移动距离&#xff1a;translateX() transla…

Rust 基本环境安装

rust 基本介绍请看上一篇文章&#xff1a;rust 介绍 rustup 介绍 rustup 是 Rust 语言的安装器和版本管理工具。通过 rustup&#xff0c;可以轻松地安装 Rust 编译器&#xff08;rustc&#xff09;、标准库和文档。它也允许你切换不同的 Rust 版本或目标平台&#xff0c;以及…

Compose 自定义 - 数据转UI的三阶段(组合、布局、绘制)

一、概念 Compose 通过三个阶段把数据转化为UI&#xff1a;组合&#xff08;要显示什么&#xff09;、布局&#xff08;要显示在哪里&#xff09;、绘制&#xff08;如何渲染&#xff09;。 组合阶段 Compisition 界面首次渲染时会将可组合函数转化为一个个布局节点 Layout Nod…

【打工日常】使用docker部署linux-command解析搜索工具

一、linux-command介绍 linux-command工具是一个非盈利性的工具&#xff0c;里面记录了550 个 Linux 命令&#xff0c;内容包含 Linux 命令手册、详解、学习&#xff0c;是值得收藏的 Linux 命令速查手册。内容来自网络和网友的补充。 二、本次实践介绍 1. 本次实践简介 本次…

Flume(二)【Flume 进阶使用】

前言 学数仓的时候发现 flume 落了一点&#xff0c;赶紧补齐。 1、Flume 事务 Source 在往 Channel 发送数据之前会开启一个 Put 事务&#xff1a; doPut&#xff1a;将批量数据写入临时缓冲区 putList&#xff08;当 source 中的数据达到 batchsize 或者 超过特定的时间就会…