C语言实战项目【4】通讯录(纯C含文件操作和动态内存管理)

这篇博客介绍了如何使用C语言实现一个简单的个人通讯录管理系统,包括添加、删除、查找、修改、打印、排序和清空等功能。通过动态内存分配和文件操作,实现了数据的持久化。程序还包含了菜单驱动的用户交互界面,便于用户操作。
摘要由CSDN通过智能技术生成

1.目录

这里我们需要制作一个目录供使用者选择,具体代码如下

void menu()
{
	printf("**************************************\n");
	printf("*****1.Add            2.Del***********\n");
	printf("*****3.Alt            4.Find**********\n");
	printf("*****5.Print          6.Sort**********\n");
	printf("*****7.Empty          0.Exit**********\n");
	printf("**************************************\n");
}

2.多次运行

我们在操作通讯录的时候,需要进行多次操作,所以我们设置一个多次运行的代码

int input;
	Contact con = {0};
	con.data = (PeoInfo*)malloc(sizeof(PeoInfo) * MAX);
	if (con.data == NULL)
	{
		printf("开辟空间失败\n");
		return -1;
	}
	InitContact(&con);
	do
	{
		menu();
		printf("请选择:>\n");
		scanf("%d", &input);
		switch (input)
		{
		case Add:
			ADD(&con);
			break;
		case Del:
			Del_Con(&con);
			break;
		case Alt:
			Alt_Con(&con);
			break;
		case Find:
			Find_Con(&con);
			break;
		case Print:
			system("cls");                //清空控制台
			Print_Con(&con);
			break;
		case Sort:
			Sqrt_Con(&con);
			break;
		case Empty:
			Empty_Con(&con);
			break;
		case Exit:
			printf("程序退出\n");
			SaveContact(&con);
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
		         

	} while (input);

为了更加清晰,我设置了一个枚举常量,来对case进行标识,具体的枚举常量如下

enum Input
{
	Exit,              //退出
	Add,               //增加
	Del,               //删除
	Alt,               //更改
	Find,              //查找
	Print,             //打印
	Sort,              //排序
	Empty              //清空
};

3.初始化通讯录,这里我们要对通讯录先进行初始化

void InitContact(Contact* pc)
{
	assert(pc);
	pc->Capacity = MAX;
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
	LoadContact(pc);
}

这里的LoadContact是为了文件操作,在后面会设计讲设计这个函数(6.文件读取)

4.扩容

因为上面的2.多次运行中我们设置的是动态的内存空间,所以肯定会存在内存不足的情况,所以我们这里就进行一个扩容,一次多增加两个空间,具体代码如下

void Capacity(Contact* pc)                                //扩容
{
	if (pc->sz == pc->Capacity)
	{
		pc->data = (PeoInfo*)realloc(pc->data, sizeof(PeoInfo) * pc->Capacity + sizeof(PeoInfo) * 2);
		pc->Capacity += 2;
		if (pc->data == NULL)
		{
			printf("扩容失败\n");
			return;
		}
		else
		printf("扩容成功\n");
	}
}

5.文件写入

这里我们可以在exit里面设置一个文件读取,这样我们在退出的时候,可以把我们写在通讯录里面的东西写入到文件里面去

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

6.文件读取

这里我们在每次打开的时候,可以把之前存在文件里面的数据写入到通讯录中,具体代码如下

void LoadContact(Contact* pc)
{
	PeoInfo temp;
	FILE* pf = fopen("Contact.txt","rb");
	if (pf == NULL)
	{
		perror("LoadContact::fopen");
		return;
	}
	while (fread(&temp, sizeof(PeoInfo), 1, pf))
	{
		*(pc->data + pc->sz) = temp;
		pc->sz++;
		Capacity(pc);
	}
	fclose(pf);
	pf == NULL;
}

7.联系人结构体

在这一步我们可以写入联系人到联系人结构体中去,我设计的联系人的结构体如下

typedef struct PeoInfo
{
	char name[MAX_NAME];
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
	int age;
}PeoInfo;

typedef struct Contact
{
	PeoInfo* data;
	int sz;
	int Capacity;
}Contact;

这里设计了两个结构体是为了方便记录联系人当前的数据

8.添加联系人

这里我们只需要往联系人结构体里面添加数据就可以了

void ADD(Contact* pc)                                     //添加
{
	Capacity(pc);
	printf("请输入名字\n");
	scanf("%s",pc->data[pc->sz].name);
	printf("请输入性别\n");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入年龄\n");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入电话号码\n");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址\n");
	scanf("%s", pc->data[pc->sz].addr);
	pc->sz++;
	printf("添加成功\n");
	fflush(stdin);                                //清空缓存区
}

