【C语言】——通讯录(静态-动态增长-文件储存)

news2024/12/27 13:53:36

 

目录

前言:

一:整体框架

关于通讯录结构体的创建 

二:通讯录的功能实现(静态)

2.1初始化通讯录

2.2增加联系人

2.3打印通讯录

2.4删除联系人

 2.5 查找联系人

2.6修改联系人 

2.7排序联系人

三:通讯录优化——动态内存

 3.1通讯录的创建

3.2初始化通讯录 

3.3增加联系人 

3.4清空通讯录 

 四:通讯录优化——文件版本

4.1退出保存信息到文件

 4.2初始化时加载文件信息

五:整体代码

test.c

 contact.c

contact.h

前言:

在之前的篇章中讲述了【C语言】进阶——结构体,【C语言】进阶——动态内存,【C语言】进阶——文件操作。

在本篇运用以上知识结合来写一个小项目——通讯录

我会逐步从静态版本优化到动态增加以及最终的文件存储版,循循渐进,详解通讯录的实现

实现思路

通讯录类似一个复杂结构体,包含了很多信息,以个人信息的通讯录而言,需要包含个人名字,年龄,电话,性别以及地址;

而它所具有的基本功能:增(Add)删(Del) 改(modify) 查 (Search);以及我们可以对其一些简单的拓展功能;

这些具体分析为:

  1. 打印一个菜单,提供用户选择功能;
  2. 添加联系人信息;
  3. 删除联系人信息;
  4. 查询联系人信息;
  5. 修改联系人信息;
  6. 显示所有联系人信息;
  7. 对所有联系人信息进行排序整理;
  8. 删除所有联系人信息;
  9. 操作完毕可选择退出。

将整个项目分为三部分 :

test.c ——测试代码模块

contact.c——函数的实现

contact.h——类型的定义,函数声明等 

一:整体框架

我们需要映入眼帘的菜单选择和提示,可以选择do...while();和switch语句相结合,来打印出整个框架体系;

另外因为switch语句中case 1,case2...这样的数字不好看,我们可以采用枚举变量来定义;

        枚举的关键字是enum

在括号内部注意每个成员名后面要加逗号,同时别忘了括号外面的分号

枚举内部的成员被依次赋值为0,1,2

我们假如将female赋值为1,secret就被赋值为2,male赋值为0

        枚举的优点:

1.增加代码的可读性和可维护性

2. 和 #define 定义的标识符比较枚举有类型检查,更加严谨。

3. 防止了命名污染(封装)

4. 便于调试

5. 使用方便,一次可以定义多个常量

void menu()
{
	printf("<-==============通讯录=============->\n");
	printf("<-==========1.增加联系人===========->\n");
	printf("<-==========2.删除联系人===========->\n");
	printf("<-==========3.查找联系人===========->\n");
	printf("<-==========4.修改联系人===========->\n");
	printf("<-==========5.打印通讯录===========->\n");
	printf("<-==========6.排序通讯录===========->\n");
	printf("<-==========0.退出通讯录===========->\n");
	printf("<-=================================->\n");
}
enum Option
{
	EXIT,	//0
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT
};
int main()
{
	int input = 0;
	do
	{
		//菜单
		menu();
		printf("请输入操作:");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			printf("增加联系人\n");
			break;
		case DEL:
			printf("删除联系人\n");
			break;
		case SEARCH:
			printf("查找联系人\n");
			break;
		case MODIFY:
			printf("修改联系人\n");
			break;
		case SHOW:
			printf("打印联系人\n");
			break;
		case SORT:
			printf("排序联系人\n");
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		default:
			printf("输入错误,重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

 

关于通讯录结构体的创建 

创建所需的个人信息结构体

利用#define 定义常量,有利于维护;

#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30

typedef struct Peo		//个人信息结构体
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char tele[TELE_MAX];
	char addr[ADDR_MAX];
}Peo;

另外还需要创建一个结构体,来记录Peo的信息,以数组来存放,创建变量,记录个数 

typedef struct Contact
{
	Peo data[DATA_MAX];		//存放个人信息
	int sz;		//记录信息人数
}Contact;

二:通讯录的功能实现(静态)

2.1初始化通讯录

//静态-初始化通讯录
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data)); 
}

