【C语言】实现通讯录

一、项目整体分析

通讯录项目用于针对c语言初学者练手使用,涉及到数组,指针,结构体,枚举等知识。
通讯录需要实现对用户信息的存储,新增,删除,查找,排序,修改等内容,每位用户的信息包含姓名,性别,年龄,电话号码,住址等信息。因此需要创建一个用户信息结构体,结构体成员包含姓名,性别,年龄,电话号码,住址信息。

(1)在初级阶段由于无法让程序自动开辟内存,因此需要额外创建一个结构体,结构体成员包含用户信息成员变量,当前结构体指针变量(用于指向存储位置),成员信息最大存储能力。

(2)当初级阶段实现后,需要利用动态内存管理的方法,使开辟用户信息的内存可以实现自动开辟。

(3)当完成上述两个阶段后,需要利用文件存储的方式,将已经存储在通讯录中的用户信息存储在磁盘中,当打开通讯录文件后,自动读取数据,同时在关闭通讯录时自动保存通讯录。

二、各部分分析

由于实现通讯录项目需要许多头文件和函数,因此需要将项目分为两大部分:头文件和.cpp文件,头文件用于声明一些函数,引入一些库函数,创建一些宏定义和结构体。.cpp文件用于对函数进行实现。

2.1头文件

需要引入两个头文件:一个公共头文件utili.h 一个通讯录头文件contact.h。其中公共头文件引入一些库函数。通讯录头文件负责声明通讯录中需要用到的函数,创建宏定义和结构体

2.2.cpp文件

需要引入两个.cpp文件:一个函数实现文件Contact.cpp 一个主函数文件MainContact.cpp。

三、实现代码

注:(1)表示这段代码是实现项目整体分析中第一个阶段,(2) (3)相同

//utili.h
#ifndef _UTILI_H_
#define _UTILI_H_
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdbool.h>
#include<stdlib.h>
#endif /* _UTILI_H_ */
//
#ifndef _CONTACT_H_
#define _CONTACT_H_


//Contact.h
#include"utili.h"//首先引入公共头文件

enum {QUIT, ADD, DEL, FIND, MODIFY, SHOW, CLEAR, SORT};//定义菜单中的选项

#define MAX_NAME_SIZE 10 		//定义用户姓名最大字符数
#define MAX_SEX_SIZE 3			//定义用户性别最大字符数
#define MAX_AGE_SIZE 100		//定义用户年龄最大数		
#define MAX_TEL_SIZE 12			//定义电话号码最大位数
#define MAX_ADDRESS_SIZE 128	//定义地址信息最大字符数
#define MAX_CONTACT_SIZE 8		//定义最大存储通讯录用户个数(1)
#define DEFAULT_CONTACT_SIZE 2	//定义默认存储通讯录用户个数(2)

//打印菜单
void Menu();

//定义通讯录人员信息
typedef struct PersonInfo
{
	char name[MAX_NAME_SIZE];
	char sex[MAX_SEX_SIZE];
	int age;
	char tel[MAX_TEL_SIZE];
	char address[MAX_ADDRESS_SIZE];
}PersonInfo;

//定义通讯录结构
typedef struct Contact
{
	//PersonInfo cont[MAX_CONTACT_SIZE];(1)
	PersonInfo *cont(2)//需要动态开辟空间,因此设为指针变量
	size_t     capacity;		//通讯录最大存储用户个数
	size_t     size;			//通讯录当前指针指向位置
}Contact;

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

//查验通讯录是否已满
bool IsFullContact(Contact* pcont);

//增加通讯录
void AddContact(Contact* pcont);

//显示通讯录
void ShowContact(Contact* pcont);

//查找通讯录信息
int FindContact(Contact* pcont);

//清除通讯录
void ClearContact(Contact* pcont);

//删除通讯录成员
void DelContact(Contact* pcont);

//修改通讯录成员
void ModifyContact(Contact* pcont);

//对通讯录成员进行排序(bubble)
void SortContact_bubble(Contact* pcont);

//使用快排函数(qsort)
void SortContact_qsort(Contact* pcont);

#endif /* _UTILI_H_ */





//Contact.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"				//引入通讯录头文件