9.查找函数

因为查找联系人和删除联系人,修改联系人等都需要进行查找操作,所以我就把查找联系人封装成一个函数

int Find_name(Contact* pc,char c[])             //用名字查找
{
	for (int i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, c) == 0)
			return i;
	}
	return -1;
}

10.删除联系人

这里我们只要调用之前的查找联系人函数,然后然后将后面的数据往前面移就可以了

void Del_Con(Contact* pc)                       //删除
{
	char c[MAX_NAME];
	if (pc->sz == 0)
	{
		printf("没有联系人可以删除\n");
		return;
	}
	printf("请输入需要删除的名字\n");
	scanf("%s",c);
	int ret =Find_name(pc, c);
	if (ret == -1)
	{
		printf("没有找到该数据");
		return;
	}
	for (int i = ret; i < pc->sz-1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
}

11.查找联系人

这里我们只需要调用一下上面的查找函数就可以了

void Find_Con(Contact* pc)
{
	char c[MAX_NAME];
	printf("请输入需要查找的名字\n");
	scanf("%s",c);
	int ret = Find_name(pc,c);
	if (ret == -1)
	{
		printf("没有该元素\n");
		return;
	}
	printf("%-20s%-5s%-5s%-13s%-30s\n", "名字", "性别", "年龄", "电话号码", "地址");
	printf("%-20s%-5s%-5s%-13s%-30s\n", pc->data[ret].name, pc->data[ret].sex, pc->data[ret].name,
		pc->data[ret].tele, pc->data[ret].addr);
}

12.更改联系人信息

这里我们也需要调用查找练习人的信息,然后选择需要更改的项目,最后进行更改就可以了其他的逻辑和上面的多次运行差不多

void Alt_Con(Contact* pc)
{
	char c[MAX_NAME];
	printf("请输入需要修改的名字\n");
	scanf("%s",c);
	int ret = Find_name(pc, c);
	if (ret == -1)
	{
		printf("该联系人不存在\n");
		return;
	}
	printf("请选择需要修改的内容\n");
	printf("1.名字    2.性别     \n");
	printf("3.年龄    4.电话号码 \n");
	printf("5.地址    0.放弃修改 \n");
	int input;
	scanf("%d",&input);
	switch (input)
	{
	case 1 :
		printf("请输入需要修改成什么\n");
		char nam[MAX_NAME];
		scanf("%s",nam);
		strcpy(pc->data[ret].name, nam);
		break;
	case 2 :
		printf("请输入需要修改成什么\n");
		char sex[MAX_SEX];
		scanf("%s", sex);
		strcpy(pc->data[ret].sex, sex);
		break;
	case 3:
		printf("请输入需要修改成什么\n");
		char age[3];
		scanf("%s", age);
		strcpy(pc->data[ret].age, age);
		break;
	case 4:
		printf("请输入需要修改成什么\n");
		char tele[MAX_TELE];
		scanf("%s", tele);
		strcpy(pc->data[ret].tele,tele);
		break;
	case 5:
		printf("请输入需要修改成什么\n");
		char addr[MAX_ADDR];
		scanf("%s", addr);
		strcpy(pc->data[ret].addr, addr);
		break;
	case 0:
		return;
		break;
	default:
		printf("输入错误\n");
		return;
	}

}

13.打印联系人

这里可以把所有练习人的信息打印到屏幕上面,然后清空控制台

void Print_Con(Contact* pc)                       //打印
{
	printf("%-20s%-5s%-5s%-13s%-30s\n","名字","性别","年龄","电话号码","地址");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-20s%-5s%-5d%-13s%-30s\n",pc->data[i].name, pc->data[i].sex, pc->data[i].age,
			pc->data[i].tele, pc->data[i].addr);
	}
}

14.联系人排序

这里我们可以对联系人的名字进行排序,我采用的是比较简单的冒泡排序法