memset来初始化,以字节为单位一个字节一个字节的初始化! 

2.2增加联系人

增加之前,先判断是否为满,增加成功后,还需要将sz++,记录加入的人数

//增加联系人
void AddContact(Contact* pc)
{
	assert(pc);
	//判断通讯录是否满了
	if (pc->sz == DATA_MAX)
	{
		printf("通讯录已满,增加失败\n");
		return;
	}
	//增加信息
	printf("请输入名字:");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别:");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入电话:");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[pc->sz].addr);
	//对sz增加,
	pc->sz++;
	printf("增加成功\n");
}

 

2.3打印通讯录

增加联系人后,真的在内存中增加与否,并不知道,我们需要打印出来

先判断是否有信息,然后打印标题,增加可读性,再利用for循环,将sz个信息打印出来 

-20就代表域宽是20(长度不够20用空格填充),负号代表左对齐,默认是右对齐的!

//显示所有的联系人
void ShowContact(const Contact* pc)
{
	assert(pc);
	//判断通讯录内是否有信息
	if (pc->sz == 0)
	{
		printf("打印失败,通讯录为空\n");
		return;
	}
	//打印
	//打印标题
	printf("%-20s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
	//打印信息
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		//打印每个人的信息
		printf("%-20s%-5d%-5s%-12s%-30s\n",
			pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}
}

2.4删除联系人

  1. 先判断通讯录是否有信息,通过名字来查找是否存在此人,
  2. 封装函数:因为我们在查找联系人,修改联系人中也会用到此功能。查找到此人,返回sz位置,没有此人,返回-1;
  3.  通过for循环:假如要删除人为 tmp的信息;就只需要把tmp后的数据往前移动,覆盖掉tmp位置的信息就可以了;
  4. 如果要删除最后一个人,则直接sz--;可以不进行访问,算是删除了
  5. 删除成功后,就把sz--;说明数组里的有效数据减1!
//通过名字查找被删除人
static 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 DelContact(Contact* pc)
{
	assert(pc);
	//判断是否为空
	if (pc->sz == 0)
	{
		printf("删除失败,通讯录为空\n");
		return;
	}
	//查找是否存在此人
	char name[NAME_MAX];
	printf("请输入被删除人名字:\n");
	scanf("%s", name);
	//查找此人,存在返回位置,不存在返回-1
	int ret = FindByName(pc,name);
	if (ret == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	//删除(覆盖)此人
	for (int i = ret; i < pc->sz - 1; i++)	//sz-1 是防止执行体越界,如果要删除的是最后一个元素,通过sz--,直接不访问,
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz --;
	printf("删除成功\n");
}

 

 

 2.5 查找联系人

跟删除同理,先查找是否存在此人,查找到了返回下标打印出来即可 

//查找联系人
void FindContact(Contact* pc)
{
	assert(pc);
	//判断是否为空
	if (pc->sz == 0)
	{
		printf("查找失败,通讯录为空\n");
		return;
	}
	//查找此人,存在返回位置,不存在返回-1
	char name[NAME_MAX];
	printf("请输入被查找人名字:\n");
	scanf("%s", name);
	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("要查找的人不存在\n");
		return;
	}
	//显示出来
	printf("%-20s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
	printf("%-20s%-5d%-5s%-12s%-30s\n",
		pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}

2.6修改联系人 

查找到此人位置,记录返回,通过该位置进行修改 

//修改联系人
void ModifyContact(Contact* pc)
{
	assert(pc);
	//判断是否为空
	if (pc->sz == 0)
	{
		printf("修改失败,通讯录为空\n");
		return;
	}
	//查找此人,存在返回位置,不存在返回-1
	char name[NAME_MAX];
	printf("请输入被修改人名字:\n");
	scanf("%s", name);
	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("要查找的人不存在\n");
		return;
	}
	//修改
	printf("请输入名字:");
	scanf("%s", pc->data[ret].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[ret].age));
	printf("请输入性别:");
	scanf("%s", pc->data[ret].sex);
	printf("请输入电话:");
	scanf("%s", pc->data[ret].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[ret].addr);

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

 

2.7排序联系人

利用qsort快速排序,然后我们以名字strcmp函数来比较

//目录排序
//void qsort(void* base, size_t num, size_t size,
//	int (*compar)(const void*, const void*));
int cmpare(const void* p1, const void* p2)
{
	return strcmp(((Peo*)p1)->name, ((Peo*)p2)->name);
}

void SortContact(Contact* pc)
{
	qsort(pc->data, pc->sz, sizeof(Peo), cmpare);
}

三:通讯录优化——动态内存

 3.1通讯录的创建

增加变量capacity——用来记录通讯录容量

利用指针动态创建内存,结合malloc,realloc,calloc

typedef struct Contact
{
	Peo* data;    //存放数据
	int sz;		    //记录信息人数
	int capacity;    //记录的是通讯录的当前容量
}Contact;

3.2初始化通讯录 

利用calloc 开辟动态空间给data 

#define DEFAULT_SZ 3		//默认容量
#define DEFAULT_INC 2		//扩容量
//动态版本的初始化
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;	
	pc->data = calloc(pc->capacity, sizeof(Peo));	
	if (pc->data == NULL)
	{
		perror("InitContact->calloc");
		return;
	}
}

3.3增加联系人 

 利用realloc来进行动态扩容,存放到临时变量ptr里,开辟成功给data

//检查是否需要扩容
void CheckCapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		Peo* ptr = (Peo*)realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(Peo));
		if (ptr != NULL)
		{
			pc->data = ptr;
			pc->capacity += DEFAULT_INC;
			printf("增容成功\n");
		}
		else
		{
			perror("AddContact->realloc");
			return;
		}
	}
}
//增加联系人
void AddContact(Contact* pc)
{
	assert(pc);
	//增加容量
	CheckCapacity(pc);
	//增加信息
	printf("请输入名字:");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别:");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入电话:");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;
	printf("增加成功\n");
}