//打印菜单
void Menu()
{
	printf("********************通 讯 录***********************\n");
	printf("*      [1]Add                       [2]Del        *\n");
	printf("*      [3]Find                      [4]Modif      *\n");
	printf("*      [5]Show                      [6]Clear      *\n");
	printf("*      [7]Sort                      [0]Quit       *\n");
	printf("********************通 讯 录***********************\n");
}

//初始化通讯录
void InitContact(Contact* pcont)
{
	assert(pcont != NULL);
	//memset(pcont->cont, 0, sizeof(PersonInfo) * MAX_CONTACT_SIZE);(1)
	pcont->cont = (PersonInfo*)malloc(sizeof(PersonInfo)*DEFAULT_CONTACT_SIZE);(2)
	memset(pcont->cont, 0sizeof(PersonInfo) * DEFAULT_CONTACT_SIZE);(2)
	pcont->capacity = MAX_CONTACT_SIZE;(1)
	pcont->capacity = DEFAULT_CONTACT_SIZE;(2)
	pcont->size = 0;
}

static bool _Inc(Contact* pcont)//(2)
{
	PersonInfo* new_cont = (PersonInfo*)realloc(pcont->cont, sizeof(PersonInfo) * 	pcont->capacity * 2);	//使用realloc进行扩容
	if (new_cont == NULL)
	{
		printf("扩容失败,内存不足\n");
		return false;
	}
	pcont->cont = new_cont;//扩容成功,修改cont指针
	pcont->capacity *= 2;//扩容成功,修改容量
	return true;
}

//判断通讯录是否已满
bool IsFullContact(Contact* pcont)
{
	assert(pcont != NULL);
	return pcont->size >= pcont->capacity;
}

//添加通讯录用户
void AddContact(Contact* pcont)
{
	assert(pcont != NULL);
	//if (IsFullContact(pcont))//(1)
	if(IsFullContact(pcont) && !_Inc(pcont))//(2)
	{
		printf("通讯录空间已满,不能新增信息");
		return;
	}

	printf("姓名:>");
	scanf("%s", pcont->cont[pcont->size].name);
	printf("性别:>");
	scanf("%s", pcont->cont[pcont->size].sex);
	printf("年龄:>");
	scanf("%d", &pcont->cont[pcont->size].age);
	printf("电话号码:>");
	scanf("%s", pcont->cont[pcont->size].tel);
	printf("地址:>");
	scanf("%s", pcont->cont[pcont->size].address);

	pcont->size++;
	printf("添加完成!!!\n");
}

//展示当前通讯录已存用户信息
void ShowContact(Contact* pcont)
{
	assert(pcont != NULL);
	printf("***************************************************\n");
	printf("*%-8s%-7s%-6s%-13s%s\n", "姓名", "性别", "年龄", "电话", "地址");
	for (int i = 0; i < pcont->size; i++)
	{
		printf("*%-8s%-7s%-6d%-13s%s\n",pcont->cont[i].name,  
										pcont->cont[i].sex, 
										pcont->cont[i].age, 
										pcont->cont[i].tel, 
										pcont->cont[i].address);
	} 
}

//查找通讯录成员
int FindContact(Contact* pcont)
{
	assert(pcont != NULL);
	printf("请输入要查找的姓名:>");
	char name[MAX_NAME_SIZE] = {0};
	scanf("%s", name);
	for (int i = 0; i < pcont->size; i++)
	{
		if (strcmp(pcont->cont[i].name, name) == 0)
		{
			printf("*%-8s%-7s%-6s%-13s%s\n", "姓名", "性别", "年龄", "电话", "地址");
			printf("*%-8s%-7s%-6d%-13s%s\n",pcont->cont[i].name,
											pcont->cont[i].sex,
											pcont->cont[i].age,
											pcont->cont[i].tel,
											pcont->cont[i].address);
			return i;
		}
	}
	printf("对不起,没找到\n");
	return -1;
}

//清除通讯录
void ClearContact(Contact* pcont)
{
	assert(pcont != NULL);
	pcont->size = 0;
	printf("清除完成!!!\n");
}