void Sqrt_Con(Contact* pc)                                  //排序
{
	int i = 0;
	int j = 0;
	PeoInfo c;
	for (i = 0; i < pc->sz-1; i++)
	{
		for (j = 0; j < pc->sz-1-i; j++)
		{
			if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0)
			{
				c = pc->data[j];
				pc->data[j] = pc->data[j + 1];
				pc->data[j + 1] = c;
			}
		}
	}
	printf("排序完成\n");
}

15.清空联系人

当我们需要重置表的时候,就可以调用清空联系人的函数,这里的代码和初始化很像,但是不可以直接使用初始化函数,因为初始化函数中有读取文件操作

void Empty_Con(Contact* pc)                               //清空
{
	assert(pc);
	pc->Capacity = MAX;
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
	printf("通讯录已清空\n");
}

16.全部代码

//address.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"address.h"
void InitContact(Contact* pc)
{
	assert(pc);
	pc->Capacity = MAX;
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
	LoadContact(pc);
}

void Capacity(Contact* pc)                                //扩容
{
	if (pc->sz == pc->Capacity)
	{
		pc->data = (PeoInfo*)realloc(pc->data, sizeof(PeoInfo) * pc->Capacity + sizeof(PeoInfo) * 2);
		pc->Capacity += 2;
		if (pc->data == NULL)
		{
			printf("扩容失败\n");
			return;
		}
		else
		printf("扩容成功\n");
	}
}


void ADD(Contact* pc)                                     //添加
{
	Capacity(pc);
	printf("请输入名字\n");
	scanf("%s",pc->data[pc->sz].name);
	printf("请输入性别\n");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入年龄\n");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入电话号码\n");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址\n");
	scanf("%s", pc->data[pc->sz].addr);
	pc->sz++;
	printf("添加成功\n");
	fflush(stdin);                                //清空缓存区
}

void Print_Con(Contact* pc)                       //打印
{
	printf("%-20s%-5s%-5s%-13s%-30s\n","名字","性别","年龄","电话号码","地址");
	for (int i = 0; i < pc->sz; i++)
	{
		printf("%-20s%-5s%-5d%-13s%-30s\n",pc->data[i].name, pc->data[i].sex, pc->data[i].age,
			pc->data[i].tele, pc->data[i].addr);
	}
}

//找到返回下标
//没找到返回-1
int Find_name(Contact* pc,char c[])             //用名字查找
{
	for (int i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, c) == 0)
			return i;
	}
	return -1;
}

void Del_Con(Contact* pc)                       //删除
{
	char c[MAX_NAME];
	if (pc->sz == 0)
	{
		printf("没有联系人可以删除\n");
		return;
	}
	printf("请输入需要删除的名字\n");
	scanf("%s",c);
	int ret =Find_name(pc, c);
	if (ret == -1)
	{
		printf("没有找到该数据");
		return;
	}
	for (int i = ret; i < pc->sz-1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
}


void Alt_Con(Contact* pc)
{
	char c[MAX_NAME];
	printf("请输入需要修改的名字\n");
	scanf("%s",c);
	int ret = Find_name(pc, c);
	if (ret == -1)
	{
		printf("该联系人不存在\n");
		return;
	}
	printf("请选择需要修改的内容\n");
	printf("1.名字    2.性别     \n");
	printf("3.年龄    4.电话号码 \n");
	printf("5.地址    0.放弃修改 \n");
	int input;
	scanf("%d",&input);
	switch (input)
	{
	case 1 :
		printf("请输入需要修改成什么\n");
		char nam[MAX_NAME];
		scanf("%s",nam);
		strcpy(pc->data[ret].name, nam);
		break;
	case 2 :
		printf("请输入需要修改成什么\n");
		char sex[MAX_SEX];
		scanf("%s", sex);
		strcpy(pc->data[ret].sex, sex);
		break;
	case 3:
		printf("请输入需要修改成什么\n");
		char age[3];
		scanf("%s", age);
		strcpy(pc->data[ret].age, age);
		break;
	case 4:
		printf("请输入需要修改成什么\n");
		char tele[MAX_TELE];
		scanf("%s", tele);
		strcpy(pc->data[ret].tele,tele);
		break;
	case 5:
		printf("请输入需要修改成什么\n");
		char addr[MAX_ADDR];
		scanf("%s", addr);
		strcpy(pc->data[ret].addr, addr);
		break;
	case 0:
		return;
		break;
	default:
		printf("输入错误\n");
		return;
	}

}

void Find_Con(Contact* pc)
{
	char c[MAX_NAME];
	printf("请输入需要查找的名字\n");
	scanf("%s",c);
	int ret = Find_name(pc,c);
	if (ret == -1)
	{
		printf("没有该元素\n");
		return;
	}
	printf("%-20s%-5s%-5s%-13s%-30s\n", "名字", "性别", "年龄", "电话号码", "地址");
	printf("%-20s%-5s%-5s%-13s%-30s\n", pc->data[ret].name, pc->data[ret].sex, pc->data[ret].name,
		pc->data[ret].tele, pc->data[ret].addr);
}


void Sqrt_Con(Contact* pc)                                  //排序
{
	int i = 0;
	int j = 0;
	PeoInfo c;
	for (i = 0; i < pc->sz-1; i++)
	{
		for (j = 0; j < pc->sz-1-i; j++)
		{
			if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0)
			{
				c = pc->data[j];
				pc->data[j] = pc->data[j + 1];
				pc->data[j + 1] = c;
			}
		}
	}
	printf("排序完成\n");
}

