C语言程序设计—通讯录实现

本篇文章主要是实现一个简易的通讯录:

功能如下:

  1. 添加用户
  2. 修改用户
  3. 删除用户
  4. 查找用户(可重名)
  5. 按名字或年龄排序
  6. 显示用户
  7. 保存通讯录
  8. 日志追加

有如下知识点:

  1. 动态数组
  2. 结构体
  3. 枚举
  4. 自定义标识符和宏
  5. 文件打开与存储
  6. 函数
  7. 指针
  8. 循环
  9. 排序

简述特点:

  1. 将人员信息放在一个PeoInf的结构体中,再创建一个结构体List,用于存放peoinf这个结构体的指针,和容量与目前通讯录人员数量。
  2. 再用realloc动态开辟以结构体peoinf为大小的内存,用于实现动态内存开辟。
  3. 程序运行后,初始化这段空间,并查询是否有"contact.txt"的文件存在,如果存在,则读取文件里的内容,并放到peoinf的结构体"数组"中,并实时监控是否需要扩容。如果不存在就创建文件。
  4. 随后就可以添加、修改、查找、删除用户,每一次增删改查都会被记录到一个"contact_log.txt"的文件里,这里使用了时间戳。
  5. 用qsort进行名字或年龄进行排序
  6. 程序会知道本次是否进行修改,如果修改后就退出会提示是否需要保存,当然也可以自己手动保存。
  7. 程序以"rb"和"wb"进行文件的读写。
  8. 程序实现了重名查找,在有重名的情况下会进行选择。
  9. (代码可直接运行,复制到编译器vs2019即可)

代码部分

contact.h

cpp 复制代码
#pragma once
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <time.h>
#include <sys/stat.h>

#define MAX_10 10
#define MAX_20 20
//#define LOG_PRINT(x) fprintf(pf, "In %s %s ,user %s name calling %s\n",__DATE__,__TIME__,(x),(list->pl+num)->name)
typedef struct PeoInf
{
	char name[MAX_20];
	int age;
	char sex[5];
	char tel[12];
	char addr[30];
}PeoInf;
//定义通讯录结构体,嵌套PeoInf
typedef struct List
{
	//动态内存分配
	PeoInf* pl;
	int count;
	int capacity;//容量
}List;
//定义一个枚举变量,用于存储菜单所有选择
enum select_all
{
	EXIT,//0
	ADD,
	DEL,
	SELECT,
	MODIFY,
	SORT,
	SHOW,
	SAVE
};
//菜单函数
void menu();
//定义初始化list函数
void initialise_list(List* list);
//定义添加信息函数
void add_peoinf(List* list);
//定义显示函数
void show_list(List* list);
//定义删除函数
void del_peoinf(List* list);
//定义通过找名字查找人的函数(已实现重名查找)
int find_byname(const List* list);
//定义查找人
void sele_peoinf(const List* list);
//定义修改人信息函数
void modify_peoinf(List* list);
//定义删除和修改已找到下标的信息函数
void del_havefond(List* list, int position);
void modify_havefond(List* list, int position);
//定义排序函数
void sort_peoinf(List* list);
//定义文件保存函数
void file_save(List* list);
//定义扩容函数
void expand_list(List* list);

actualize.c