//删除通讯录成员
void DelContact(Contact* pcont)
{
	assert(pcont != NULL);
	printf("请输入要删除的名字:>");
	char name[MAX_NAME_SIZE] = { 0 };
	scanf("%s", name);
	int i;
	for (i = 0; i < pcont->size; i++)
	{
		if (strcmp(pcont->cont[i].name, name) == 0)
			break;
	}
	if (i >= pcont->size)
	{
		printf("对不起,您所删除的名字不存在\n");
		return;
	}
	for (int k = i; k < pcont->size - 1; k++)
		pcont->cont[k] = pcont->cont[k + 1];
	pcont->size--;
	printf("删除完成!!!\n");
}

//修改通讯录成员
void ModifyContact(Contact* pcont)
{
	assert(pcont != NULL);
	printf("请输入要修改的名字:>");
	char name[MAX_NAME_SIZE] = { 0 };
	scanf("%s", name);
	int i;
	for (i = 0; i < pcont->size; i++)
	{
		if (strcmp(pcont->cont[i].name, name) == 0)
			break;
	}
	if (i >= pcont->size)
	{
		printf("对不起,您所要修改的名字不存在\n");
		return;
	}
	printf("你要修改什么信息(1-姓名 2-性别 3-年龄 4-电话 5-住址)\n");
	int select;
	scanf("%d", &select);
	switch (select)
	{
	case 1:
		printf("请输入要修改的名字:>");
		scanf("%s", pcont->cont[i].name);
		break;
	case 2:
		printf("请输入要修改的性别:>");
		scanf("%s", pcont->cont[i].sex);
		break;
	case 3:
		printf("请输入要修改的年龄:>");
		scanf("%d", &pcont->cont[i].age);
		break;
	case 4:
		printf("请输入要修改的电话:>");
		scanf("%s", pcont->cont[i].tel);
		break;
	case 5:
		printf("请输入要修改的住址:>");
		scanf("%s", pcont->cont[i].address);
		break;
	}
	printf("修改完成!!!\n");
}

//对通讯录成员进行排序
//方法一利用冒泡排序
void SortContact_bubble(Contact* pcont)
{	
	//采用冒泡排序
	assert(pcont != NULL);
	//qsort(pcont, pcont->size, sizeof(pcont->cont[0]), compar);
	for (int i = 0; i < pcont->size-1; i++)
	{
		for (int j = 0; j < pcont->size - 1 - i; j++)
		{
			if (strcmp(pcont->cont[j].name, pcont->cont[j + 1].name) > 0 )
			{
				PersonInfo tmp = pcont->cont[j];
				pcont->cont[j] = pcont->cont[j + 1];
				pcont->cont[j + 1] = tmp;
			}
		}
	}
	printf("排序完成!!!\n");
}

//方法二利用快排函数
int compar_name(Contact* pcont->cont.name1, pcont->cont.name2)
{
	return strcmp(pcont->cont.name1, pcont->cont.name2);
}

void SortContact_qsort(Contact* pcont)
{
	assert(pcont != NULL);
	qsort(pcont, pcont->size, sizeof(pcont->cont[0]), compar_name);
}

//摧毁通讯录目的是为了防止内存泄漏
void DestoryContact(Contact* pcont)
{
	assert(pcont != NULL);
	free(pcont->cont);//释放内存
	pcont->cont = NULL;//预防野指针

	pcont->capacity = pcont->size = 0;

}

//存储通讯录(3)
void SaveContact(Contact* pcont)
{
	assert(pcont != NULL);
	FILE* fp = fopen("cont.dat", "w");
	if (fp == NULL)
	{
		printf("写入通讯录文件失败\n");
		return;
		
	}
	for (int i = 0; i < pcont->size; i++)
	{
		fprintf(fp, "*%-8s%-7s%-6d%-13s%s\n", pcont->cont[i].name,
			pcont->cont[i].sex,
			pcont->cont[i].age,
			pcont->cont[i].tel,
			pcont->cont[i].address);
	}
	fclose(fp);
}

//数据的加载(3)
void LoadContact(Contact* pcont)
{
	assert(pcont != NULL);

	FILE* fp = fopen("\cont.dat", "r");
	if (fp == NULL);
	{
		printf("读取通讯录文件失败\n");
		return;
	}
	int idx = 0;
	while(1)
	{
		if (IsFullContact(pcont) && !_Inc(pcont))
			break;
		int res = fscanf(fp, "*%s %s %d %s %s\n", pcont->cont[idx].name,
										pcont->cont[idx].sex,
										&pcont->cont[idx].age,
										pcont->cont[idx].tel,
										pcont->cont[idx].address);
		if (res == EOF)
			break;
		idx++;
		pcont->size++;
	}
	fclose(fp);
}


