• C语言实现简单通讯录,malloc,calloc,realloc,free动态内存分配的学习。


    简单通讯录

    在之前的博客中,我与大家分享了结构体的相关知识,今天我们就使用结构体来完成一个简单通讯录。首先我们需要创建两个结构体,一个用来描述通讯录中成员的信息,一个用于描述通讯录。

    #define Max 100
    #define Max_Name 20
    #define Max_Sex 5
    #define Max_Tele 12
    #define Max_Addr 30
    #define Default_Sz 3
    #define Inc_Sz 2
    
    
    struct PerInfo {
    	char name[Max_Name];
    	char sex[Max_Sex];
    	char tele[Max_Tele];
    	int age;
    	char addr[Max_Addr];
    };
    
    struct Contact
    {
     PeoInfo data[MAX];//存放真实数据的空间
     int sz;//记录有效数据的个数
    };

    之后我们编写测试代码,逻辑思路是:首先打印主菜单,之后创建一个通讯录并且初始化通讯录,我们可以让用户选择需要实现的功能,可以循环操作。

    #define  _CRT_SECURE_NO_WARNINGS 1
    #include "contact.h"
    
    
    void menu()
    {
    	printf("*****************\n");
    	printf("******0.exit*****\n");
    	printf("******1.add******\n");
    	printf("******2.del******\n");
    	printf("******3.search***\n");
    	printf("******4.modify***\n");
    	printf("******5.show*****\n");
    	printf("******6.sort*****\n");
    	printf("*****************\n");
    
    }
    
    enum Option
    {
    	EXIT,
    	ADD,
    	DEL,
    	SEARCH,
    	MODIFY,
    	SHOW,
    	SORT
    };
    
    int main()
    {
    	int input = 0;
    	//创建一个通讯录
    	struct Contact con;
    
    	//初始化通讯录
    	InitContact(&con);
    
    
    	do
    	{
    		menu();
    
    		printf("请输入你的选择:");
    		scanf("%d", &input);
    
    		switch (input)
    		{
    		case EXIT:
    			DestoryContact(&con);
    			break;
    		case ADD:
    			AddContact(&con);
    			break;
    		case DEL:
    			DeleContact(&con);
    			break;
    		case SEARCH:
    			SarchContact(&con);
    			break;
    		case MODIFY:
    			ModifyContact(&con);
    			break;
    		case SHOW:
    			ShowContact(&con);
    			break;
    		case SORT:
    			SortContact(&con);
    			break;
    		}
    
    	} while (input);
    
    }
    

    初始化通讯录

    大概的思路就是这样,剩下的就是各个函数的编写了,
    我们来编写初始化通讯的功能。

    //初始化通讯录 静态版本
    void InitContact(struct Contact* pc)
    {
    	assert(pc);
    
    	pc->sz = 0;
    	memset(pc->data, 0, Max * sizeof(struct PerInfo));
    }
    

    我们将我们创建的通讯录的地址传递给InitContact()函数,将sz通讯录联系人个数初始化为0,使用memset初始化结构体变量

    增加联系人

    我们再来写一下增加联系人的功能,首先进行判断,通讯录是否还可以增加联系人,如果通讯录已满给出提示,如果可以添加就在指定的位置进行录入。

    void AddContact(struct Contact* pc)
    {
    	assert(pc);
    
    	if (pc->sz == Max)
    	{
    		printf("通讯录已满,无法录入!!!\n");
    		return;
    	}
    	else
    	{
    		printf("请输入姓名:");
    		scanf("%s", pc->data[pc->sz].name);
    
    		printf("请输入性别:");
    		scanf("%s", pc->data[pc->sz].sex);
    
    		printf("请输入年龄:");
    		scanf("%d",&(pc->data[pc->sz].age));
    
    		printf("请输入地址:");
    		scanf("%s", pc->data[pc->sz].addr);
    
    		printf("请输入电话:");
    		scanf("%s", pc->data[pc->sz].tele);
    
    		pc->sz++;
    
    	}
    
    	printf("恭喜你,录入成功!!!\n");
    
    }
    

    展示联系人

    我们需要有一个查看功能,来查看我们录入的联系人,我们创建一个变量令他从0增长到sz-1,我们读取对应位置的信息,就可以打印出对应位置的联系人。

    void ShowContact(struct Contact* pc)
    {
    	assert(pc);
    
    	if (pc->sz == 0)
    	{
    		printf("您还没有联系人,请您录入\n");
    	}
    	else
    	{
    		printf("%-20s\t%-5s\t%-5s\t%-30s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
    		
    		int i = 0;
    		for (i = 0; i < pc->sz; i++)
    		{
    			printf("%-20s\t%-5d\t%-5s\t%-30s\t%-12s\n", pc->data[i].name,
    				pc->data[i].age,
    				pc->data[i].sex,
    				pc->data[i].addr,
    				pc->data[i].tele);
    
    		}
    	}
    }
    

    删除联系人

    既然我们可以录入联系人,那么我们也应该有删除联系人的功能,我们可以写两个函数,一个是有查找功能的函数,另一个是删除联系人的函数,我们让用户输入需要删除的联系人的名字,通过查找函数判断该联系人是否存在,存在就删除,不存在给出相应的提示。

    static int FindByName(struct Contact* pc, char* name)
    {
    	int i = 0;
    	for (i = 0; i < pc->sz; i++)
    	{
    		if (0 == strcmp(name, pc->data[i].name))
    		{
    			return i;
    		}
    	}
    
    	return -1;
    }
    
    void DeleContact(struct Contact* pc)
    {
    	char name[Max_Name];
    	printf("请输入要删除联系人的姓名:");
    	scanf("%s", name);
    	int ret = FindByName(pc, name);
    
    	if (ret == -1)
    	{
    		printf("您输入的联系人不存在!!!\n");
    		return;
    	}
    	else
    	{
    		int i = ret;
    		for (i = ret; i < pc->sz - 1; i++)
    		{
    			pc->data[i] = pc->data[i + 1];
    		}
    		pc->sz--;
    	}
    }
    

    当我们找到该联系人时,查找函数返回的就是当前这个姓名联系人的下标,我们将后一个联系人的信息向前覆盖就可以达到删除联系人的目的,删除之后不要忘记,联系人总数需要sz--

    查找联系人

    我们需要查找到一个联系人,并且打印他的信息。

    static int FindByName(struct Contact* pc, char* name)
    {
    	int i = 0;
    	for (i = 0; i < pc->sz; i++)
    	{
    		if (0 == strcmp(name, pc->data[i].name))
    		{
    			return i;
    		}
    	}
    
    	return -1;
    }
    
    void SarchContact(struct Contact* pc)
    {
    	char name[Max_Name];
    	printf("请输入要查找联系人的姓名:");
    	scanf("%s", name);
    	int ret = FindByName(pc, name);
    
    	if (ret == -1)
    	{
    		printf("您输入的联系人不存在!!!\n");
    		return;
    	}
    	else
    	{
    		printf("您要查找的联系人的信息是:\n");
    		printf("%-20s\t%-5s\t%-5s\t%-30s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
    		printf("%-20s\t%-5d\t%-5s\t%-30s\t%-12s\n", pc->data[ret].name,
    			pc->data[ret].age,
    			pc->data[ret].sex,
    			pc->data[ret].addr,
    			pc->data[ret].tele);
    	}
    }
    

    同样跟删除一样,我们还是使用姓名查找,找到联系人后对他的信息进行打印就可以了。

    更改联系人

    static int FindByName(struct Contact* pc, char* name)
    {
    	int i = 0;
    	for (i = 0; i < pc->sz; i++)
    	{
    		if (0 == strcmp(name, pc->data[i].name))
    		{
    			return i;
    		}
    	}
    
    	return -1;
    }
    
    void ModifyContact(struct Contact* pc)
    {
    	char name[Max_Name];
    	printf("请输入要更改的联系人的姓名:");
    	scanf("%s", name);
    	int ret = FindByName(pc, name);
    
    	if (ret == -1)
    	{
    		printf("您要更改的联系人不存在!!!\n");
    		return;
    	}
    	else
    	{
    		printf("请更改输入姓名:");
    		scanf("%s", pc->data[ret].name);
    
    		printf("请更改输入性别:");
    		scanf("%s", pc->data[ret].sex);
    
    		printf("请更改输入年龄:");
    		scanf("%d", &(pc->data[ret].age));
    
    		printf("请更改输入地址:");
    		scanf("%s", pc->data[ret].addr);
    
    		printf("请更改输入电话:");
    		scanf("%s", pc->data[ret].tele);
    	}
    }
    
    

    与上面的思路大致一样,还是使用姓名找到该联系人,之后对该联系人的信息进行更改就可以了。

    通讯录的排序

    我们有时会觉得通讯录过于凌乱,需要对通讯录进行排序,排序的依据有很多,这里我们写一种排序,根据年龄的大小对通讯录进行排序。

    static int SortByAge(const void* a, const void* b)
    {
    	return ((struct PerInfo*)a)->age - ((struct PerInfo*)b)->age;
    }
    
    void SortContact(struct Contact* pc)
    {
    	qsort(pc->data, pc->sz, sizeof(struct PerInfo), SortByAge);
    	printf("已排序完成!!!\n");
    }
    

    我们直接使用qsort库函数对年龄大小进行快速排序。

    完整代码

    以上就是就是一个简单通讯录的实现,我们包含了增加,删除,查找,更改,排序等功能,下面是完整的代码

    test.c

    #define  _CRT_SECURE_NO_WARNINGS 1
    #include "contact.h"
    
    
    void menu()
    {
    	printf("*****************\n");
    	printf("******0.exit*****\n");
    	printf("******1.add******\n");
    	printf("******2.del******\n");
    	printf("******3.search***\n");
    	printf("******4.modify***\n");
    	printf("******5.show*****\n");
    	printf("******6.sort*****\n");
    	printf("*****************\n");
    
    }
    
    enum Option
    {
    	EXIT,
    	ADD,
    	DEL,
    	SEARCH,
    	MODIFY,
    	SHOW,
    	SORT
    };
    
    int main()
    {
    	int input = 0;
    	//创建一个通讯录
    	struct Contact con;
    
    	//初始化通讯录
    	InitContact(&con);
    
    
    	do
    	{
    		menu();
    
    		printf("请输入你的选择:");
    		scanf("%d", &input);
    
    		switch (input)
    		{
    		case EXIT:
    			printf("您已退出通讯录!!!");
    			break;
    		case ADD:
    			AddContact(&con);
    			break;
    		case DEL:
    			DeleContact(&con);
    			break;
    		case SEARCH:
    			SarchContact(&con);
    			break;
    		case MODIFY:
    			ModifyContact(&con);
    			break;
    		case SHOW:
    			ShowContact(&con);
    			break;
    		case SORT:
    			SortContact(&con);
    			break;
    		}
    
    	} while (input);
    
    }
    

    Contact.h

    #define  _CRT_SECURE_NO_WARNINGS 1
    #include
    #include
    #include
    #include
    
    #define Max 100
    #define Max_Name 20
    #define Max_Sex 5
    #define Max_Tele 12
    #define Max_Addr 30
    #define Default_Sz 3
    #define Inc_Sz 2
    
    
    struct PerInfo {
    	char name[Max_Name];
    	char sex[Max_Sex];
    	char tele[Max_Tele];
    	int age;
    	char addr[Max_Addr];
    };
    
    struct Contact {
    	struct PerInfo* data;
    	int sz;
    	int capacity;
    };
    
    //初始化通讯录
    void InitContact(struct Contact* pc);
    
    //增加通讯人
    void AddContact(struct Contact* pc);
    
    //展示联系人
    void ShowContact(struct Contact* pc); 
    
    //删除联系人
    void DeleContact(struct Contact* pc);
    
    //查找联系人
    void SarchContact(struct Contact* pc);
    
    //更改联系人
    void ModifyContact(struct Contact* pc);
    
    //根据年龄排序
    void SortContact(struct Contact* pc);
    
    
    

    Contact.c

    #define  _CRT_SECURE_NO_WARNINGS 1
    #include "contact.h"
    
    初始化通讯录 静态版本
    void InitContact(struct Contact* pc)
    {
    	assert(pc);
    
    	pc->sz = 0;
    	memset(pc->data, 0, Max * sizeof(struct PerInfo));
    }
    
    
    //增加 静态
    void AddContact(struct Contact* pc)
    {
    	assert(pc);
    
    	if (pc->sz == Max)
    	{
    		printf("通讯录已满,无法录入!!!\n");
    		return;
    	}
    	else
    	{
    		printf("请输入姓名:");
    		scanf("%s", pc->data[pc->sz].name);
    
    		printf("请输入性别:");
    	    scanf("%s", pc->data[pc->sz].sex);
    
    		printf("请输入年龄:");
    		scanf("%d",&(pc->data[pc->sz].age));
    
    		printf("请输入地址:");
    		scanf("%s", pc->data[pc->sz].addr);
    
    		printf("请输入电话:");
    		scanf("%s", pc->data[pc->sz].tele);
    
    		pc->sz++;
    
    	}
    
    	printf("恭喜你,录入成功!!!\n");
    
    }
    
    //展示联系人
    void ShowContact(struct Contact* pc)
    {
    	assert(pc);
    
    	if (pc->sz == 0)
    	{
    		printf("您还没有联系人,请您录入\n");
    	}
    	else
    	{
    		printf("%-20s\t%-5s\t%-5s\t%-30s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
    		
    		int i = 0;
    		for (i = 0; i < pc->sz; i++)
    		{
    			printf("%-20s\t%-5d\t%-5s\t%-30s\t%-12s\n", pc->data[i].name,
    				pc->data[i].age,
    				pc->data[i].sex,
    				pc->data[i].addr,
    				pc->data[i].tele);
    
    		}
    	}
    }
    
    //删除联系人
    
    static int FindByName(struct Contact* pc, char* name)
    {
    	int i = 0;
    	for (i = 0; i < pc->sz; i++)
    	{
    		if (0 == strcmp(name, pc->data[i].name))
    		{
    			return i;
    		}
    	}
    
    	return -1;
    }
    
    void DeleContact(struct Contact* pc)
    {
    	char name[Max_Name];
    	printf("请输入要删除联系人的姓名:");
    	scanf("%s", name);
    	int ret = FindByName(pc, name);
    
    	if (ret == -1)
    	{
    		printf("您输入的联系人不存在!!!\n");
    		return;
    	}
    	else
    	{
    		int i = ret;
    		for (i = ret; i < pc->sz - 1; i++)
    		{
    			pc->data[i] = pc->data[i + 1];
    		}
    		pc->sz--;
    	}
    }
    
    void SarchContact(struct Contact* pc)
    {
    	char name[Max_Name];
    	printf("请输入要查找联系人的姓名:");
    	scanf("%s", name);
    	int ret = FindByName(pc, name);
    
    	if (ret == -1)
    	{
    		printf("您输入的联系人不存在!!!\n");
    		return;
    	}
    	else
    	{
    		printf("您要查找的联系人的信息是:\n");
    		printf("%-20s\t%-5s\t%-5s\t%-30s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
    		printf("%-20s\t%-5d\t%-5s\t%-30s\t%-12s\n", pc->data[ret].name,
    			pc->data[ret].age,
    			pc->data[ret].sex,
    			pc->data[ret].addr,
    			pc->data[ret].tele);
    	}
    }
    
    //更改联系人
    void ModifyContact(struct Contact* pc)
    {
    	char name[Max_Name];
    	printf("请输入要更改的联系人的姓名:");
    	scanf("%s", name);
    	int ret = FindByName(pc, name);
    
    	if (ret == -1)
    	{
    		printf("您要更改的联系人不存在!!!\n");
    		return;
    	}
    	else
    	{
    		printf("请更改输入姓名:");
    		scanf("%s", pc->data[ret].name);
    
    		printf("请更改输入性别:");
    		scanf("%s", pc->data[ret].sex);
    
    		printf("请更改输入年龄:");
    		scanf("%d", &(pc->data[ret].age));
    
    		printf("请更改输入地址:");
    		scanf("%s", pc->data[ret].addr);
    
    		printf("请更改输入电话:");
    		scanf("%s", pc->data[ret].tele);
    	}
    }
    
    static int SortByAge(const void* a, const void* b)
    {
    	return ((struct PerInfo*)a)->age - ((struct PerInfo*)b)->age;
    }
    
    void SortContact(struct Contact* pc)
    {
    	qsort(pc->data, pc->sz, sizeof(struct PerInfo), SortByAge);
    	printf("以排序完成!!!\n");
    }
    

    动态内存分配

    上面我们完成了一个简单的通讯录,那么上面的通讯录有没有什么缺点呢?答案是有的,我们开始直接开辟了100个联系人的空间,如果我们没有那么多联系人,那么这些空间是不是就是浪费了,我们希望我们有多少联系人就申请多少内存空间,关闭程序后,这些空间返回给系统。要实现这些功能我们就要学习一下malloc calloc realloc free等库函数。

    malloc

    在这里插入图片描述
    上面介绍了这个函数,这个函数向内存申请了一块连续可用的空间,并返回这块空间的指针

    参数是一个无符号整形,就是你要开辟的空间大小
    返回值类型:
    1.如果开辟成功,返回一个指向开辟好空间的指针。
    2.如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
    3.返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定,如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。

    free

    我们动态内存分配的空间在不使用时必须使用free函数释放掉
    在这里插入图片描述

    如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
    如果参数 ptr 是NULL指针,则函数什么事都不做。

    free函数只是将参数指针指向的内存归还给了操作系统,并不会把参数指针置为NULL,为了防止以后访问错误,我们需要在调用free后,手动将指针置为NULL。
    我们在一段代码中体会一下malloc free两个库函数的作用

    int main()
    {
    
    	int* p = NULL;
    	p = (int*)malloc(20);
    
    	if (p != NULL)
    	{
    		int i = 0;
    		for (i = 0; i < 5; i++)
    		{
    			*(p + i) = i;
    			printf("%d ", *(p + i));
    		}
    	}
    
    	free(p);
    	p = NULL;
    
    	return 0;
    }
    
    

    在这里插入图片描述

    calloc

    在这里插入图片描述
    calloc库函数的作用也是用来动态内存分配的

    1.函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。
    2.与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。

    我们可以举个例子看一下malloccalloc之间的区别:

    int main()
    {
    	int* p = (int*)calloc(10, sizeof(int));
    	if (NULL != p)
    	{
    
    	}
    	free(p);
    	p = NULL;
    
    	return 0;
    }
    

    在这里插入图片描述
    我们从调试中看见,我们使用calloc开辟的空间被初始化为0,那么我们使用malloc开辟的内存空间呢?

    int main()
    {
    	int* p = (int*)malloc(40);
    	if (NULL != p)
    	{
    
    	}
    	free(p);
    	p = NULL;
    
    	return 0;
    }
    
    

    在这里插入图片描述
    我们通过调试看见,使用malloc开辟的空间初始值为随机值。

    realloc

    在这里插入图片描述
    为了让动态内存管理更加灵活realloc就出现了,有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整
    我们通过上面的介绍了解到了:
    void* realloc (void* ptr, size_t size);

    1、ptr 是要调整的内存地址
    2、size 调整之后新大小
    3、返回值为调整之后的内存起始位置。
    4、这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到 新 的空间。

    realloc在调整内存空间的时候存在两种情况:

    情况1:原有空间之后又足够大的空间,要扩展的内存就直接在原有内存之后追加空间,原空间的数据不发生变化。
    情况2:原有空间之后没有足够大的空间,扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用,这样函数返回的是一个新的内存地址。

    我们在代码中使用一下realloc

    int main()
    {
    	int* p = (int*)malloc(4);
    	if (NULL != p)
    	{
    		*p = 2;
    		printf("%d\n", *p);
    	}
    
    	int* ptr = NULL;
    	ptr = (int*)realloc(p, 8);
    	if (ptr != NULL)
    	{
    		p = ptr;
    		int i = 0;
    		for (i = 0; i < 2; i++)
    		{
    			*(p + i) = i;
    			printf("%d ", *(p + i));
    		}
    	}
    
    	free(p);
    	p = NULL;
    
    	return 0;
    }
    

    在这里插入图片描述
    如图我们使用realloc改变了p指针指向的空间大小。

    常见的错误

    我们在使用动态内存分配时,会出现很多的错误,这里总结一下最常见的一些错误:

    1、对NULL指针的解引用操作
    2、对动态开辟空间的越界访问
    3、对非动态开辟内存使用free释放
    4、 使用free释放一块动态开辟内存的一部分
    5、对同一块动态内存多次释放
    6、动态开辟内存忘记释放(内存泄漏)

    通讯录(动态版)

    好了我们言归正传,那我们该如果实现我们之前的需求呢?通讯录的大小随着联系人的多少增大或者减小。

    struct Contact {
    	struct PerInfo* data;
    	int sz;
    	int capacity;
    };
    
    

    我们更改了通讯录结构体里面的内容,将之前的数组改变为一个结构体指针,增加了一个capacity,这个变量用于对比sz,我们将capacity初始值设为3,sz设为0,当联系人增加时sz++,当sz == capaciyt时我们就需要增加通讯录的大小。我们的思路大概就是这样,我们在代码中实现一下。

    void InitContact(struct Contact* pc)
    {
    	assert(pc);
    
    	pc->data = (struct PerInfo*)malloc(Default_Sz * sizeof(struct PerInfo));
    	if (pc->data != NULL)
    	{
    		pc->sz = 0;
    		pc->capacity = Default_Sz;
    	}
    	else
    	{
    		perror("InitContact()");
    		return;
    	}
    }
    

    首先初始化,使用malloc开辟空间,将我们sz初始化为0,capacity初始化为3,我们对增加联系人的函数进行一下更改。

    void AddContact(struct Contact* pc)
    {
    	assert(pc);
    
    	if (pc->sz == pc->capacity)
    	{
    		struct PerInfo* ptr = (struct PerInfo*)realloc(pc->data,(Default_Sz)+Inc_Sz * sizeof(struct PerInfo));
    		if (ptr != NULL)
    		{
    			pc->data = ptr;
    			pc->capacity += Inc_Sz;
    			printf("通讯录扩容成功!!!\n");
    		}
    		else
    		{
    			printf("通讯录扩容失败!!!\n");
    			return;
    		}
    	}
    	
    		printf("请输入姓名:");
    		scanf("%s", pc->data[pc->sz].name);
    
    		printf("请输入性别:");
    		scanf("%s", pc->data[pc->sz].sex);
    
    		printf("请输入年龄:");
    		scanf("%d", &(pc->data[pc->sz].age));
    
    		printf("请输入地址:");
    		scanf("%s", pc->data[pc->sz].addr);
    
    		printf("请输入电话:");
    		scanf("%s", pc->data[pc->sz].tele);
    
    		pc->sz++;
    
    	
    
    	printf("恭喜你,录入成功!!!\n");
    
    }
    

    我们实现了我们的思路,当sz == capacity时我们使用realloc对通讯录进行扩容,这样我们就实现了动态内存的分配,当然我们还需要增加一个销毁函数,当用户选择退出程序时,我们使用free函数对动态申请的内存进行释放。

    void DestoryContact(struct Contact* pc)
    {
    	free(pc->data);
    	pc->capacity = Default_Sz;
    	pc->sz = 0;
    	printf("您以销毁通讯录!!!");
    }
    

    这样我们就完成了对通讯录的更改,下面我们来测试一下我们的通讯录的功能吧。
    增加联系人,展示通讯录
    在这里插入图片描述
    删除,更改,查找,扩容
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    我们也将更改后的源码分享给大家:

    test.c

    #define  _CRT_SECURE_NO_WARNINGS 1
    #include "contact.h"
    
    
    void menu()
    {
    	printf("*****************\n");
    	printf("******0.exit*****\n");
    	printf("******1.add******\n");
    	printf("******2.del******\n");
    	printf("******3.search***\n");
    	printf("******4.modify***\n");
    	printf("******5.show*****\n");
    	printf("******6.sort*****\n");
    	printf("*****************\n");
    
    }
    
    enum Option
    {
    	EXIT,
    	ADD,
    	DEL,
    	SEARCH,
    	MODIFY,
    	SHOW,
    	SORT
    };
    
    int main()
    {
    	int input = 0;
    	//创建一个通讯录
    	struct Contact con;
    
    	//初始化通讯录
    	InitContact(&con);
    
    
    	do
    	{
    		menu();
    
    		printf("请输入你的选择:");
    		scanf("%d", &input);
    
    		switch (input)
    		{
    		case EXIT:
    			DestoryContact(&con);
    			break;
    		case ADD:
    			AddContact(&con);
    			break;
    		case DEL:
    			DeleContact(&con);
    			break;
    		case SEARCH:
    			SarchContact(&con);
    			break;
    		case MODIFY:
    			ModifyContact(&con);
    			break;
    		case SHOW:
    			ShowContact(&con);
    			break;
    		case SORT:
    			SortContact(&con);
    			break;
    		}
    
    	} while (input);
    
    }
    

    contact.c

    #define  _CRT_SECURE_NO_WARNINGS 1
    #include "contact.h"
    //
    初始化通讯录 静态版本
    //void InitContact(struct Contact* pc)
    //{
    //	assert(pc);
    //
    //	pc->sz = 0;
    //	memset(pc->data, 0, Max * sizeof(struct PerInfo));
    //}
    
    //动态版本
    void InitContact(struct Contact* pc)
    {
    	assert(pc);
    
    	pc->data = (struct PerInfo*)malloc(Default_Sz * sizeof(struct PerInfo));
    	if (pc->data != NULL)
    	{
    		pc->sz = 0;
    		pc->capacity = Default_Sz;
    	}
    	else
    	{
    		perror("InitContact()");
    		return;
    	}
    }
    
    
    //增加 静态
    //void AddContact(struct Contact* pc)
    //{
    //	assert(pc);
    //
    //	if (pc->sz == Max)
    //	{
    //		printf("通讯录已满,无法录入!!!\n");
    //		return;
    //	}
    //	else
    //	{
    //		printf("请输入姓名:");
    //		scanf("%s", pc->data[pc->sz].name);
    //
    //		printf("请输入性别:");
    //		scanf("%s", pc->data[pc->sz].sex);
    //
    //		printf("请输入年龄:");
    //		scanf("%d",&(pc->data[pc->sz].age));
    //
    //		printf("请输入地址:");
    //		scanf("%s", pc->data[pc->sz].addr);
    //
    //		printf("请输入电话:");
    //		scanf("%s", pc->data[pc->sz].tele);
    //
    //		pc->sz++;
    //
    //	}
    //
    //	printf("恭喜你,录入成功!!!\n");
    //
    //}
    
    //动态
    void AddContact(struct Contact* pc)
    {
    	assert(pc);
    
    	if (pc->sz == pc->capacity)
    	{
    		struct PerInfo* ptr = (struct PerInfo*)realloc(pc->data,(Default_Sz)+Inc_Sz * sizeof(struct PerInfo));
    		if (ptr != NULL)
    		{
    			pc->data = ptr;
    			pc->capacity += Inc_Sz;
    			printf("通讯录扩容成功!!!\n");
    		}
    		else
    		{
    			printf("通讯录扩容失败!!!\n");
    			return;
    		}
    	}
    	
    		printf("请输入姓名:");
    		scanf("%s", pc->data[pc->sz].name);
    
    		printf("请输入性别:");
    		scanf("%s", pc->data[pc->sz].sex);
    
    		printf("请输入年龄:");
    		scanf("%d", &(pc->data[pc->sz].age));
    
    		printf("请输入地址:");
    		scanf("%s", pc->data[pc->sz].addr);
    
    		printf("请输入电话:");
    		scanf("%s", pc->data[pc->sz].tele);
    
    		pc->sz++;
    
    	
    
    	printf("恭喜你,录入成功!!!\n");
    
    }
    
    //销毁通讯录
    void DestoryContact(struct Contact* pc)
    {
    	free(pc->data);
    	pc->capacity = Default_Sz;
    	pc->sz = 0;
    	printf("您以销毁通讯录!!!");
    }
    
    //展示联系人
    void ShowContact(struct Contact* pc)
    {
    	assert(pc);
    
    	if (pc->sz == 0)
    	{
    		printf("您还没有联系人,请您录入\n");
    	}
    	else
    	{
    		printf("%-20s\t%-5s\t%-5s\t%-30s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
    		
    		int i = 0;
    		for (i = 0; i < pc->sz; i++)
    		{
    			printf("%-20s\t%-5d\t%-5s\t%-30s\t%-12s\n", pc->data[i].name,
    				pc->data[i].age,
    				pc->data[i].sex,
    				pc->data[i].addr,
    				pc->data[i].tele);
    
    		}
    	}
    }
    
    //删除联系人
    
    static int FindByName(struct Contact* pc, char* name)
    {
    	int i = 0;
    	for (i = 0; i < pc->sz; i++)
    	{
    		if (0 == strcmp(name, pc->data[i].name))
    		{
    			return i;
    		}
    	}
    
    	return -1;
    }
    
    void DeleContact(struct Contact* pc)
    {
    	char name[Max_Name];
    	printf("请输入要删除联系人的姓名:");
    	scanf("%s", name);
    	int ret = FindByName(pc, name);
    
    	if (ret == -1)
    	{
    		printf("您输入的联系人不存在!!!\n");
    		return;
    	}
    	else
    	{
    		int i = ret;
    		for (i = ret; i < pc->sz - 1; i++)
    		{
    			pc->data[i] = pc->data[i + 1];
    		}
    		pc->sz--;
    	}
    }
    
    void SarchContact(struct Contact* pc)
    {
    	char name[Max_Name];
    	printf("请输入要查找联系人的姓名:");
    	scanf("%s", name);
    	int ret = FindByName(pc, name);
    
    	if (ret == -1)
    	{
    		printf("您输入的联系人不存在!!!\n");
    		return;
    	}
    	else
    	{
    		printf("您要查找的联系人的信息是:\n");
    		printf("%-20s\t%-5s\t%-5s\t%-30s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
    		printf("%-20s\t%-5d\t%-5s\t%-30s\t%-12s\n", pc->data[ret].name,
    			pc->data[ret].age,
    			pc->data[ret].sex,
    			pc->data[ret].addr,
    			pc->data[ret].tele);
    	}
    }
    
    //更改联系人
    void ModifyContact(struct Contact* pc)
    {
    	char name[Max_Name];
    	printf("请输入要更改的联系人的姓名:");
    	scanf("%s", name);
    	int ret = FindByName(pc, name);
    
    	if (ret == -1)
    	{
    		printf("您要更改的联系人不存在!!!\n");
    		return;
    	}
    	else
    	{
    		printf("请更改输入姓名:");
    		scanf("%s", pc->data[ret].name);
    
    		printf("请更改输入性别:");
    		scanf("%s", pc->data[ret].sex);
    
    		printf("请更改输入年龄:");
    		scanf("%d", &(pc->data[ret].age));
    
    		printf("请更改输入地址:");
    		scanf("%s", pc->data[ret].addr);
    
    		printf("请更改输入电话:");
    		scanf("%s", pc->data[ret].tele);
    	}
    }
    
    static int SortByAge(const void* a, const void* b)
    {
    	return ((struct PerInfo*)a)->age - ((struct PerInfo*)b)->age;
    }
    
    void SortContact(struct Contact* pc)
    {
    	qsort(pc->data, pc->sz, sizeof(struct PerInfo), SortByAge);
    	printf("以排序完成!!!\n");
    }
    

    contact.h

    #define  _CRT_SECURE_NO_WARNINGS 1
    #include
    #include
    #include
    #include
    
    #define Max 100
    #define Max_Name 20
    #define Max_Sex 5
    #define Max_Tele 12
    #define Max_Addr 30
    #define Default_Sz 3
    #define Inc_Sz 2
    
    
    struct PerInfo {
    	char name[Max_Name];
    	char sex[Max_Sex];
    	char tele[Max_Tele];
    	int age;
    	char addr[Max_Addr];
    };
    
    struct Contact {
    	struct PerInfo* data;
    	int sz;
    	int capacity;
    };
    
    //初始化通讯录
    void InitContact(struct Contact* pc);
    
    //增加通讯人
    void AddContact(struct Contact* pc);
    
    //展示联系人
    void ShowContact(struct Contact* pc); 
    
    //删除联系人
    void DeleContact(struct Contact* pc);
    
    //查找联系人
    void SarchContact(struct Contact* pc);
    
    //更改联系人
    void ModifyContact(struct Contact* pc);
    
    //根据年龄排序
    void SortContact(struct Contact* pc);
    
    //摧毁通讯录
    void DestoryContact(struct Contact* pc);
    
  • 相关阅读:
    时隔3天,我终于理解了四个盘子的汉诺塔问题(Java实现)
    【连载】囚生CYの备忘录(20220906-)
    WhatsApp自动营销软件是真实的吗?对做外贸有帮助吗?
    B站每日自动签到&传统单节点网站的 Serverless 上云
    【100个 Unity实用技能】☀️ | Unity 将秒数转化为00:00:00时间格式
    浏览器工作原理与实践--浏览上下文组:如何计算Chrome中渲染进程的个数
    asp.net+sqlserver企业办公文档管理系统C#项目
    小美的排列构造
    NO8---蓝桥杯JAVA--- 斐波那契升级版
    Brooks曾经在UMLChina网站留过言-回忆和送别(1)
  • 原文地址:https://blog.csdn.net/weixin_64182409/article/details/127035189