cpp 复制代码
#include "contact.h"
//实现菜单函数
void menu(){
	printf("----------------------------------------\n");
	printf("--------1. add      2. del--------------\n");
	printf("--------3. select   4. modify-----------\n");
	printf("--------5. sort     6. show-------------\n");
	printf("--------------7. save-------------------\n");
	printf("--------------0. exit-------------------\n");
	printf("----------------------------------------\n");
}
//实现初始化list函数
void initialise_list(List* list){
	PeoInf* ptr = (PeoInf*)calloc(3, sizeof(PeoInf));//默认开辟三个人的存储空间
	if (ptr == NULL) {
		printf("%s", strerror(errno));
		return ;
	}
	list->pl = ptr;
	list->count = 0;
	list->capacity = 3;
	FILE* pf = NULL;
	struct stat buffer;//判断文件是否存在
	if (stat("contact.txt", &buffer) != 0) {//不存在就创建文件
		pf = fopen("contact.txt", "wb");
		fclose(pf);
		pf = NULL;
		return;
	}
	pf = fopen("contact.txt", "rb");
	if (pf != NULL) {
		for (int i = 0; fread(list->pl + i, sizeof(PeoInf), 1, pf) != 0; i++) {
			if (list->count == list->capacity - 1) {
				expand_list(list);
			}
			list->count++;
		}
		fclose(pf);
	}
	pf = NULL;
}
//扩容函数
void expand_list(List* list) {
	PeoInf* ptr =(PeoInf*) realloc(list->pl, (list->capacity + 2)*sizeof(PeoInf));//每次增加两个
	if (ptr == NULL) {
		printf("%s", strerror(errno));
		return;
	}
	list->pl = ptr;
	list->capacity += 2;
}
//实现添加日志功能
/*
* return 0 失败
* return 1 成功
*/
int add_log(List* list,char* moving,int num) {
	//打开文件
	FILE* pf=NULL;
	//判断写入模式是否要追加
	if (list->count == 0) {
		pf = fopen("contact_log.txt", "w");
	}
	else {
		pf = fopen("contact_log.txt", "a");
	}
	//如果打开失败,报错
	if (pf == NULL) {
		perror("fopen:");
		return 0;
	}
	//获取时间戳
	time_t rawtime;
	struct tm* timeinfo;
	time(&rawtime);
	timeinfo = localtime(&rawtime);
	fprintf(pf, "In %s \tuser %s name calling %s.\n", asctime(timeinfo), moving, (list->pl + num)->name);
	fclose(pf);
	pf = NULL;
	return 1;
}
//实现添加信息功能
void add_peoinf(List* list) {
	assert(list);//断言
	//判断是否需要扩容
	if (list->count == list->capacity) {
		expand_list(list);//内部函数,不必去头文件里定义
		printf("Automatic capacity expansion is successful,\n and the current address book capacity is %d\n", list->capacity);
	}
	printf("Please enter the name\n->");
	scanf("%s", (list->pl+list->count)->name);
	printf("Please enter age\n->");
	scanf("%d", &(list->pl + list->count)->age);
	printf("Please enter sex\n->");
	scanf("%s", (list->pl + list->count)->sex);
	printf("Please enter the telephone\n->");
	scanf("%s", (list->pl + list->count)->tel);
	printf("Please enter the address\n->");
	scanf("%s", (list->pl + list->count)->addr);
	//添加日志log功能
	if (!add_log(list,"add",list->count)) {
		printf("log fail,please find excause.\n");
	}
	list->count++;
	printf("succeed!\n");
}
//实现显示函数
void show_list(List* list) {
	assert(list);
	printf("name\tage\tsex\ttelephone\taddr\n");
	for (int i = 0; i < (list->count); i++) {
		printf("%s\t%d\t%s\t%s\t\t%s\n", (list->pl + i)->name,
			(list->pl + i)->age, (list->pl + i)->sex, (list->pl + i)->tel, (list->pl + i)->addr);
	}
}
//实现通过寻找名字,找到这个人
//重名默认存放数组为10,如需变大可改为动态扩容实现
int find_byname(const List* list) {
	char s_name[MAX_20] = { 0 };
	int count = 0;
	int find_result[MAX_10] = { 0 };
	printf("Please enter the name that you want \n->");
	scanf("%s", s_name);
	for (int i = 0; i < list->count; i++) {
		if (strcmp((list->pl + i)->name, s_name)==0) {
			//找到了
			if (count == 0) {
				printf("Find the information, please confirm\n");
				printf("number\tname\tage\tsex\ttelephone\taddr\n");
			}
			printf("%d\t%s\t%d\t%s\t%s\t\t%s\n", count+1,(list->pl + i)->name,
				(list->pl + i)->age, (list->pl + i)->sex, (list->pl + i)->tel, (list->pl + i)->addr);
			find_result[count] = i;//将找到的坐标存入数组中
			count++;//判断是否有重复
		}
	}
	if (count == 0) {
		//找不到
		printf("Check no such person, please confirm after the input!\n");
		return -1;
	}
	else if (count == 1) {
		return find_result[0];
	}
	else {//两个以上
		int select_num = 0;
		while (1) {
			printf("Please select the object serial number that you want to operate on\n->");
			scanf("%d", &select_num);
			if (select_num >= 1 && select_num <= count) {//输入正确序号,方可返回
				return find_result[select_num - 1];
			}
			else {
				printf("error,please reenter\n");
			}
		}
	}
}
//实现删除函数
void del_peoinf(List* list) {
	assert(list);
	int del_num = find_byname(list);
	if (del_num < 0) return;//查找失败
	for (int i = 0; i < list->count - del_num - 1; i++) {
		*(list->pl + del_num + i) = *(list->pl + del_num + 1 + i);
	}
	list->count--;
	printf("delet successfully\n");
	if (!add_log(list, "delet", del_num)) {
		printf("log fail,please find excause.\n");
	}
}
void del_havefond(List* list,int position) {
	assert(list);
	for (int i = 0; i < list->count - position - 1; i++) {
		*(list->pl + position + i) = *(list->pl + position + 1 + i);
	}
	list->count--;
	printf("delet successfully\n");
	if (!add_log(list, "delet", position)) {
		printf("log fail,please find excause.\n");
	}
}
//实现查找信息功能
void sele_peoinf(const List* list) {
	assert(list);
	int find_num = find_byname(list);
	if (find_num < 0) return;//查找失败
	printf("The information is as follows\n");
	printf("name\tage\tsex\ttelephone\taddr\n");
	printf("%s\t%d\t%s\t%s\t\t%s\n", (list->pl + find_num)->name,
		(list->pl + find_num)->age, (list->pl + find_num)->sex, (list->pl + find_num)->tel, (list->pl + find_num)->addr);
	int input_find = 0;
	do {
		printf("--------------------------------\n");
		printf("--------------------------------\n");
		printf("-----1. del-------2. modif------\n");
		printf("------------0. exit-------------\n");
		printf("--------------------------------\n");
		printf("--------------------------------\n");
		printf("please enter what you want\n->");
		scanf("%d", &input_find);
		if (input_find == 1) {
			del_havefond(list, find_num);
			return;
		}
		else if (input_find == 2) {
			modify_havefond(list, find_num);
			return;
		}
		else if (input_find != 0) {
			printf("Input is wrong, please reagain\n");
		}
	} while (input_find);

}
void modify_havefond(List* list,int position) {
	assert(list);
	printf("Please enter the new name\n->");
	scanf("%s", (list->pl + position)->name);
	printf("Please enter new age\n->");
	scanf("%d", &(list->pl + position)->age);
	printf("Please enter new sex\n->");
	scanf("%s", (list->pl + position)->sex);
	printf("Please enter the new telephone\n->");
	scanf("%s", (list->pl + position)->tel);
	printf("Please enter the new address\n->");
	scanf("%s", (list->pl + position)->addr);
	printf("Modified successfully\n");
	if (!add_log(list, "modify", position)) {
		printf("log fail,please find excause.\n");
	}
}
//实现修改信息
void modify_peoinf(List* list) {
	assert(list);
	int mod_num = find_byname(list);
	if (mod_num < 0) return;//查找失败
	printf("Please enter the new name\n->");
	scanf("%s", (list->pl + mod_num)->name);
	printf("Please enter new age\n->");
	scanf("%d", &(list->pl + mod_num)->age);
	printf("Please enter new sex\n->");
	scanf("%s", (list->pl + mod_num)->sex);
	printf("Please enter the new telephone\n->");
	scanf("%s", (list->pl + mod_num)->tel);
	printf("Please enter the new address\n->");
	scanf("%s", (list->pl + mod_num)->addr);
	printf("Modified successfully\n");
	if (!add_log(list, "modify",mod_num)) {
		printf("log fail,please find excause.\n");
	}
}
//qsort的比较函数
int compare_name(const void* e1,const void* e2) {
	return strcmp(((PeoInf*)e1)->name, ((PeoInf*)e2)->name);

}
int compare_age(const void* e1, const void* e2) {
	return ((PeoInf*)e1)->age - ((PeoInf*)e2)->age;

}
//实现排序函数
void sort_peoinf(List* list) {
	int sort_input = 0;
	do {
		printf("--------------------------------\n");
		printf("--------------------------------\n");
		printf("-----1. name-------2. age------\n");
		printf("------------0. exit-------------\n");
		printf("--------------------------------\n");
		printf("--------------------------------\n");
		printf("please enter you want sort by\n->");
		scanf("%d", &sort_input);
		if (sort_input == 1) {
			qsort(list->pl, list->count, sizeof(PeoInf), compare_name);
			printf("sort by name successfully\n");
			return;
		}
		else if (sort_input == 2) {
			qsort(list->pl, list->count, sizeof(PeoInf), compare_age);
			printf("sort by age successfully\n");
			return;
		}
	} while (sort_input);
	
}
void file_save(List *list) {
	FILE* pf = fopen("contact.txt", "wb");//二进制写入
	if (pf == NULL) {
		perror("fopen:");
		return;
	}
	//写数据
	for (int i = 0; i < list->count; i++) {
		fwrite(list->pl+i, sizeof(PeoInf), 1, pf);
	}
	fclose(pf);
	pf = NULL;
}