//MainContact.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"//引入通讯录头文件

void main()
{
	Contact cont;//先进行通讯录的创建和初始化
	InitContact(&cont);

	int select = 1;
	while (select)
	{
		Menu();				//打印开始菜单
		printf("请选择:>");
		scanf("%d", &select);

		if (select == QUIT)
			break;
		switch (select)
		{
		case ADD:
			IsFullContact(&cont); //判断通讯录是否已满
			AddContact(&cont);	  //添加用户信息
			break;
		case DEL:
			DelContact(&cont);	  //删除用户信息
			break;
		case FIND:
			FindContact(&cont);		//查找用户信息
			break;
		case MODIFY:
			ModifyContact(&cont);	//修改用户信息
			break;
		case SHOW:
			ShowContact(&cont);     //展示通讯录内容
			break;
		case CLEAR:
			ClearContact(&cont);	//清除通讯录
			break;
		case SORT:
			SortContact_bubble(&cont);	//对通讯录进行排序
			break;

		}
	}
	SaveContact(&cont);
	DestoryContact(&cont);
}

四、效果展示

开始运行

选择1,添加用户
在这里插入图片描述
选择5,展示
在这里插入图片描述
选择4,修改用户信息
在这里插入图片描述
选择2,删除用户信息
在这里插入图片描述
选择7,对用户信息进行排序,注意(这里的排序是通过冒泡排序对用户姓名进行排序,用户姓名排序的原理是利用其对应的ASCII码值进行排序),通过对排序函数的修改,可以实现通过年龄,电话住址等信息进行排序。
在这里插入图片描述
选择3,进行信息查找
在这里插入图片描述
如果查找的姓名不存在,会报找不到的错误在这里插入图片描述

一、题目:通讯录管理 二、目的与要求 1. 目的: (1)基本掌握面向过程程序设计的基本思路和方法; (2)达到熟练掌握C语言的基本知识和技能; (3)能够利用所学的基本知识和技能,解决简单的程序设计问题 2. 要求 基本要求: 1. 要求利用C语言面向过程的编程思想来完成系统的设计; 2. 突出C语言的函数特征,以多个函数实现每一个子功能; 3. 画出功能模块图; 4. 具有清晰的程序流程图和数据结构的详细定义; 5. 熟练掌握C语言对文件的各种操作。 创新要求: 在基本要求达到后,可进行创新设计,如系统用户功能控制,对管理员级和一般级别的用户系统功能操作不同 三、信息描述 有关该系统基本信息的描述,如:姓名、电话、城市和邮编等。 四、功能描述 1. 名单基本信息姓名,城市,电话,邮编等)的录入,并存放在文件当中。 2. 基本信息的查询与修改。 3. 记录的添加和删除。 4. 对同一类型记录的查找:如查找同一城市的记录或同一省份的记录。 五、解决方案 1. 分析程序的功能要求,划分程序功能模块。 2. 画出系统流程图。 3. 代码的编写。定义数据结构和各个功能子函数。 4. 程序的功能调试。 5. 完成系统总结报告以及使用说明书 六、进度安排 此次课程设计时间为一周或两周,分四个阶段完成: 1. 分析设计阶段。指导教师应积极引导学生自主学习和钻研问题,明确设计要求,找出实现方法,按照需求分析、总体设计、详细设计这几个步骤进行。 2. 编码调试阶段:根据设计分析方案编写C代码,然后调试该代码,实现课题要求的功能。 3. 总结报告阶段:总结设计工作,写出课程设计说明书,要求学生写出需求分析、总体设计、详细设计、编码、测试的步骤和内容。 4. 考核阶段。 七、撰写课程设计报告或课程设计总结 课程设计报告要求: 总结报告包括需求分析、总体设计、详细设计、编码(详细写出编程步骤)、测试的步骤和内容、课程设计总结、参考资料等,不符合以上要求者,则本次设计以不及格记。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值