C语言项目实践——通讯录(三版本联合分解)

项目简介

近代通信少不了电话号码,但是朋友或是要联络的人太多,就需要把电话号码记下来,然而书本纸面上的记载,查询都太过麻烦,因此我们可以利用计算机编程实现一个多功能全面的通讯录,帮助我们更加方便的处理这些电话号码。

目标功能涵盖:

  1. 添加联系人信息
  2. 删除指定联系人信息
  3. 查找指定联系人信息
  4. 显示所有联系人信息
  5. 清空所有联系人
  6. 以名字排序所有联系人
  7. 保存联系人到文件 (文件版)
  8. 从文件加载联系人(文件版)

共需完成三种版本:

  1. 结构体版本(基础版本)
  2. 动态内存版本
  3. 文件操作版本

项目思路

流程图

主要功能放在一个对应的函数里进行封装
在这里插入图片描述
在这里插入图片描述

项目用到的知识点

  1. 结构体的使用
  2. 动态内存malloc realloc calloc free 的使用
  3. 文件的操作

项目功能的实现

函数声明及抽象目标

1.抽象个人信息

typedef struct PersonInfo 
{ 
char name[MAX_NAME]; 
char sex[SEX_NAME]; 
short age; 
char tele[TEL_NAME]; 
char addr[TEL_NAME]; 
}PersonInfo;

2.抽象通讯录

typedef struct Contact { 
//PersonInfo per[MAX_PER_NUM] ;静态版本 
int usedsize;//有效数据个数 动态版本 
PersonInfo* per; //动态版本
int capacity;//初始容量 
}Contact;//通讯录

需要实现函数:

#ifndef __CONTACT_H__ 
#define __CONTACT_H__ 
#include<string.h> 
#include<stdio.h> 
#include<assert.h> 
#include<stdlib.h> 
enum Option 
{ 
EXIT, 
ADD, 
DEL, 
SEARCH, 
MONDIFY, 
SHOW, 
EMPTY, 
SORT 
};
#define MAX_NAME 20 
#define SEX_NAME 5 
#define TEL_NAME 12 
#define ADDR_NAME 20 //通讯录最多为1000人 
#define MAX_PER_NUM 1000 //动态扩容版本 
#define DEFAULT_SIZE 2; 
typedef struct PersonInfo 
{ 
char name[MAX_NAME]; 
char sex[SEX_NAME]; 
short age;
char tele[TEL_NAME]; 
char addr[TEL_NAME]; 
}PersonInfo; 
typedef struct Contact 
{ 
//PersonInfo per[MAX_PER_NUM] ;普通版本 
PersonInfo* per; 
int usedsize;//有效数据个数 
int capacity;//初始容量 
}Contact;//通讯录 
//初始化通讯录 
void InitContact(Contact *con); 
//添加成员 
void AddContact(Contact *con); 
//打印通讯录 
void ShowContact(Contact *con); 
//删除成员 
void DelContact(Contact *con); 
//查找成员 
int SearchContact(Contact *con); 
//清空通讯录 
void EmptyContact(Contact *con); 
//摧毁通讯录(动态版本) 
void DestoryContact(Contact *con); 
//文件版本 //保存联系人到文件 
void SaveContact(Contact *con); 
//加载联系人 
void LoadContact(Contact *con); 
#endif //__CONTACT_H__

主函数的架构与搭建

#include"contact.h"


void menu() {
	printf("******************通讯录********************\n");
	printf("*** 1.add   2.show    3.delete 4.search ****\n");
	printf("*** 5.empty 6.distory 7.save   8.load   ****\n");
	printf("***************** 0.quit *******************\n");
	printf("********************************************\n");
}

int main()
{
	int select = 0;
	Contact contact;
	InitContact(&contact);
	do{
		menu();
		printf("Pleas intput you changce:");
		scanf("%d", &select);

		switch (select)
		{
		case QUIT: 
			printf("Good bye!\n");
			break;
		case ADD:
			AddContact(&contact);
			break;
		case SHOW:
			ShowContact(&contact);
			break;
		case DEL:
			DelContact(&contact);
			break;
		case SEARCH:
			SearchContact(&contact);
			break;
		case EMPTY:
			EmptyContact(&contact);
			break;
		case DESTORY:
			DestoryContact(&contact);
			break;
		case SAVE:
			SaveContact(&contact);
			break;
		case LOAD:
			LoadContact(&contact);
			break;
		default:
			break;
		}
	} while (select);
	system("pause");
	return 0;
}

初始化通讯录