void Empty_Con(Contact* pc)                               //清空
{
	assert(pc);
	pc->Capacity = MAX;
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
	printf("通讯录已清空\n");
}



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

void LoadContact(Contact* pc)
{
	PeoInfo temp;
	FILE* pf = fopen("Contact.txt","rb");
	if (pf == NULL)
	{
		perror("LoadContact::fopen");
		return;
	}
	while (fread(&temp, sizeof(PeoInfo), 1, pf))
	{
		*(pc->data + pc->sz) = temp;
		pc->sz++;
		Capacity(pc);
	}
	fclose(pf);
	pf == NULL;
}






//address.h
#pragma once
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#define MAX_NAME 20
#define MAX_SEX 3
#define MAX_TELE 12
#define MAX_ADDR 30
#define MAX 1
enum Input
{
	Exit,              //退出
	Add,               //增加
	Del,               //删除
	Alt,               //更改
	Find,              //查找
	Print,             //打印
	Sort,              //排序
	Empty              //清空
};

typedef struct PeoInfo
{
	char name[MAX_NAME];
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
	int age;
}PeoInfo;

typedef struct Contact
{
	PeoInfo* data;
	int sz;
	int Capacity;
}Contact;

void InitContact(Contact* pc);									//非文件的初始化
void ADD(Contact* pc);											//添加联系人
void Print_Con(Contact* pc);                                    //打印联系人
void Del_Con(Contact* pc);                                      //删除联系人
void Alt_Con(Contact* pc);										//修改联系人
void Find_Con(Contact* pc);                                     //查找联系人
void Sqrt_Con(Contact* pc);                                     //排序联系人
void Empty_Con(Contact* pc);                                    //清空联系人
void Capacity(Contact* pc);										//扩容
void SaveContact(Contact* pc);									//将联系人以二进制写入文件
void LoadContact(Contact* pc);									//以二进制文件的方式初始化联系人


//test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"address.h"
#include<stdio.h>

void menu()
{
	printf("**************************************\n");
	printf("*****1.Add            2.Del***********\n");
	printf("*****3.Alt            4.Find**********\n");
	printf("*****5.Print          6.Sort**********\n");
	printf("*****7.Empty          0.Exit**********\n");
	printf("**************************************\n");
}

int main()
{
	int input;
	Contact con = {0};
	con.data = (PeoInfo*)malloc(sizeof(PeoInfo) * MAX);
	if (con.data == NULL)
	{
		printf("开辟空间失败\n");
		return -1;
	}
	InitContact(&con);
	do
	{
		menu();
		printf("请选择:>\n");
		scanf("%d", &input);
		switch (input)
		{
		case Add:
			ADD(&con);
			break;
		case Del:
			Del_Con(&con);
			break;
		case Alt:
			Alt_Con(&con);
			break;
		case Find:
			Find_Con(&con);
			break;
		case Print:
			system("cls");                //清空控制台
			Print_Con(&con);
			break;
		case Sort:
			Sqrt_Con(&con);
			break;
		case Empty:
			Empty_Con(&con);
			break;
		case Exit:
			printf("程序退出\n");
			SaveContact(&con);
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
		         

	} while (input);
	return 0;
}

快去创建自己的通讯录吧

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值