3.4清空通讯录 

因为涉及到了动态开辟,所以使用后要进行free空间

防止内存泄漏

写到EXIT退出通讯录里面,让它退出直接调用这个清空销毁函数!就算不销毁最终程序结束也会自动销毁!

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

 四:通讯录优化——文件版本

4.1退出保存信息到文件

使用文件操作,涉及到了文件缓冲区;

ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序 中每一个正在使用的文件开辟一块“文件缓冲区”。

① 从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。

② 从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓 冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。

③ 缓冲区的大小根据C编译系统决定的。

因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。 如果不做,可能导致读写文件的问题。

 

先把信息存储起来后,在执行销毁并退出! 

//保存信息到文件
void SaveContact(Contact* pc)
{
	FILE* pf = fopen("contact.txt", "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);
		fwrite(pc->data + i, sizeof(Peo), 1, pf);
	}

	fclose(pf);
	pf = NULL;
}

 4.2初始化时加载文件信息

将信息加载到文件当中,

在初始化阶段加载文件信息

void CheckCapacity(Contact* pc);//检查上次保存的信息是否需要扩容
void LoadContact(Contact* pc)
{
	FILE* pf = fopen("contact.txt", "rb");    //以二进制读文件
	if (pf == NULL)
	{
		perror("LoadContact");
		return;
	}
	//读文件
	Peo tmp = { 0 };    //临时变量
	while (fread(&tmp, sizeof(Peo), 1, pf))
	{
		CheckCapacity(pc);
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}

	fclose(pf);
	pf = NULL;
}

//文件版本的初始化函数
void InitContact(Contact* pc)
{
	assert(pc);

	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
	pc->data = calloc(pc->capacity, sizeof(Peo));
	if (pc->data == NULL)
	{
		perror("InitContact->calloc");
		return;
	}
	//加载文件中的信息到通讯录
	LoadContact(pc);
}

 

