当前位置: 首页 > news >正文

C语言 — 通讯录模拟实现

目录

  • 1.创建contact.h,contact.c,test.c三个文件
    • 1.1 contact.h文件
    • 1.2 contact.c文件实现函数的定义
    • 1.3 test.c文件
  • 2.InitidContact初始化函数
  • 3.Add函数
  • 4.Show函数
  • 5.Delete函数
  • 6.Search函数
  • 7.Modify函数
  • 8.Sort函数
  • 9.修改为动态版本
  • 10.修改为文件版本
  • 11.程序代码展示
    • 11.1.contact.h文件
    • 11.2.contact.c文件
    • 11.3.test.c文件

1.创建contact.h,contact.c,test.c三个文件

1.1 contact.h文件

1.需要包含头文件;
2.#define定义的常量;
3.#pragma指令的包含;
4.结构体的创建;
5.函数的声明;

//防止头文件多次包含
#pragma once//防止函数报不安全警告
#pragma warning(disable:4996)//头文件的包含#include<stdio.h>//#define定义的常量#define MAX 50 //假设最大容量是50个
#define MAX_NAME 20//名字存放的大小
#define MAX_SEX 6//性别存放的大小
#define MAX_TELE 12//类型方式存放的大小
#define MAX_ADDR 20//地址存放的大小//创建一个存放人信息的结构体
typedef struct PeoInf
{char name[MAX_NAME];//名字int age;//年龄char sex[6];char tele[MAX_TELE];//联系方式char addr[MAX_ADDR];//地址}PeoInf;//类型重定义为PeoInf//创建一个通讯录结构体
typedef struct Contact
{int count;//记录当前存放的个数PeoInf data[MAX];//结构体数组}Contact;//类型重定义为Contact

1.2 contact.c文件实现函数的定义

#include "contact.h"//包含自定义头文件

1.3 test.c文件

1.实现menu菜单函数;
2.使用枚举完成替换;
3.使用switch分支实现功能的选择;

#include "contact.h"//包含自定义头文件//菜单:增删查改,展示,排序,退出
void menu()
{printf("************************************\n");printf("*******  1.Add       2.Delete   ****\n");printf("*******  3.Search    4.Modify   ****\n");printf("*******  5.Show      6.Sort     ****\n");printf("*******  0.Exit                 ****\n");printf("************************************\n");
}//枚举常量替换
enum
{EXIT,//0ADD,//1DELETE,//2SEARCH,//3MODIFY,//4SHOW,//5SORT//6
};int main()
{int input = 0;do {menu();printf("请选择:>");(void)scanf("%d", &input);switch (input){case ADD:	break;case DELETE:break;case SEARCH:break;case MODIFY:break;case SHOW:break;case SORT:break;case EXIT:printf("退出程序中...\n");break;default:printf("请重新选择!\n");}} while (input);return 0;
}

2.InitidContact初始化函数

在test.c文件中创建一个Contact结构体变量 con,并在该文件中调用InitidContact函数。

int main()
{int input = 0;//功能选择Contact con;//创建通讯录的变量//初始化函数InitidContact(&con);//指针传参//多次选择do {menu();printf("请选择:>");void)scanf("%d", &input);switch (input){case ADD:	break;case DELETE:break;case SEARCH:break;case MODIFY:break;case SHOW:break;case SORT:break;case EXIT:printf("退出程序中...\n");break;default:printf("请重新选择!\n");}} while (input);return 0;
}

在contact.c文件事项该函数的定义,需要使用assert函数和memset函数。

#include "contact.h"//包含自定义头文件void InitidContact(Contact* con)
{assert(con);//保证con不为空指针//初始化:使用memset函数memset(con,0, MAX * sizeof(Contact));
}

contact.h文件需要包含assert和memset函数需要的头文件和初始化函数的定义。

//防止头文件多次包含
#pragma once//防止函数报不安全警告
#pragma warning(disable:4996)//头文件的包含#include<stdio.h>//标准输入输出需要的头文件
#include<assert.h>//断言函数需要的头文件
#include<string.h>//memset函数和字符串函数需要的文件//#define定义的常量#define MAX 50 //假设最大容量是50个
#define MAX_NAME 20
#define MAX_SEX 6
#define MAX_TELE 12
#define MAX_ADDR 20//创建一个存放人信息的结构体
typedef struct PeoInf
{char name[MAX_NAME];//名字int age;//年龄char sex[6];//性别char tele[MAX_TELE];//联系方式char addr[MAX_ADDR];//地址}PeoInf;//类型重定义为PeoInf//创建一个通讯录结构体
typedef struct Contact
{int count;//记录当前存放的个数PeoInf data[MAX];//结构体数组}Contact;//类型重定义为Contact//函数的声明//初始化函数
void InitidContact(Contact* con);

此时可以按F10启动调试查询能否初始化数据,可以打开监视窗口观察。

在这里插入图片描述

3.Add函数

在contact.h文件中包含Add函数的声明。

//Add函数
void Add(Contact* con);

在contact.c文件实现文件的定义

//Add函数的定义
void Add(Contact* con)
{assert(con);//判断当前存放的个数是否满了if (con->count == MAX){//此时不能存放,终止增加printf("当前容量已满,不可创建,退出中.......\n");return;}//此时容量未满,可以增加//找到当前数组的位置printf("请输入名字:>");scnaf("%s", con->data[con->count].name);//字符串数组名标识地址不需要&printf("请输入年龄:>");scnaf("%s", &(con->data[con->count].age));//age是变量需要&printf("请输入性别:>");scnaf("%s", con->data[con->count].sex);printf("请输入联系方式:>");scnaf("%s", con->data[con->count].tele);printf("请输入地址:>");scnaf("%s", con->data[con->count].addr);//此时增加成功,将count++con->count++;//提示一下,增加成功printf("输入的信息已经保存\n");
}

在test.c文件调用Add函数。

	do {menu();printf("请选择:>");(void)scanf("%d", &input);switch (input){case ADD:	Add(&con);//调用Add函数break;case DELETE:break;case SEARCH:break;case MODIFY:break;case SHOW:break;case SORT:break;case EXIT:printf("退出程序中...\n");break;default:printf("请重新选择!\n");}} while (input);

4.Show函数

实现Add函数后需要将Add含增加的信息展示,使用Show函数输出对应的信息。

contact.h文件实现函数声明。

//Show函数
void Show(Contact* con);

contact.c文件实现函数的定义

//Show函数的定义
void Show(Contact* con)
{assert(con);//con不为空指针//判断count是否为0if (con->count == 0){printf("没有信息,不可展示!\n");return;//结束Show函数}//打印标题行:-表示左对齐,\t是间隔8个水平制表位printf("%-20s%-5s\t%-6s\t%-12s\t%s\n","名字","年龄","性别","联系方式","地址");//使用for循环遍历输出打印int i = 0;//从下标为0的元素开始for (i = 0; i < con->count; i++){printf("%-20s%-5d\t%-6s\t%-12s\t%s\n", con->data[i].name,con->data[i].age, con->data[i].sex,con->data[i].tele, con->data[i].addr);}
}

test.c文件实现Show函数的调用

	do {menu();printf("请选择:>");(void)scanf("%d", &input);switch (input){case ADD:	Add(&con);//调用Add函数break;case DELETE:break;case SEARCH:break;case MODIFY:break;case SHOW:Show(&con);//调用Show函数break;case SORT:break;case EXIT:printf("退出程序中...\n");break;default:printf("请重新选择!\n");}} while (input);

按Ctrl + F5开始调试不执行,测试当前的增加和展示.

在这里插入图片描述

5.Delete函数

Delete函数是将指定用户的信息进行删除,需要先输入指定的删除对象,实现一个FindName函数查询该用户是是否存在,如果存在将指定用户删除后进行覆盖,进入不存在输出提示信息。

contact.h文件实现函数的声明和头文件的包含

#include<string.h>//memset函数和strcmp函数的头文件
void contact(Contact* con)//函数声明

contact.c文件实现函数的定义。

int FindName(Contact*con,const char* tem)
{assert(tem);//此时con已经在Delet数组中调用,不需要判断con//使用数组遍历查找int i = 0;for (i = 0; i < con->count; i++){//判断名字是否相等,使用strcmp函数//头文件是#include<string.h>if(strcmp(con->data[i].name,tem) == 0)return i;//表示找到,返回下标}return -1;//遍历数组后还找不到返回-1
}//Delete函数的定义
void Delete(Contact* con)
{assert(con);//判断con不为空指针char tem[20] = { 0 };printf("请输入需要删除的对象:>");scanf("%s", tem);//1.需要找到删除的对象,需要实现一个查找函数;int r = FindName(con, tem);//2.判断是否找到//如果找到了进行覆盖if (r != -1)//找到了,通过后一个信息覆盖前一个信息完成删除{	//使用for循环遍历数组//从下标为r的数组元素开始覆盖for (; r < con->count - 1; r++)//count - 1表示数组倒数第二个元素{//count - 1表示数组倒数第二个元素,防止数组越界//memcpy函数的头文件是#include<string.h>memcpy(con->data + r, con->data + r + 1, sizeof(PeoInf));//memcpy是内存块拷贝函数,第一个参数是下标为r的元素的起始地址//第二个元素是r + 1下标元素的起始地址,第三个参数是拷贝元素的//大小,刚刚好是一个人信息结构体大小。}}//找不到,输出原因,并退出函数else{printf("输入的用户信息不存在,请稍后尝试!\n");return;}//3.count--,此时的用户信息删除了一个,用户信息减一con->count--;//4.提示一下删除成功printf("输入的用户信息删除成功!\n");
}

test.c文件调用Delete函数。

//多次选择
do 
{menu();printf("请选择:>");(void)scanf("%d", &input);switch (input){case ADD:	Add(&con);//调用Add函数break;case DELETE:Delete(&con);//调用删除函数break;case SEARCH:break;case MODIFY:break;case SHOW:Show(&con);//调用Show函数break;case SORT:break;case EXIT:printf("退出程序中...\n");break;default:printf("请重新选择!\n");}
} while (input);

按Ctrl + F5启动调试测试是否能够删除。

在这里插入图片描述

选择删除功能,删除李四的信息,然后调用Show函数.

在这里插入图片描述

6.Search函数

Search函数的作用是查找指定用户,使用已经实现的FindName函数,如果存在指定用户,将用户信息输出展示,如果指定用户不存在,输出提示信息。

contact.h文件实现Search函数的声明。

//Search函数的声明
void Search(Contact* con);

contact.c文件实现Search函数的定义。

void Search(Contact* con)
{assert(con);//判断con不为NULL//前面的Delete函数已经实现了查找函数//此处可以调用该函数判断是否存在该用户信息//如果存在,将该用户信息输入即可//1.输入需要查找的对象char tem[20] = { 0 };printf("请输入需要查找的对象:>");scanf("%s", tem);//2.查找是否存在int r = FindName(con, tem);//存在输入打印if (r != -1){//找到了,提示一下printf("输入的用户存在,正在加载中....\n");//使用Show函数的格式输出//打印标题行:-表示左对齐,\t是间隔8个水平制表位printf("%-20s%-5s\t%-6s\t%-12s\t%s\n", "名字", "年龄", "性别", "联系方式", "地址");//指定格式输出printf("%-20s%-5d\t%-6s\t%-12s\t%s\n", con->data[r].name,con->data[r].age, con->data[r].sex,con->data[r].tele, con->data[r].addr);}//不存在,提示一下,并结束函数else{printf("输入的用户不存在!\n");return ;//结束函数}
}

test.c实现函数的调用

//多次选择
do 
{menu();printf("请选择:>");(void)scanf("%d", &input);switch (input){case ADD:	Add(&con);//调用Add函数break;case DELETE:Delete(&con);//调用删除函数break;case SEARCH:Search(&con);//调用查找函数break;case MODIFY:break;case SHOW:Show(&con);//调用Show函数break;case SORT:break;case EXIT:printf("退出程序中...\n");break;default:printf("请重新选择!\n");}
} while (input);

按Ctrl + F5启动调试测试Search函数。

在这里插入图片描述

7.Modify函数

Modify函数是将指定的用户进行修改,使用FindName函数进行查找,如果用户存在,对用户信息重新录入修改,如果不存在,输出提示信息。

contatc.h文件实现Modify函数的声明.

//Modify函数的声明
void Modify(Contact* con);

contact.c文件实现函数的定义.

//Modify函数的定义
void Modify(Contact* con)
{assert(con);//保证con不为NULL;//1.查找到成员信息,还是使用查找函数char tem[20] = { 0 };printf("请输入需要修改的对象:>");scanf("%s", tem);//2.查找是否存在int r = FindName(con, tem);//如果存在,因为是修改,可以将原因信息重新录入即可if (r != -1){//直接使用Add函数的代码printf("请输入名字:>");scanf("%s", con->data[r].name);//字符串数组名标识地址不需要&printf("请输入年龄:>");scanf("%d", &(con->data[r].age));//age是变量需要&printf("请输入性别:>");scanf("%s", con->data[r].sex);printf("请输入联系方式:>");scanf("%s", con->data[r].tele);printf("请输入地址:>");scanf("%s", con->data[r].addr);//修改成功后提示一下printf("用户信息已经成功修改!\n");}//没有找到,提示一下else{printf("输入的用户信息不存在!\n");return;//结束程序}
}

test.c文件实现函数的调用。

//多次选择
do 
{menu();printf("请选择:>");(void)scanf("%d", &input);switch (input){case ADD:	Add(&con);//调用Add函数break;case DELETE:Delete(&con);//调用删除函数break;case SEARCH:Search(&con);//调用查找函数break;case MODIFY:Modify(&con);//调用修改函数break;case SHOW:Show(&con);//调用Show函数break;case SORT:break;case EXIT:printf("退出程序中...\n");break;default:printf("请重新选择!\n");}
} while (input);

按Ctrl + F5测试修改函数。

在这里插入图片描述

8.Sort函数

Sort函数是按照指定顺序排序,以下是按照名字排序,使用qsort函数完成具体排序,使用qsort函数需要实现一个函数指针,并包含指定头文件。

contact.h文件实现Sort函数的声明

#include<stdlib.h>//qsort函数需要的头文件
//Sort函数的声明
void Sort(Contact* con);

contact.c文件实现函数的定义。

//Sort函数的定义
int cmp_by_name(const void* e1,const void* e2)
{assert(e1 && e2);//e1和e2不为NULL//比较名字,实现strcmp函数//将比较结果自己返回return strcmp(((PeoInf*)e1)->name,((PeoInf*)e2)->name);
}
void Sort(Contact* con)
{assert(con);//判断con不为NULL//假设按照名字排列,使用qsort函数实现排序//qsort函数的头文件是#inlcude<stdlib.h>//qsor函数需要实现一个函数指针qsort(con->data, con->count, sizeof(PeoInf), cmp_by_name);//提示一下排序成功printf("用户信息已经成功排序!\n");
}

test.c文件实现函数的调用

//多次选择
do 
{menu();printf("请选择:>");(void)scanf("%d", &input);switch (input){case ADD:	Add(&con);//调用Add函数break;case DELETE:Delete(&con);//调用删除函数break;case SEARCH:Search(&con);//调用查找函数break;case MODIFY:Modify(&con);//调用修改函数break;case SHOW:Show(&con);//调用Show函数break;case SORT:Sort(&con);//调用Sort函数break;case EXIT:printf("退出程序中...\n");break;default:printf("请重新选择!\n");}
} while (input);

按Ctrl + F5测试Sort函数。

在这里插入图片描述
在这里插入图片描述

9.修改为动态版本

此时的通讯录最大只能存放MAX个用户的信息,可以有些用户不需要这么多的空间,可能导致空间的浪费,有些用户需要更大的空间,导致空间不足;因此需要将大小根据用户的需求进行调整,可以实现动态内存管理的函数即时调整空间大小。

contact文件修改Contact结构体的内容,增加一个capacity(容量)变量,并将data数组修改为结构体指针类型,节省空间大小,并重新定义初始容量大小,和扩容大小,并进行销毁函数的声明。

#define INT_EXPANSION 5//扩容大小
//动态版本
typedef struct Contact
{int count;//记录当前存放的个数int capacity;//记录当前容量PeoInf* data;//结构体指针}Contact;//类型重定义为Contact
//销毁通讯录
void DestroyContact(Contact* con);

contact.c文件需要修改初始化函数,Add函数,增加一个扩容函数和销毁函数。

//动态版本
void InitidContact(Contact* con)
{assert(con);//保证con不为空指针//初始化:使用memset函数con->count = 0;//开始信息为0con->capacity = INT_EXPANSION;//表示当前容量是5PeoInf*pfData = (PeoInf*)calloc(INT_EXPANSION, sizeof(PeoInf));if (pfData == NULL)//判断是否开辟空间失败{perror("InitidContact");//输出错误信息return;//结束扩容}//赋值con->data = pfData;//data可以指向pf指向的空间}//销毁通讯录
void DestroyContact(Contact* con)
{assert(con);//判断con不为NULL//回收空间,设置空指针free(con->data);con->data = NULL;
}//扩容函数,static修饰只能在当前文件使用
static void Expansion(Contact* con)
{//扩容PeoInf* pfData = (PeoInf*)realloc(con->data, (con->capacity + INT_EXPANSION) * sizeof(PeoInf));//if (pfData == NULL){perror("Expansion::");//提示扩容失败的原因return;//结束扩容函数}con->data = pfData;//data数组可以指向调整后开辟的空间。con->capacity += INT_EXPANSION;//记录下当前的容量//提示一下扩容成功printf("扩容成功,当前容量为:%d\n", con->capacity);
}
void Add(Contact* con)
{assert(con);//考虑是否需要扩容if (con->capacity == con->count)Expansion(con);//此时容量未满,可以增加//找到当前数组的位置printf("请输入名字:>");scanf("%s", con->data[con->count].name);//字符串数组名标识地址不需要&printf("请输入年龄:>");scanf("%d", &(con->data[con->count].age));//age是变量需要&printf("请输入性别:>");scanf("%s", con->data[con->count].sex);printf("请输入联系方式:>");scanf("%s", con->data[con->count].tele);printf("请输入地址:>");scanf("%s", con->data[con->count].addr);//此时增加成功,将count++con->count++;//提示一下,增加成功printf("输入的信息已经保存\n");
}

test.c文件在退出程序时调用DestroyContact函数。

	//多次选择do {menu();printf("请选择:>");(void)scanf("%d", &input);switch (input){case ADD:	Add(&con);//调用Add函数break;case DELETE:Delete(&con);//调用删除函数break;case SEARCH:Search(&con);//调用查找函数break;case MODIFY:Modify(&con);//调用修改函数break;case SHOW:Show(&con);//调用Show函数break;case SORT:Sort(&con);//调用Sort函数break;case EXIT:DestroyContact(&con);//销毁通讯录printf("退出程序中...\n");break;default:printf("请重新选择!\n");}} while (input);

按Ctrl + F5启动调试,测试是否能使用动态的版本。

在这里插入图片描述

10.修改为文件版本

文件版本是为了改进动态版本程序退出后数据销毁的问题,可以在程序退出时将已经保存的数据存放于一个data.txt的文件中,当程序下一次运行时将data.txt文件的信息在初始化阶段加载到data数组中,
需要创建一个Save函数保存用户信息,创建一个LoadContact函数将信息加载到data数组中。

contact.h文件对Save函数和LoadContact函数进行声明。

//Save函数的声明
void Save(Contact* con);//LoadContact函数的声明
void LoadContact(Contact* con);

contact.c文件需要对Save函数和LoadContact函数进行函数定义。

//LoadContact函数的定义
void LoadContact(Contact* con)
{//以二进制读取方式打开文件FILE* pfRead = fopen("data.txt", "rb");if (pfRead == NULL){perror("LoadContact");//输出错误信息return;//结束函数}//使用PeoInf tem = { 0 };//创建一个结构体变量while (fread(&tem,sizeof(PeoInf),1,pfRead) == 1){Expansion(con);//检测是否需要扩容//因为文件的内容的大小可能比初始化的可以存储的空间多//因此需要考虑扩容con->data[con->count] = tem;//将读取到的信息赋给data数组的元素con->count++;//用户信息+1}//关闭fclose(pfRead);pfRead = NULL;
}//Save函数的定义
void Save(Contact* con)
{assert(con);//判断不为NULL//打开文件FILE* pfWrite = fopen("data.txt", "wb");//判断if (pfWrite == NULL){printf("Save");//输出错误信息return;//结束函数}//使用for遍历数组for (int i = 0; i < con->count; i++){fwrite(con->data+i,sizeof(PeoInf),1,pfWrite);}//关闭fclose(pfWrite);pfWrite = NULL;
}

test.c文件在程序退出卡调用Save函数,保存信息。

	//多次选择do {menu();printf("请选择:>");(void)scanf("%d", &input);switch (input){case ADD:	Add(&con);//调用Add函数break;case DELETE:Delete(&con);//调用删除函数break;case SEARCH:Search(&con);//调用查找函数break;case MODIFY:Modify(&con);//调用修改函数break;case SHOW:Show(&con);//调用Show函数break;case SORT:Sort(&con);//调用Sort函数break;case EXIT:Save(&con);//保存信息DestroyContact(&con);//销毁通讯录printf("退出程序中...\n");break;default:printf("请重新选择!\n");}} while (input);

按Ctrl + F5测试是否能使用Save函数。

在这里插入图片描述

打开data.txt文件观察是否存放信息,可以观察到已经将用户信息存放。

在这里插入图片描述

将程序关闭,重新按Ctrl + F5测试LoadContact函数是否能使用,程序运行后使用Show功能展示。

在这里插入图片描述

此时可以使用文件的版本保存和加载有效信息,但是此时的程序还是存在很多问题,效率还是比较低的,高效的使用应该使用数据库管理用户信息,这里就不再进行改进,有兴趣的学习数据库后进行版本的改进,推荐数据库的学习链接:数据库学习

11.程序代码展示

11.1.contact.h文件

//防止头文件多次包含
#pragma once//防止函数报不安全警告
#pragma warning(disable:4996)//头文件的包含#include<stdio.h>//标准输入输出需要的头文件
#include<assert.h>//断言函数需要的头文件
#include<string.h>//memset函数和字符串函数需要的文件
#include<stdlib.h>//qsort函数和realloc函数需要的头文件//#define定义的常量//#define MAX 50 //假设最大容量是50个
#define MAX_NAME 20
#define MAX_SEX 6
#define MAX_TELE 12
#define MAX_ADDR 20
#define INT_EXPANSION 5//扩容大小//创建一个存放人信息的结构体
typedef struct PeoInf
{char name[MAX_NAME];//名字int age;//年龄char sex[6];char tele[MAX_TELE];//联系方式char addr[MAX_ADDR];//地址}PeoInf;//类型重定义为PeoInf//创建一个通讯录结构体//静态版本
//typedef struct Contact
//{
//	int count;//记录当前存放的个数
//	PeoInf data[MAX];//结构体数组
//
//}Contact;//类型重定义为Contact//动态版本
typedef struct Contact
{int count;//记录当前存放的个数int capacity;//记录当前容量PeoInf* data;//结构体指针}Contact;//类型重定义为Contact//函数的声明//初始化函数
void InitidContact(Contact* con);//销毁通讯录
void DestroyContact(Contact* con);//Add函数
void Add(Contact* con);//Show函数
void Show(Contact* con);//Delete函数
void Delete(Contact* con);//Search函数的声明
void Search(Contact* con);//Modify函数的声明
void Modify(Contact* con);//Sort函数的声明
void Sort(Contact* con);//Save函数的声明
void Save(Contact* con);//LoadContact函数的声明
void LoadContact(Contact* con);

11.2.contact.c文件

在这里插入代码片#include "contact.h"//包含自定义头文件//初始化函数的定义//静态版本
//void InitidContact(Contact* con)
//{
//	assert(con);//保证con不为空指针
//
//	//初始化:使用memset函数
//	con->count = 0;
//	memset(con->data,0, sizeof(con ->data));
//}//扩容函数,static修饰只能在当前文件使用
static void Expansion(Contact* con)
{//扩容if (con->capacity == con->count){PeoInf* pfData = (PeoInf*)realloc(con->data, (con->capacity + INT_EXPANSION) * sizeof(PeoInf));//if (pfData == NULL){perror("Expansion::");//提示扩容失败的原因return;//结束扩容函数}con->data = pfData;//data数组可以指向调整后开辟的空间。con->capacity += INT_EXPANSION;//记录下当前的容量//提示一下扩容成功printf("扩容成功,当前容量为:%d\n", con->capacity);}
}//LoadContact函数的定义
void LoadContact(Contact* con)
{//以二进制读取方式打开文件FILE* pfRead = fopen("data.txt", "rb");if (pfRead == NULL){perror("LoadContact");//输出错误信息return;//结束函数}//使用PeoInf tem = { 0 };//创建一个结构体变量while (fread(&tem,sizeof(PeoInf),1,pfRead) == 1){Expansion(con);//检测是否需要扩容//因为文件的内容的大小可能比初始化的可以存储的空间多//因此需要考虑扩容con->data[con->count] = tem;//将读取到的信息赋给data数组的元素con->count++;//用户信息+1}//关闭fclose(pfRead);pfRead = NULL;}//动态版本
void InitidContact(Contact* con)
{assert(con);//保证con不为空指针//初始化:使用memset函数con->count = 0;//开始信息为0con->capacity = INT_EXPANSION;//表示当前容量是5PeoInf*pfData = (PeoInf*)calloc(INT_EXPANSION, sizeof(PeoInf));if (pfData == NULL){perror("InitidContact");//输出错误信息return;//结束扩容}//赋值con->data = pfData;//data可以指向pf指向的空间LoadContact(con);}//销毁通讯录
void DestroyContact(Contact* con)
{assert(con);//判断con不为NULL//回收空间,设置空指针free(con->data);con->data = NULL;
}//Add函数的定义// 静态版本
//void Add(Contact* con)
//{
//	assert(con);
//
//	//判断当前存放的个数是否满了
//	if (con->count == MAX)
//	{
//		//此时不能存放,终止增加
//		printf("当前容量已满,不可创建,退出中.......\n");
//		return;
//	}
//	//此时容量未满,可以增加
//	//找到当前数组的位置
//	printf("请输入名字:>");
//	scanf("%s", con->data[con->count].name);//字符串数组名标识地址不需要&
//	printf("请输入年龄:>");
//	scanf("%d", &(con->data[con->count].age));//age是变量需要&
//	printf("请输入性别:>");
//	scanf("%s", con->data[con->count].sex);
//	printf("请输入联系方式:>");
//	scanf("%s", con->data[con->count].tele);
//	printf("请输入地址:>");
//	scanf("%s", con->data[con->count].addr);
//
//	//此时增加成功,将count++
//	con->count++;
//	//提示一下,增加成功
//	printf("输入的信息已经保存\n");
//}//动态版本void Add(Contact* con)
{assert(con);//考虑是否需要扩容if (con->capacity == con->count)Expansion(con);//此时容量未满,可以增加//找到当前数组的位置printf("请输入名字:>");scanf("%s", con->data[con->count].name);//字符串数组名标识地址不需要&printf("请输入年龄:>");scanf("%d", &(con->data[con->count].age));//age是变量需要&printf("请输入性别:>");scanf("%s", con->data[con->count].sex);printf("请输入联系方式:>");scanf("%s", con->data[con->count].tele);printf("请输入地址:>");scanf("%s", con->data[con->count].addr);//此时增加成功,将count++con->count++;//提示一下,增加成功printf("输入的信息已经保存\n");
}//Show函数的定义
void Show(Contact* con)
{assert(con);//con不为空指针//判断count是否为0if (con->count == 0){printf("没有信息,不可展示!\n");return;//结束Show函数}//打印标题行:-表示左对齐,\t是间隔8个水平制表位printf("%-20s%-5s\t%-6s\t%-12s\t%s\n","名字","年龄","性别","联系方式","地址");//使用for循环遍历输出打印int i = 0;//从下标为0的元素开始for (i = 0; i < con->count; i++){printf("%-20s%-5d\t%-6s\t%-12s\t%s\n", con->data[i].name,con->data[i].age, con->data[i].sex,con->data[i].tele, con->data[i].addr);}
}int FindName(Contact*con,const char* tem)
{assert(tem);//此时con已经在Delet数组中调用,不需要判断con//使用数组遍历查找int i = 0;for (i = 0; i < con->count; i++){//判断名字是否相等,使用strcmp函数if(strcmp(con->data[i].name,tem) == 0)return i;//表示找到,返回下标}return -1;//遍历数组后还找不到返回-1
}//Delete函数的定义
void Delete(Contact* con)
{assert(con);//判断con不为空指针char tem[20] = { 0 };printf("请输入需要删除的对象:>");scanf("%s", tem);//1.需要找到删除的对象,需要实现一个查找函数;int r = FindName(con, tem);//2.判断是否找到//如果找到了进行覆盖if (r != -1)//找到了,通过后一个信息覆盖前一个信息完成删除{	//使用for循环遍历数组//从下标为r的数组元素开始覆盖for (; r < con->count - 1; r++)//count - 1表示数组倒数第二个元素{                            //防止数组越界memcpy(con->data + r, con->data + r + 1, sizeof(PeoInf));//memcpy是内存块拷贝函数,第一个参数是下标为r的元素的起始地址//第二个元素是r + 1下标元素的起始地址,第三个参数是拷贝元素的//大小,刚刚好是一个人信息结构体大小。}}//找不到,输出原因,并退出函数else{printf("输入的用户信息不存在,请稍后尝试!\n");return;}//3.count--,此时的用户信息删除了一个,用户信息减一con->count--;//4.提示一下删除成功printf("输入的用户信息删除成功!\n");
}void Search(Contact* con)
{assert(con);//判断con不为NULL//前面的Delete函数已经实现了查找函数//此处可以调用该函数判断是否存在该用户信息//如果存在,将该用户信息输入即可//1.输入需要查找的对象char tem[20] = { 0 };printf("请输入需要查找的对象:>");scanf("%s", tem);//2.查找是否存在int r = FindName(con, tem);//存在输入打印if (r != -1){//找到了,提示一下printf("输入的用户存在,正在加载中....\n");//使用Show函数的格式输出//打印标题行:-表示左对齐,\t是间隔8个水平制表位printf("%-20s%-5s\t%-6s\t%-12s\t%s\n", "名字", "年龄", "性别", "联系方式", "地址");//指定格式输出printf("%-20s%-5d\t%-6s\t%-12s\t%s\n", con->data[r].name,con->data[r].age, con->data[r].sex,con->data[r].tele, con->data[r].addr);}//不存在,提示一下,并结束函数else{printf("输入的用户不存在!\n");return;//结束函数}
}//Modify函数的定义
void Modify(Contact* con)
{assert(con);//保证con不为NULL;//1.查找到成员信息,还是使用查找函数char tem[20] = { 0 };printf("请输入需要修改的对象:>");scanf("%s", tem);//2.查找是否存在int r = FindName(con, tem);//如果存在,因为是修改,可以将原因信息重新录入即可if (r != -1){//直接使用Add函数的代码printf("请输入名字:>");scanf("%s", con->data[r].name);//字符串数组名标识地址不需要&printf("请输入年龄:>");scanf("%d", &(con->data[r].age));//age是变量需要&printf("请输入性别:>");scanf("%s", con->data[r].sex);printf("请输入联系方式:>");scanf("%s", con->data[r].tele);printf("请输入地址:>");scanf("%s", con->data[r].addr);//修改成功后提示一下printf("用户信息已经成功修改!\n");}//没有找到,提示一下else{printf("输入的用户信息不存在!\n");return;//结束程序}
}//Sort函数的定义
int cmp_by_name(const void* e1,const void* e2)
{assert(e1 && e2);//e1和e2不为NULL//比较名字,实现strcmp函数//将比较结果自己返回return strcmp(((PeoInf*)e1)->name,((PeoInf*)e2)->name);
}
void Sort(Contact* con)
{assert(con);//判断con不为NULL//假设按照名字排列,使用qsort函数实现排序//qsort函数的头文件是#inlcude<stdlib.h>//qsor函数需要实现一个函数指针qsort(con->data, con->count, sizeof(PeoInf), cmp_by_name);//提示一下排序成功printf("用户信息已经成功排序!\n");
}//Save函数的定义
void Save(Contact* con)
{assert(con);//判断不为NULL//打开文件FILE* pfWrite = fopen("data.txt", "wb");//判断if (pfWrite == NULL){printf("Save");//输出错误信息return;//结束函数}//使用for遍历数组for (int i = 0; i < con->count; i++){fwrite(con->data+i,sizeof(PeoInf),1,pfWrite);}//关闭fclose(pfWrite);pfWrite = NULL;
}

11.3.test.c文件

#include "contact.h"//包含自定义头文件//菜单
void menu()
{printf("************************************\n");printf("*******  1.Add       2.Delete   ****\n");printf("*******  3.Search    4.Modify   ****\n");printf("*******  5.Show      6.Sort     ****\n");printf("*******  0.Exit                 ****\n");printf("************************************\n");
}//枚举常量
enum
{EXIT,//0ADD,//1DELETE,//2SEARCH,//3MODIFY,//4SHOW,//5SORT//6
};int main()
{int input = 0;//功能选择Contact con;//创建通讯录的变量//初始化函数InitidContact(&con);//指针传参//多次选择do {menu();printf("请选择:>");(void)scanf("%d", &input);switch (input){case ADD:	Add(&con);//调用Add函数break;case DELETE:Delete(&con);//调用删除函数break;case SEARCH:Search(&con);//调用查找函数break;case MODIFY:Modify(&con);//调用修改函数break;case SHOW:Show(&con);//调用Show函数break;case SORT:Sort(&con);//调用Sort函数break;case EXIT:Save(&con);//保存信息DestroyContact(&con);//销毁通讯录printf("退出程序中...\n");break;default:printf("请重新选择!\n");}} while (input);return 0;
}

相关文章:

  • 135. 分发糖果
  • 2.1.1 通信基础的基本概念
  • F(x,y)= 0 隐函数 微分法
  • sizeof 与strlen的区别
  • 基于规则的自然语言处理
  • 进程与线程的区别
  • 5-C#的DateTime使用
  • 2025.6.8
  • java 时区时间转为UTC
  • 一种停车场自动停车导航器的设计(论文+源码)
  • 31.2linux中Regmap的API驱动icm20608实验(编程)_csdn
  • 【存储基础】对象存储基础知识
  • 动态生成 PV 的机制:使用 NFS-Client Provisione
  • Python训练打卡Day43
  • Angular中Webpack与ngx-build-plus 浅学
  • nodejs环境变量配置
  • Day25 异常处理
  • 力扣HOT100之二分查找:4. 寻找两个正序数组的中位数
  • pymongo配置事务环境并封装事务功能
  • (三)Linux性能优化-CPU-CPU 使用率
  • 网站建设龙卡要审批多久时间/如何做网络销售产品
  • 企业管理顾问东莞网站建设/凡科建站怎么导出网页
  • 网站用的横幅广告怎么做/内部优化
  • 一区适合晚上一个人看b站/含有友情链接的网页
  • 比较好的网站搭建论坛/seo研究协会
  • 怎么做网站一张图/体验式营销