test.c

cpp 复制代码
#include "contact.h"
int main()
{
	int input = 0;
	List list;
	initialise_list(&list);//动态内存开辟,记得用完销毁
	int modify_num = 0;//修改数量记录
	do{
		menu();
		printf("Please choose!\n->");
		scanf("%d", &input);
		switch (input)
		{
		case ADD: 
		{
			add_peoinf(&list);
			modify_num++;
		}break;
		case DEL:
		{
			del_peoinf(&list);
			modify_num++;
		}break;
		case SELECT:
		{
			sele_peoinf(&list);
		}break;
		case MODIFY:
		{
			modify_peoinf(&list);
			modify_num++;
		}break;
		case SORT:
		{
			sort_peoinf(&list);
		}break;
		case SHOW:
		{
			show_list(&list);
		}break;
		case SAVE:
		{
			file_save(&list);
			printf("save in file sucessfully\n");
			modify_num = 0;
		}break;
		case EXIT:
		{
			if (modify_num != 0) {
				int save_select = 0;
				printf("=========1.save   2.no=============\n");
				printf("The modified data is not saved, whether it needs to be saved\n->");
				scanf("%d", &save_select);
				if (save_select == 1) {
					file_save(&list);
					printf("save in file sucessfully\n");
				}
			}
			printf("Ok,have a nice day! Bye~");
		}break;
		default:
			printf("Input is wrong,please reagain!\n");
			break;
		}
	} while (input);
	//销毁动态内存
	free(list.pl);
	list.pl = NULL;
}

希望对大家有帮助!

相关推荐
代码小鑫13 分钟前
A032-基于Spring Boot的健康医院门诊在线挂号系统
java·开发语言·spring boot·后端·spring·毕业设计
训山21 分钟前
4000字浅谈Java网络编程
java·开发语言·网络
API快乐传递者22 分钟前
除了网页标题,还能用爬虫抓取哪些信息?
开发语言·爬虫·python
hutaotaotao1 小时前
c语言用户不同命令调用不同函数实现
c语言·开发语言
huangjiazhi_1 小时前
QTcpSocket 服务端和客户端
开发语言·qt
lb36363636361 小时前
介绍一下位操作符(c基础)
c语言·知识点
ac-er88881 小时前
ThinkPHP中的MVC分层是什么
开发语言·php·mvc
shinelord明2 小时前
【再谈设计模式】建造者模式~对象构建的指挥家
开发语言·数据结构·设计模式
黑不拉几的小白兔2 小时前
PTA部分题目C++重练
开发语言·c++·算法
写bug的小屁孩2 小时前
websocket身份验证
开发语言·网络·c++·qt·websocket·网络协议·qt6.3