五:整体代码

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include "contact.h"
void menu()
{
	printf("<-==============通讯录=============->\n");
	printf("<-==========1.增加联系人===========->\n");
	printf("<-==========2.删除联系人===========->\n");
	printf("<-==========3.查找联系人===========->\n");
	printf("<-==========4.修改联系人===========->\n");
	printf("<-==========5.打印通讯录===========->\n");
	printf("<-==========6.排序通讯录===========->\n");
	printf("<-==========0.退出通讯录===========->\n");
	printf("<-=================================->\n");
}
enum Option
{
	EXIT,	//0
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT
};
int main()
{
	int input = 0;
	Contact con;	//创建通讯录
	//初始化通讯录
	InitContact(&con);
	do
	{
		//菜单
		menu();
		printf("请输入操作:");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			printf("增加联系人\n");
			AddContact(&con);
			break;
		case DEL:
			printf("删除联系人\n");
			DelContact(&con);
			break;
		case SEARCH:
			printf("查找联系人\n");
			FindContact(&con);
			break;
		case MODIFY:
			printf("修改联系人\n");
			ModifyContact(&con);
			break;
		case SHOW:
			printf("打印联系人\n");
			ShowContact(&con);
			break;
		case SORT:
			printf("排序联系人\n");
			SortContact(&con);
			break;
		case EXIT:
			printf("退出通讯录\n");
			SaveContact(&con);
			DestroyContact(&con);
			break;
		default:
			printf("输入错误,重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

 contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"

静态-初始化通讯录
//void InitContact(Contact* pc)
//{
//	assert(pc);
//	pc->sz = 0;
//	memset(pc->data, 0, sizeof(pc->data)); 
//}
动态版本的初始化
//void InitContact(Contact* pc)
//{
//	assert(pc);
//	pc->sz = 0;
//	pc->capacity = DEFAULT_SZ;	
//	pc->data = calloc(pc->capacity, sizeof(Peo));	
//	if (pc->data == NULL)
//	{
//		perror("InitContact->calloc");
//		return;
//	}
//}
void CheckCapacity(Contact* pc);//检查上次保存的信息是否需要扩容
void LoadContact(Contact* pc)
{
	FILE* pf = fopen("contact.txt", "rb");
	if (pf == NULL)
	{
		perror("LoadContact");
		return;
	}
	//读文件
	Peo tmp = { 0 };
	while (fread(&tmp, sizeof(Peo), 1, pf))
	{
		CheckCapacity(pc);
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}

	fclose(pf);
	pf = NULL;
}

//文件版本的初始化函数
void InitContact(Contact* pc)
{
	assert(pc);

	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
	pc->data = calloc(pc->capacity, sizeof(Peo));
	if (pc->data == NULL)
	{
		perror("InitContact->calloc");
		return;
	}
	//加载文件中的信息到通讯录
	LoadContact(pc);
}
//
静态增加联系人
//void AddContact(Contact* pc)
//{
//	assert(pc);
//	//判断通讯录是否满了
//	if (pc->sz == DATA_MAX)
//	{
//		printf("通讯录已满,增加失败\n");
//		return;
//	}
//	//增加信息
//	printf("请输入名字:");
//	scanf("%s", pc->data[pc->sz].name);
//	printf("请输入年龄:");
//	scanf("%d", &(pc->data[pc->sz].age));
//	printf("请输入性别:");
//	scanf("%s", pc->data[pc->sz].sex);
//	printf("请输入电话:");
//	scanf("%s", pc->data[pc->sz].tele);
//	printf("请输入地址:");
//	scanf("%s", pc->data[pc->sz].addr);
//	//对sz增加,
//	pc->sz++;
//	printf("增加成功\n");
//}
void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->sz = 0;
	pc->capacity = 0;
}
//检查是否需要扩容
void CheckCapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		Peo* ptr = (Peo*)realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(Peo));
		if (ptr != NULL)
		{
			pc->data = ptr;
			pc->capacity += DEFAULT_INC;
			printf("增容成功\n");
		}
		else
		{
			perror("AddContact->realloc");
			return;
		}
	}
}
//增加联系人
void AddContact(Contact* pc)
{
	assert(pc);
	//增加容量
	CheckCapacity(pc);
	//增加信息
	printf("请输入名字:");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别:");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入电话:");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;
	printf("增加成功\n");
}