void InitContact(Contact *pcon) {
	//普通版本
	//pcon->usedSize = 0; 
	//memset(pcon->per,0,sizeof(pcon->per));

	pcon->usedsize = 0;
	pcon->capacity = DEFAULT_SIZE;
	pcon->per = (PersonInfo *)malloc(
		sizeof(PersonInfo) * pcon->capacity);
	assert(pcon->per != NULL);

	LoadContact(pcon);//有可能文件中也有存储的联系人
}

加载联系人

void LoadContact(Contact *pcon) {
	FILE *pf = fopen("Contact.bat", "rb");
	PersonInfo tmp = { 0 };
	if (pf == NULL)
	{
		return;
	}
	//fread函数的返回值是:读取成功的字节数
	while (fread(&tmp, sizeof(PersonInfo), 1, pf) > 0)
	{
		//必须判断是否为满,如果满了扩容
		CheckFullAndRe(pcon);
		pcon->per[pcon->usedsize++] = tmp;
	}
	fclose(pf);
	pf = NULL;
}

添加成员

void AddContact(Contact *pcon) {
	//普通版本,无扩容解决办法
	//if(pcon->usedSize == MAX_NUMBER)
	//{
	//	printf("this contact is full\n");
	//	return;
	//}

	if (CheckFullAndRe(pcon) != 1)
	{
		printf("扩容失败\n");
		return;
	}

	printf("请输入姓名:");
	scanf("%s", pcon->per[pcon->usedsize].name);
	printf("请输入年龄:");
	scanf("%d", &(pcon->per[pcon->usedsize].age));
	printf("请输入性别:");
	scanf("%s", pcon->per[pcon->usedsize].sex);
	printf("请输入电话:");
	scanf("%s", pcon->per[pcon->usedsize].tele);
	printf("请输入住址:");
	scanf("%s", pcon->per[pcon->usedsize].addr);
	pcon->usedsize++;
	printf("添加成功\n");
}

打印通讯录

void ShowContact(Contact *pcon) {
	int i = 0;
	printf("%-10s %-5s %-5s %-11s %-20s\n", "姓名", "年龄",
		"性别", "电话", "住址");
	for (i = 0; i < pcon->usedsize; i++)
	{
		printf("%-10s %-5d %-5s %-11s %-20s\n",
			pcon->per[i].name, pcon->per[i].age,
			pcon->per[i].sex, pcon->per[i].tele,
			pcon->per[i].addr);
	}
}

删除成员

void DelContact(Contact *pcon) {
	int index = SearchContact(pcon);
	int i = 0;
	if (index == -1)
	{
		printf("删除失败,查无此人\n");
		return;
	}
	for (i = index; i < pcon->usedsize - 1; i++)
	{
		pcon->per[i] = pcon->per[i + 1];
	}
	pcon->usedsize--;
	printf("删除成功\n");
}

查找成员

int SearchContact(Contact *pcon) {
	int i = 0;
	char name[MAX_NAME] = { 0 };
	if (pcon->usedsize == 0)
	{
		printf("通讯录为空\n");
		return -1;
	}
	printf("请输入你要删除的姓名:");
	scanf("%s", name);
	for (i = 0; i < pcon->usedsize; i++)
	{
		if (strcmp(pcon->per[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

清空通讯录

void EmptyContact(Contact *pcon) {
	pcon->usedsize = 0;
}

摧毁通讯录(动态版本)

void DestoryContact(Contact *pcon) {
	SaveContact(pcon);
	free(pcon->per);
	pcon->per = NULL;//预防野指针  
	pcon->capacity = 0;
	pcon->usedsize = 0;
}

保存联系人到文件(文件版本)

void SaveContact(Contact *pcon) {
	int i = 0;
	FILE *pf = fopen("Contact.bat", "wb");
	assert(pf != NULL);
	for (i = 0; i < pcon->usedsize; i++)
	{
		fwrite(pcon->per + i, sizeof(PersonInfo), 1, pf);
	}
	fclose(pf);
	pf = NULL;
}

所遇问题

通讯录无论是静态版本还是动态版本,储存人数都有上限。

动态内存虽然可以需要多少开辟多少内存,但仍需要在编程中定义。

解决办法

设计一个拓展函数,如果存储不足时,再开辟更多内存。

扩容通讯录

static int CheckFullAndRe(Contact *pcon) {
	if (pcon->usedsize == pcon->capacity)
	{
		PersonInfo * ptr = NULL;
		ptr = (PersonInfo *)realloc(pcon->per,
			sizeof(PersonInfo) * pcon->capacity * 2);
		if (ptr != NULL)
		{
			pcon->per = ptr;
			pcon->capacity *= 2;
			printf("扩容成功\n");
			return 1;
		}
		else
		{
			return 0;//扩容失败
		}
	}

	return 1;
}

项目源码

我的通讯录项目源码:https://github.com/GagaAutom/C-programming-language/blob/master/my_contact/contact

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值