//显示所有的联系人
void ShowContact(const Contact* pc)
{
	assert(pc);
	//判断通讯录内是否有信息
	if (pc->sz == 0)
	{
		printf("打印失败,通讯录为空\n");
		return;
	}
	//打印
	//打印标题
	printf("%-20s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
	//打印信息
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		//打印每个人的信息
		printf("%-20s%-5d%-5s%-12s%-30s\n",
			pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}
}

//通过名字查找被删除人
static 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 DelContact(Contact* pc)
{
	assert(pc);
	//判断是否为空
	if (pc->sz == 0)
	{
		printf("删除失败,通讯录为空\n");
		return;
	}
	//查找是否存在此人
	char name[NAME_MAX];
	printf("请输入被删除人名字:\n");
	scanf("%s", name);
	//查找此人,存在返回位置,不存在返回-1
	int ret = FindByName(pc,name);
	if (ret == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	//删除(覆盖)此人
	for (int i = ret; i < pc->sz - 1; i++)	//sz-1 是防止执行体越界,如果要删除的是最后一个元素,通过sz--,直接不访问,
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

//查找联系人
void FindContact(Contact* pc)
{
	assert(pc);
	//判断是否为空
	if (pc->sz == 0)
	{
		printf("查找失败,通讯录为空\n");
		return;
	}
	//查找此人,存在返回位置,不存在返回-1
	char name[NAME_MAX];
	printf("请输入被查找人名字:\n");
	scanf("%s", name);
	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("要查找的人不存在\n");
		return;
	}
	//显示出来
	printf("%-20s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
	printf("%-20s%-5d%-5s%-12s%-30s\n",
		pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}

//修改联系人
void ModifyContact(Contact* pc)
{
	assert(pc);
	//判断是否为空
	if (pc->sz == 0)
	{
		printf("修改失败,通讯录为空\n");
		return;
	}
	//查找此人,存在返回位置,不存在返回-1
	char name[NAME_MAX];
	printf("请输入被修改人名字:\n");
	scanf("%s", name);
	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("要查找的人不存在\n");
		return;
	}
	//修改
	printf("请输入名字:");
	scanf("%s", pc->data[ret].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[ret].age));
	printf("请输入性别:");
	scanf("%s", pc->data[ret].sex);
	printf("请输入电话:");
	scanf("%s", pc->data[ret].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[ret].addr);

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

//目录排序
//void qsort(void* base, size_t num, size_t size,
//	int (*compar)(const void*, const void*));
int cmpare(const void* p1, const void* p2)
{
	return strcmp(((Peo*)p1)->name, ((Peo*)p2)->name);
}

void SortContact(Contact* pc)
{
	qsort(pc->data, pc->sz, sizeof(Peo), cmpare);
}
//保存信息到文件
void SaveContact(Contact* pc)
{
	FILE* pf = fopen("contact.txt", "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);
		fwrite(pc->data + i, sizeof(Peo), 1, pf);
	}

	fclose(pf);
	pf = NULL;
}

contact.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<string.h>
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30

#define DATA_MAX 100

#define DEFAULT_SZ 3		//默认容量
#define DEFAULT_INC 2		//扩容量

typedef struct Peo		//个人信息结构体
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char tele[TELE_MAX];
	char addr[ADDR_MAX];
}Peo;
typedef struct Contact
{
	Peo* data;//存放数据
	int sz;		//记录信息人数
	int capacity;//记录的是通讯录的当前容量
}Contact;

//初始化通讯录
//void InitContact(Contact* pc);

//动态版本的初始化
void InitContact(Contact* pc);

//增加联系人
void AddContact(Contact* pc);

//显示所有的联系人
void ShowContact(const Contact* pc);

//删除联系人
void DelContact(Contact* pc);

//查找联系人
void FindContact(Contact* pc);

//修改联系人
void ModifyContact(Contact* pc);

//排序联系人
void SortContact(Contact* pc);

//销毁通讯录
void DestroyContact(Contact* pc);

//保存信息到文件
void SaveContact(Contact* pc);

//加载文件信息到通讯录
void LoadContact(Contact* pc);

以上就是利用三章知识点结合做的小项目——通讯录;

文中不足之处还望指点,感激不尽

 

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

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

相关文章

docker 复习

文章目录 docker 安装配置镜像加速器拉取镜像的仓库&#xff1a; docker 部署Mysql 镜像命令的详细解释docker 相关命令总结 docker 安装 查看是否安装的镜像已经在系统中存在&#xff1a; docker images &#xff08;存在2&#xff0c;不存在 3&#xff09; 卸载旧版本 yum r…

当出现“无法成功完成操作,因为文件包含病毒或潜在的垃圾软件“时的解决办法

安装补丁或其他安装包时,被系统识别为病毒垃圾 具体解决步骤是: 1.在开始菜单&#xff0c;打开Windows 安全中心 找到主页的病毒和威胁防护 找到管理设置 最后将确认安全的文件或安装包添加到排除项即可

Latex 通过\item控制编号

\item通常用于 1 论文写作中的hightlight 2 或一些需要缩进的场景 具体实现 \item 或\item[]在方括号里面添加1&#xff09;、 (1)来控制

Ubuntu系统搭建及环境部署

Ubuntu系统搭建及环境部署 1 制作系统&#xff08;系统盘安装&#xff09;1.1 选择版本&#xff0c;并下载1.2 刻录系统盘1.3 制作系统 2 配置2.1 root登陆2.2 更新国内源 1 制作系统&#xff08;系统盘安装&#xff09; ubuntu中文官网 1.1 选择版本&#xff0c;并下载 在官…

canvas画一个笑脸和画一个三角形

画一个笑脸主要用到的是画弧形的方法&#xff1a;arc&#xff0c;有五个参数&#xff1a;起始坐标&#xff0c;半径&#xff0c;弧形起始坐标&#xff0c;还有一个参数是顺时针还是逆时针。画的笑脸&#xff1a;虽然丑了点&#xff0c;但是学习了 代码&#xff1a; <!DOCTY…

在C++和Python的项目中使用ROS

如果搜索如何使用ROS&#xff0c;搜索结果肯定是先建立工作空间&#xff0c;在创建功能包等等步骤&#xff0c;但其实不需要这么麻烦。 在Python中使用ROS&#xff0c;只需要在Pycharm的Project Structure中的Add Content Root加入ros的packages就可以了&#xff0c;如下图 在…

实时美颜SDK技术的崭新时代:美颜sdk的开发与应用

美颜技术一直以来都备受关注&#xff0c;特别是在社交媒体和直播平台的兴起中&#xff0c;人们对自己的外貌越来越注重。最近这几年&#xff0c;实时美颜已经进入了一个新的阶段&#xff0c;也带来了行业的革新&#xff0c;特别是美颜SDK&#xff0c;在这一进程中扮演了至关重要…

科技与环卫的结合,是智慧公厕厂家的使命

城市&#xff0c;作为人类社会的象征&#xff0c;正经历着前所未有的快速发展和改变。然而&#xff0c;这个发展过程中往往伴随着环境卫生问题&#xff0c;其中城市卫生设施的质量和管理尤为重要。在这个背景下&#xff0c;智慧公厕厂家正致力于将科技与环卫领域的专业知识结合…

牛客周赛 Round 15 D 游游的树上边染红(树形dp)

牛客周赛 Round 15 D 游游的树上边染红(树形dp) 一道很裸的树形dp&#xff0c;周日晚上看了一晚上看不懂&#xff0c;第二天突然就悟了。 题目跟没有上司从舞会很像&#xff0c;我们粗略的考虑&#xff0c;当前节点的状态为选/不选&#xff0c;然后根据此进行状态转移。 不选择…

跨境商城源码有哪些独特的功能和优势

1. 强大的跨境支付功能 跨境商城源码具备强大的跨境支付功能&#xff0c;支持多种支付方式&#xff0c;包括信用卡、支付宝、微信支付等。该功能遵循国际支付标准&#xff0c;能够确保支付过程的安全性和可靠性&#xff0c;为用户提供便捷的跨境购物体验。 2. 多语言和多货币支…

26栈和队列-简单实践

目录 LeetCode之路——20. 有效的括号 分析&#xff1a; LeetCode之路——1047. 删除字符串中的所有相邻重复项 分析&#xff1a; LeetCode之路——20. 有效的括号 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#…

SpringBoot 整和 Netty 并监听多端口

SpringBoot 整和 Netty 并监听多端口 Netty 是由 JBOSS 提供的一个 Java 开源框架。Netty 提供异步的、基于事件驱动的网络应用程序框架&#xff0c;用以快速开发高性能、高可靠性的网络 IO 程序,是目前最流行的 NIO 框架&#xff0c;Netty 在互联网领域、大数据分布式计算领域…

Bootstrap的警告框组件

可以利用类alert实现警告框组件。。 01-基本的警告框组件使用示例 示例代码如下&#xff1a; <!DOCTYPE html> <html> <head><meta charset"UTF-8"><title>警告框</title><meta name"viewport" content"wi…

如何同时打开两个pycharm文件

进入设置&#xff0c;搜索项目&#xff0c;选择新窗口或询问都可以 下面是选择了询问后打开新项目会弹出的页面

Vue进阶(幺陆伍)PhantomJS 实战讲解

文章目录 一、前言二、PhantomJS2.1 PhantomJS 使用场景2.2 PhantomJS 项目实战2.2.1 环境配置2.2.2 Demo: 自动化截图 三、拓展阅读 一、前言 在前期博文《Vue进阶&#xff08;五十六&#xff09;&#xff1a;vue-cli 脚手架 karma.conf.js 配置文件详解》中讲解了 karma.con…

Jmeter关联操作

1.首先右键添加一个线程选择线程组,命名为线程组-1&#xff0c;添加取样器选择HTTP请求--城市天气 2.线程组-1右键&#xff0c;添加取样器选择后置处理器中的JSON提取器 3.线程组-1右键,添加取样器选择后置处理器中的BeanShell 后置处理程序(必须平级) 4.首先右键添加一个线程选…

MySQL学习(一)——简介以及SQL语句

文章目录 1. MySQL介绍1.1 数据库概述1.2 关系型数据库 2. SQL2.1 SQL通用规范2.2 DDL2.2.1 数据库操作2.2.2 创建和查询表2.2.3 修改表2.2.4 数据类型2.2.5 DataGrip使用 2.3 DML2.3.1 添加数据2.3.2 更新和删除 2.4 DQL2.4.1 基础查询2.4.2 条件查询2.4.3 聚合函数2.4.4 分组…

ArcGIS笔记6_绘制中间镂空的面要素、面要素抠洞

本文目录 前言Step 1 对海湾大整面和零散的岛屿分别绘制面要素Step 2 利用[擦除]工具从海湾大整面中抠掉零散的岛屿 前言 使用ArcGIS做项目时&#xff0c;很多场景下都需要绘制中间镂空的面要素&#xff0c;比如一个海湾中间有许多零散的岛屿&#xff0c;计算水域面积时就要扣…

Linux-CentOS8-Oracle19c 安装详解

Linux-CentOS8-Oracle19c安装图解 文章目录 Linux-CentOS8-Oracle19c安装图解预备1. Oracle19c 安装手册&#xff1a;2. 安装虚拟机&#xff1a;4G内存&#xff0c;2*2核心&#xff0c;30G3. 下载CentOS8镜像。4. 开始准备预安装5. 修改Oracle账户密码6. 修改SELINUX值在文件&a…

行业追踪,2023-10-16

自动复盘 2023-10-16 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…