• 通讯录的实现(静态版本和动态版本和文件版本)


    为什们要实现通讯录

    主要是为了让我们将结构体的知识,了解的更加深刻,将结构体应用一下,我们先将静态的通讯录实现,在进行改良,用动态内存的知识再将通讯录改造一边,将动态内容的知识也运用一下,最后再用文件操作的方式在改造一下通讯录。
    所以我们会写三个通讯录,同时他是循序渐进的,一步一步的,如果不动前面的知识,可以去看看前面的知识点。

    1. 静态版本通讯录
    2. 动态版本通讯录
    3. 文件版本通讯录

    🐖静态通讯录

    主要运用结构体的知识,不会的同学可以看看《自定义类型保姆级教学(结构体,位段,枚举,联合)》

    首先先介绍一下代码的主题框架有三个部分test.c ,contact.c,contact.h
    test.c的作用:测试通讯录的实现,也就是主函数,整个代码的操作逻辑
    🐖contact.c的作用:写通讯录的实现(通讯录代码函数实现)
    🐖contact.h的作用:写通讯录的声明(通讯录代码函数声明)

    在引用头文件时需要注意的地方
    🐖 contact.h中放通讯录的声明,在 test.ccontact.c的文件都要应用该声明,所以为什们我们不把 #include这些头文件也放到声明里,我们就不需要在 test.ccontact.c的文件重复定义了,那么怎么在在 test.ccontact.c的文件中引用 contact.h文件呢,
    🐕我们知道引用外部文件时,用双引号所以可以用 include"contact.h",这样在 contact.h中存放的声明都可以使用。

    对于通讯录需要存放100个人的信息,每个人的信息包括(姓名,性别,电话,年龄,住址)
    而且通讯录还要有以下功能,
    🐶 (1)增加联系人
    🐶 (2)删除指定联系人
    🐶 (3)修改指定联系人
    🐶 (4)查找指定联系人
    🐶 (5)排序
    🐶 (6)显示通讯录的信息

    🍔通讯录的代码实现

    🦊(1)通讯录的外部封装

    对于通讯录不可能看完做完一个操作就不做了,所以应该写一个循环,能够选择要进行的操作,等操作做完,想要退出循环也是可以的,我们又知道,这个操作至少要进行一次,所以我们学过的循环发现只有do-while()循环可以用了,但对于通讯录来说他有很多操作,所以要用switch,case语句选择操作,但是又发现case后面只能跟整型表达式;所以要用一个菜单函数将这些操作与整型数字联系起来,比如在菜单函数中规定1-就是增加联系人,当switch选择1时就是增加联系人,
    还需要注意一个点,也是在设计最巧妙的一个点,设置0的时候退出程序,在case后整型是0的时候break,然后到while()循环用0,就可以跳出循环,因为0为假。

    在test.c 文件中写这个主函数

    #include
    void menu()
    {
    	printf("***********************************\n");
    	printf("****1-增加联系人   2-删除联系人****\n");
    	printf("****3-修改联系人   4-查找联系人****\n");
    	printf("****5-排序         6-显示通讯录****\n");
    	printf("****       0-退出程序          ****\n");
    	printf("***********************************\n");
    }
    int main()
    {
    	int input = 0;
    	do
    	{
    		menu();
    		printf("请选择操作->");
    		scanf("%d", &input);
    		switch(input)
    		{
    		case 1:
    			break;
    		case 2:
    			break;
    		case 3:
    			break;
    		case 4:
    			break;
    		case 5:
    			break;
    		case 6:
    			break;
    		case 0:
    			printf("退出程序\n");
    			break;
    		default:
    			printf("输入错误,请重新输入\n");
    			break;
    		}
    
    	} while (input);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    🦊(2)创建一个通讯录
    <创建一个结构体>
    🐖想要创建一个通讯录,就要创建一个结构体,用来表示一个人的信息(姓名,性别,电话,年龄,住址),通讯录中每个人的信息,而通讯录就想当与,众多人的集合,所以可以创建一个结构体数组。
    🐕而对于这个表示一个人信息的结构体,因为也只是一个结构体,我们就放在通讯录声明的文件当中,也就是 contact.h文件。
    //创建一个结构体,表示一个人的信息
    struct PeoInf
    {
    	char name[20];
    	char sex[20];
    	char tele[12];
    	int age;
    	char addr[30];
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    <创建一个通讯录>
    🐖创建好这个记录每个人信息的结构体,我们现在就可以创建通讯录了,而了解本质我们就知道,通讯录就是这个结构体数组。放到代码就是 struct PeoInf data[100];这样就创建了可以存放100个人信息的通讯录。
    🐕但是大家觉得这样就完事了吗?那就大错特错了,这样想如果你想要增加一个信息,你要增加那个位置,你是不知道的,所以对于通讯录来说,我们不仅要创建这个数组,也要知道这个通讯录有几个信息,这时我们创建一个 int sz;来表示通讯录中有几个人的信息,所以将这两个内容再封装成一个结构体。代码如下,因为这是封装一个通讯录结构体,所以也放在 contact.h文件中。

    有了通讯录的结构体,我们就可以在主函数中创建一个通讯录。

    在这里插入图片描述

    🦊(3)初始化通讯录

    对于创建好了通讯录,对于通讯录的内容,应该先初始化,之后才可以进行修改。下面就要进行通讯录的初始化,注意他是传的是地址,不可以传值,如果传值,他是形参的一份临时拷贝,不会改变原本的参数,也就不能初始化。

    void InitContact(struct Contact* pc)
    {
    	//防止是空指针,用断言函数
    	assert(pc);
    	pc->sz = 0;
    	memset(pc->data, 0, 100 * sizeof(struct PeoInf));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    🦊(4)增加通讯录(功能一:增)

    代码实现,在代码中用注释解释,看完代码相信你就能理解了

    //增加通讯录
    void AddContact(struct Contact* pc)
    {
    	//防止是空指针,用断言函数
    	assert(pc);
    	//判断通讯录的信息满了没有,就是看sz的大小
    	//if (pc->sz == 100)
    	//我们发现这个100,我们一直再用,可以直接用define定义MAX=100
    	//这时我们可以把通讯录中人的信息也用define定义
    	if(pc -> sz == MAX)
    	{
    		printf("通讯录已满,无法增加数据\n"); 
    		return;
    		//因为通讯录已经放不下了,应该退出函数,对于这
    		//个函数的返回值是void,所以不需要返回任何东西
    	}
    	else
    	{
    		printf("请输入名字:>");
    		scanf("%s", pc->data[pc->sz].name);
    		printf("请输入性别:>");
    		scanf("%s", pc->data[pc->sz].sex);
    		printf("请输入电话:>");
    		scanf("%s", pc->data[pc->sz].tele);	
    		printf("请输入年龄:>");
    		scanf("%s", &(pc->data[pc->sz].age));
    		printf("请输入地址:>");
    		scanf("%s", pc->data[pc->sz].addr);
    		pc->sz++;
    		printf("成功增加联系人\n");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    🦊(5)查找通讯录(功能二:查)

    跟增加通讯录一样,在注释中解释为什们要这么写

    //显示通讯录的信息
    void ShowContact(const struct Contact* pc)
    {
    	int i = 0;
    	for (i = 0; i < pc->sz; i++)
    	{
    		printf("%s %s %s %d %s\n", pc->data[i].name,
    			pc->data[i].sex,
    			pc->data[i].tele,
    			pc->data[i].age,
    			pc->data[i].addr);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    上图,是我用上面的代码增加了三个人的信息然后查看,发现他们乱七八糟,每一个都没有一一对齐,连一个表头都没有,所以我们就要将这些代码对齐然后,在创建一个表头,请看下面代码。

    //显示通讯录的信息
    void ShowContact(const struct Contact* pc)
    {
    	int i = 0;
    	printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");
    	for (i = 0; i < pc->sz; i++)
    	{
    		printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[i].name,
    			pc->data[i].sex,
    			pc->data[i].tele,
    			pc->data[i].age,
    			pc->data[i].addr);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    🦊(6)删除通讯录-(功能三:删)

    跟增加通讯录一样,在注释中解释为什们要这么写

    }
    //查找函数,通过名字找到这个人
    int Findname(const struct Contact* pc, char name[])
    {
    	int i = 0;
    	for (i = 0; i < pc->sz; i++)
    	{
    		if (0 == strcmp(pc->data[i].name, name))
    		{
    			return i;
    		}
    	}
    	return -1;
    
    }
    //删除通讯录
    void DelContact(struct Contact* pc)
    {
    	char name[NAME];
    	printf("请输入删除人的名字:>");
    	scanf("%s", name);
    	//查找一下指定的人是否存在
    	//就构造一个函数
    	int ret = Findname(pc, name);
    	if (ret == -1)
    	{
    		printf("要删除的人不存在\n");
    	}
    	else
    	{
    		//删除
    		int j = 0;
    		for (j = ret; j < pc->sz - 1 ; j++)
    		{
    			pc->data[j] = pc->data[j + 1];
    		}
    		pc->sz--;
    		printf("成功删除联系人\n");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    🦊(7)查找通讯录-(功能三:查)

    跟增加通讯录一样,在注释中解释为什们要这么写

    //查找指定联系人
    void SerchContact(const struct Contact* pc)
    {
    	//跟上面删除操作一样,只不过将删除变为查找
    	char name[NAME];
    	printf("请输入查找联系人的名字:>");
    	scanf("%s", name);
    	//查找一下查找的人是否存在
    	//就会用上面的函数
    	int ret = Findname(pc, name);
    	if (ret == -1)
    	{
    		printf("要查找的人不存在\n");
    	}
    	else
    	{
    		//查找联系人,找到就打印出来
    		printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");
    		printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[ret].name,
    			pc->data[ret].sex,
    			pc->data[ret].tele,
    			pc->data[ret].age,
    			pc->data[ret].addr);
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    🦊(8)修改通讯录-(功能三:改)

    修改通讯录,就是先找到要修改的信息位置,然后再像增加通讯录一样重新录入一遍信息。

    //修改指定联系人
    void ModifyContact(struct Contact* pc)
    {
    	printf("请输入修改人的信息:>");
    	char name[NAME];
    	scanf("%s", name);
    	int ret = Findname(pc, name);
    	if (ret == -1)
    	{
    		printf("要查找的人不存在\n");
    	}
    	else
    	{
    		//修改
    		//就相当于重新录入信息
    		printf("请输入名字:>");
    		scanf("%s", pc->data[ret].name);
    		printf("请输入性别:>");
    		scanf("%s", pc->data[ret].sex);
    		printf("请输入电话:>");
    		scanf("%s", pc->data[ret].tele);
    		printf("请输入年龄:>");
    		scanf("%d", &(pc->data[ret].age));
    		printf("请输入地址:>");
    		scanf("%s", pc->data[ret].addr);
    		printf("修改成功\n");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    🦊(9)排序通讯录

    要排序通讯录,就要学会使用qsort(可以在这个地方查找信息),我也写过一遍文章介绍这么用去sort函数《用冒泡排序模拟qsort库函数》,可以参考一下
    在这里插入图片描述

    下面代码是按年龄排序的,只要你将排序函数改一下内容就行了

    //比较
    int CmpByAge(const void* e1, const void* e2)
    {
    	return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
    }
    //按照年龄来排序
    void SortContact(struct Contact* pc)
    {
    	//用qsort排序
    	qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    🦊(10)组装函数

    我们将每个函数都写完了,但是运行起来需要在主函数中将这些函数串联起来,因此可以看下面的主函数的代码。

    int main()
    {
    	//创建一个通讯录
    	struct Contact con;
    	//初始化通讯录
    	InitContact(&con);
    	int input = 0;
    	do
    	{
    		menu();
    		printf("请选择操作->");
    		scanf("%d", &input);
    		switch(input)
    		{
    		case 1:
    			AddContact(&con);
    			break;
    		case 2:
    			DelContact(&con);
    			break;
    		case 3:
    			ModifyContact(&con);
    			break;
    		case 4:
    			SerchContact(&con);
    			break;
    		case 5:
    			SortContact(&con);
    			break;
    		case 6:
    			ShowContact(&con);
    			break;
    		case 0:
    			printf("退出程序\n");
    			break;
    		default:
    			printf("输入错误,请重新输入\n");
    			break;
    		}
    
    	} while (input);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    🐕小总结

    这样通讯录就写完了,看一看各各文件的代码吧

    🦊test.c
    #define _CRT_SECURE_NO_WARNINGS 1
    #include"contact.h"
    void menu()
    {
    	printf("***********************************\n");
    	printf("****1-增加联系人   2-删除联系人****\n");
    	printf("****3-修改联系人   4-查找联系人****\n");
    	printf("****5-排序         6-显示通讯录****\n");
    	printf("****       0-退出程序          ****\n");
    	printf("***********************************\n");
    }
    int main()
    {
    	//创建一个通讯录
    	struct Contact con;
    	//初始化通讯录
    	InitContact(&con);
    	int input = 0;
    	do
    	{
    		menu();
    		printf("请选择操作->");
    		scanf("%d", &input);
    		switch(input)
    		{
    		case 1:
    			AddContact(&con);
    			break;
    		case 2:
    			DelContact(&con);
    			break;
    		case 3:
    			ModifyContact(&con);
    			break;
    		case 4:
    			SerchContact(&con);
    			break;
    		case 5:
    			SortContact(&con);
    			break;
    		case 6:
    			ShowContact(&con);
    			break;
    		case 0:
    			printf("退出程序\n");
    			break;
    		default:
    			printf("输入错误,请重新输入\n");
    			break;
    		}
    
    	} while (input);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    🦊contact.h
    #pragma once
    #include
    #include
    #define MAX 100
    #define NAME 20
    #define SEX 20
    #define TELE 12
    #define ADDR 30
    #include
    #include
    struct PeoInfo
    {
    	char name[NAME];
    	char sex[SEX];
    	char tele[TELE];
    	int age;
    	char addr[ADDR];
    };
    //通讯录
    struct Contact
    {
    	struct PeoInfo data[MAX];
    	int sz ;
    };
    //初始化通讯录
    void InitContact(struct Contact* pc);
    //增加通讯录的信息
    void AddContact(struct Contact* pc);
    //显示通讯录的信息
    void ShowContact(const struct Contact* pc);
    //删除通讯录的信息
    void DelContact(struct Contact *pc);
    //查找指定联系人
    void SerchContact(const struct Contact* pc);
    //修改指定联系人
    void ModifyContact(struct Contact* pc);
    //排序通讯录-按照年龄
    void SortContact(struct Constact* pc);
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    🦊 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, 100 * sizeof(struct PeoInfo));
    }
    //增加通讯录
    void AddContact(struct Contact* pc)
    {
    	//防止是空指针,用断言函数
    	assert(pc);
    	//判断通讯录的信息满了没有,就是看sz的大小
    	//if (pc->sz == 100)
    	//我们发现这个100,我们一直再用,可以直接用define定义MAX=100
    	//这时我们可以把通讯录中人的信息也用define定义
    	if(pc -> sz == MAX)
    	{
    		printf("通讯录已满,无法增加数据\n"); 
    		return;
    		//因为通讯录已经放不下了,应该退出函数,对于这
    		//个函数的返回值是void,所以不需要返回任何东西
    	}
    	else
    	{
    		printf("请输入名字:>");
    		scanf("%s", pc->data[pc->sz].name);
    		printf("请输入性别:>");
    		scanf("%s", pc->data[pc->sz].sex);
    		printf("请输入电话:>");
    		scanf("%s", pc->data[pc->sz].tele);	
    		printf("请输入年龄:>");
    		scanf("%d", &(pc->data[pc->sz].age));
    		printf("请输入地址:>");
    		scanf("%s", pc->data[pc->sz].addr);
    		pc->sz++;
    		printf("成功增加联系人\n");
    	}
    }
    //显示通讯录的信息
    void ShowContact(const struct Contact* pc)
    {
    	int i = 0;
    	printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");
    	for (i = 0; i < pc->sz; i++)
    	{
    		printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[i].name,
    			pc->data[i].sex,
    			pc->data[i].tele,
    			pc->data[i].age,
    			pc->data[i].addr);
    	}
    }
    //查找函数,通过名字找到这个人
    static int Findname(const struct Contact* pc, char name[])
    {
    	int i = 0;
    	for (i = 0; i < pc->sz; i++)
    	{
    		if (0 == strcmp(pc->data[i].name, name))
    		{
    			return i;
    		}
    	}
    	return -1;
    
    }
    //删除通讯录
    void DelContact(struct Contact* pc)
    {
    	char name[NAME];
    	printf("请输入删除人的名字:>");
    	scanf("%s", name);
    	//查找一下指定的人是否存在
    	//就构造一个函数
    	int ret = Findname(pc, name);
    	if (ret == -1)
    	{
    		printf("要删除的人不存在\n");
    	}
    	else
    	{
    		//删除
    		int j = 0;
    		for (j = ret; j < pc->sz - 1 ; j++)
    		{
    			pc->data[j] = pc->data[j + 1];
    		}
    		pc->sz--;
    		printf("成功删除联系人\n");
    	}
    }
    //查找指定联系人
    void SerchContact(const struct Contact* pc)
    {
    	//跟上面删除操作一样,只不过将删除变为查找
    	char name[NAME];
    	printf("请输入查找联系人的名字:>");
    	scanf("%s", name);
    	//查找一下查找的人是否存在
    	//就会用上面的函数
    	int ret = Findname(pc, name);
    	if (ret == -1)
    	{
    		printf("要查找的人不存在\n");
    	}
    	else
    	{
    		//查找联系人,找到就打印出来
    		printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");
    		printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[ret].name,
    			pc->data[ret].sex,
    			pc->data[ret].tele,
    			pc->data[ret].age,
    			pc->data[ret].addr);
    	}
    }
    //修改指定联系人
    void ModifyContact(struct Contact* pc)
    {
    	printf("请输入修改人的信息:>");
    	char name[NAME];
    	scanf("%s", name);
    	int ret = Findname(pc, name);
    	if (ret == -1)
    	{
    		printf("要查找的人不存在\n");
    	}
    	else
    	{
    		//修改
    		//就相当于重新录入信息
    		printf("请输入名字:>");
    		scanf("%s", pc->data[ret].name);
    		printf("请输入性别:>");
    		scanf("%s", pc->data[ret].sex);
    		printf("请输入电话:>");
    		scanf("%s", pc->data[ret].tele);
    		printf("请输入年龄:>");
    		scanf("%d", &(pc->data[ret].age));
    		printf("请输入地址:>");
    		scanf("%s", pc->data[ret].addr);
    		printf("修改成功\n");
    	}
    }
    //比较
    int CmpByAge(const void* e1, const void* e2)
    {
    	return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
    }
    //按照年龄来排序
    void SortContact(struct Contact* pc)
    {
    	//用qsort排序
    	qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160

    🐖动态通讯录

    主要运用动态内存开辟的知识,不会的同学可以看看《动态内存管理(malloc free calloc realloc)》

    (1)为什们要设计动态通讯录
    起始就是在静态通讯录上改造,并且对于动态开辟空间的函数的运用。
    静态通讯只能存放100个人,但是这样就不够灵活,为了让通讯录可以更加灵活,就设计成动态通讯录
    (2)设计动态通讯录的思路
    首先先做一个通讯录,用 malloc存放3个人空间,存放满了后,在用 realloc增加两个人的空间,这样就更加灵活,并且不会浪费空间。
    对于这个我们创建通讯录的代码就要改变,因为 malloc创建的空间用 void*指针来接收,所以将 data[]变为指针,并且在多增加一个参数,容量参数 capacity,当 szcapacity相同时,增加2个空间。所以

    🍔动态通讯录代码实现

    🦊(1)创建通讯录的代码如下:

    🐖

    //通讯录
    struct Contact
    {
    	struct PeoInfo *data ;
    	int sz;
    	int capacity;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    🦊(2)初始化通讯录

    初始化通讯录,用malloc申请3个结构体的空间

    void InitContact(struct Contact* pc)
    {
    	//防止是空指针,用断言函数
    	assert(pc);
    	pc->data = (struct PeoInfo*)malloc(sizeof(struct PeoInfo) * 3);
    	if (pc == NULL)
    	{
    		peeor("InitContact");
    		return;
    	}
    	else
    	{
    		pc -> sz = 0;
    		//pc->capacity = 3;
    		//我们发现这个3,我们一直再用,可以直接用define定义Capacity = 3
    		//这时我们可以把通讯录中人的信息也用define定义
    		pc->capacity = CAPATICY;
    
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    🦊(3)增加通讯录

    对于增加那用不用改呢,答案是用的,因为当空间不够的时候就需要增加空间。

    int check_capacity(struct Contact* pc)
    {
    	if (pc->sz == pc->capacity)
    	{
    		//当前容量满了,现在用realloc增加容量
    		struct PeoInfo* str = (struct PeoInfo*)relloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo));
    		if (str == NULL)
    		{
    			printf("空间申请失败\n");
    			return 0;
    		}
    		else
    		{
    			pc->data = str;
    			//将申请的空间传给pc->data	
    			pc->capacity = pc->capacity + 2;
    			//将容量变大2.
    			printf("增容成功\n");
    			return 1;
    		}
    	}
    	return 1;
    }
    
    //增加通讯录
    void AddContact(struct Contact* pc)
    {
    	//防止是空指针,用断言函数
    	assert(pc);
    	//判断通讯录的信息满了没有,就是看sz的大小
    	//if (pc->sz == 100)
    	//我们发现这个100,我们一直再用,可以直接用define定义MAX=100
    	//这时我们可以把通讯录中人的信息也用define定义
    
    	//我们可以封装一个函数来判断他是否需要增容
    	
    	int ret = check_capacity(pc);
    
    	if (ret == 1)
    	{
    		printf("请输入名字:>");
    		scanf("%s", pc->data[pc->sz].name);
    		printf("请输入性别:>");
    		scanf("%s", pc->data[pc->sz].sex);
    		printf("请输入电话:>");
    		scanf("%s", pc->data[pc->sz].tele);
    		printf("请输入年龄:>");
    		scanf("%d", &(pc->data[pc->sz].age));
    		printf("请输入地址:>");
    		scanf("%s", pc->data[pc->sz].addr);
    		pc->sz++;
    		printf("成功增加联系人\n");
    	}
    	else
    	{
    		return;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    🦊(4)销毁通讯录

    我们知道callocfree是同时出现的,申请了空间,就肯定要销毁空间,所以在退出函数就可以添加一个函数,销毁函数。

    void DistoryContact(struct Contact* pc) 
    {
    	free(pc->data);
    	pc->data = NULL;
    	pc->capacity = 0;
    	pc->sz = 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    🐕动态总结

    动态开辟内存还是相对与来说比较简单的,希望大家先将动态内存的知识看懂,再将动态通讯录来练习学会。

    🦊动态test.c
    #define _CRT_SECURE_NO_WARNINGS 1
    #define _CRT_SECURE_NO_WARNINGS 1
    #include"contact.h"
    void menu()
    {
    	printf("***********************************\n");
    	printf("****1-增加联系人   2-删除联系人****\n");
    	printf("****3-修改联系人   4-查找联系人****\n");
    	printf("****5-排序         6-显示通讯录****\n");
    	printf("****       0-退出程序          ****\n");
    	printf("***********************************\n");
    }
    int main()
    {
    	//创建一个通讯录
    	struct Contact con;
    	//初始化通讯录
    	InitContact(&con);
    	int input = 0;
    	do
    	{
    		menu();
    		printf("请选择操作->");
    		scanf("%d", &input);
    		switch (input)
    		{
    		case 1:
    			AddContact(&con);
    			break;
    		case 2:
    			DelContact(&con);
    			break;
    		case 3:
    			ModifyContact(&con);
    			break;
    		case 4:
    			SerchContact(&con);
    			break;
    		case 5:
    			SortContact(&con);
    			break;
    		case 6:
    			ShowContact(&con);
    			break;
    		case 0:
    			DistoryContact(&con);
    			printf("退出程序\n");
    			break;
    		default:
    			printf("输入错误,请重新输入\n");
    			break;
    		}
    
    	} while (input);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    🦊动态contact.h
    #pragma once
    #pragma once
    #include
    #include
    #define MAX 100
    #define NAME 20
    #define SEX 20
    #define TELE 12
    #define ADDR 30
    #include
    #include
    #define CAPATICY 3
    struct PeoInfo
    {
    	char name[NAME];
    	char sex[SEX];
    	char tele[TELE];
    	int age;
    	char addr[ADDR];
    };
    //通讯录
    struct Contact
    {
    	struct PeoInfo *data ;
    	int sz;
    	int capacity;
    };
    //初始化通讯录
    void InitContact(struct Contact* pc);
    //增加通讯录的信息
    void AddContact(struct Contact* pc);
    //显示通讯录的信息
    void ShowContact(const struct Contact* pc);
    //删除通讯录的信息
    void DelContact(struct Contact* pc);
    //查找指定联系人
    void SerchContact(const struct Contact* pc);
    //修改指定联系人
    void ModifyContact(struct Contact* pc);
    //排序通讯录-按照年龄
    void SortContact(struct Contact* pc);
    //销毁通讯录
    void DistoryContact(struct Contact*pc);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    🦊动态contact.c
    #define _CRT_SECURE_NO_WARNINGS 1
    #define _CRT_SECURE_NO_WARNINGS 1
    #include"contact.h"
    
    void InitContact(struct Contact* pc)
    {
    	//防止是空指针,用断言函数
    	assert(pc);
    	pc->data = (struct PeoInfo*)malloc(sizeof(struct PeoInfo) * 3);
    	if (pc == NULL)
    	{
    		perror("InitContact");
    		return;
    	}
    	else
    	{
    		pc -> sz = 0;
    		//pc->capacity = 3;
    		//我们发现这个3,我们一直再用,可以直接用define定义Capacity = 3
    		//这时我们可以把通讯录中人的信息也用define定义
    		pc->capacity = CAPATICY;
    
    	}
    }
    int check_capacity(struct Contact* pc)
    {
    	if (pc->sz == pc->capacity)
    	{
    		//当前容量满了,现在用realloc增加容量
    		struct PeoInfo* str = (struct PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo));
    		if (str == NULL)
    		{
    			printf("空间申请失败\n");
    			return 0;
    		}
    		else
    		{
    			pc->data = str;
    			//将申请的空间传给pc->data	
    			pc->capacity = pc->capacity + 2;
    			//将容量变大2.
    			printf("增容成功\n");
    			return 1;
    		}
    	}
    	return 1;
    }
    
    //增加通讯录
    void AddContact(struct Contact* pc)
    {
    	//防止是空指针,用断言函数
    	assert(pc);
    	//判断通讯录的信息满了没有,就是看sz的大小
    	//if (pc->sz == 100)
    	//我们发现这个100,我们一直再用,可以直接用define定义MAX=100
    	//这时我们可以把通讯录中人的信息也用define定义
    
    	//我们可以封装一个函数来判断他是否需要增容
    	
    	int ret = check_capacity(pc);
    
    	if (ret == 1)
    	{
    		printf("请输入名字:>");
    		scanf("%s", pc->data[pc->sz].name);
    		printf("请输入性别:>");
    		scanf("%s", pc->data[pc->sz].sex);
    		printf("请输入电话:>");
    		scanf("%s", pc->data[pc->sz].tele);
    		printf("请输入年龄:>");
    		scanf("%d", &(pc->data[pc->sz].age));
    		printf("请输入地址:>");
    		scanf("%s", pc->data[pc->sz].addr);
    		pc->sz++;
    		printf("成功增加联系人\n");
    	}
    	else
    	{
    		return;
    	}
    }
    //显示通讯录的信息
    void ShowContact(const struct Contact* pc)
    {
    	int i = 0;
    	printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");
    	for (i = 0; i < pc->sz; i++)
    	{
    		printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[i].name,
    			pc->data[i].sex,
    			pc->data[i].tele,
    			pc->data[i].age,
    			pc->data[i].addr);
    	}
    }
    //查找函数,通过名字找到这个人
    static int Findname(const struct Contact* pc, char name[])
    {
    	int i = 0;
    	for (i = 0; i < pc->sz; i++)
    	{
    		if (0 == strcmp(pc->data[i].name, name))
    		{
    			return i;
    		}
    	}
    	return -1;
    
    }
    //删除通讯录
    void DelContact(struct Contact* pc)
    {
    	char name[NAME];
    	printf("请输入删除人的名字:>");
    	scanf("%s", name);
    	//查找一下指定的人是否存在
    	//就构造一个函数
    	int ret = Findname(pc, name);
    	if (ret == -1)
    	{
    		printf("要删除的人不存在\n");
    	}
    	else
    	{
    		//删除
    		int j = 0;
    		for (j = ret; j < pc->sz - 1; j++)
    		{
    			pc->data[j] = pc->data[j + 1];
    		}
    		pc->sz--;
    		printf("成功删除联系人\n");
    	}
    }
    //查找指定联系人
    void SerchContact(const struct Contact* pc)
    {
    	//跟上面删除操作一样,只不过将删除变为查找
    	char name[NAME];
    	printf("请输入查找联系人的名字:>");
    	scanf("%s", name);
    	//查找一下查找的人是否存在
    	//就会用上面的函数
    	int ret = Findname(pc, name);
    	if (ret == -1)
    	{
    		printf("要查找的人不存在\n");
    	}
    	else
    	{
    		//查找联系人,找到就打印出来
    		printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");
    		printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[ret].name,
    			pc->data[ret].sex,
    			pc->data[ret].tele,
    			pc->data[ret].age,
    			pc->data[ret].addr);
    	}
    }
    //修改指定联系人
    void ModifyContact(struct Contact* pc)
    {
    	printf("请输入修改人的信息:>");
    	char name[NAME];
    	scanf("%s", name);
    	int ret = Findname(pc, name);
    	if (ret == -1)
    	{
    		printf("要查找的人不存在\n");
    	}
    	else
    	{
    		//修改
    		//就相当于重新录入信息
    		printf("请输入名字:>");
    		scanf("%s", pc->data[ret].name);
    		printf("请输入性别:>");
    		scanf("%s", pc->data[ret].sex);
    		printf("请输入电话:>");
    		scanf("%s", pc->data[ret].tele);
    		printf("请输入年龄:>");
    		scanf("%d", &(pc->data[ret].age));
    		printf("请输入地址:>");
    		scanf("%s", pc->data[ret].addr);
    		printf("修改成功\n");
    	}
    }
    //比较
    int CmpByAge(const void* e1, const void* e2)
    {
    	return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
    }
    //按照年龄来排序
    void SortContact(struct Contact* pc)
    {
    	//用qsort排序
    	qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);
    }
    void DistoryContact(struct Contact* pc) 
    {
    	free(pc->data);
    	pc->data = NULL;
    	pc->capacity = 0;
    	pc->sz = 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207

    🐖文件通讯录

    主要运用文件操作的知识,不会的同学可以看看《C的文件操作》

    文件通讯录的需求
    通讯录退出后,之前保存的信息不能改变,当下一次重新运行通讯录的时候,还能看到上次保存的信息
    分析需求
    退出的时候,把数据保存到文件中,当下一次运行的时候,再从文件中加载信息就可以了

    🍔文件通讯录代码实现

    🦊保存通讯录

    首先我们要实现这个需求,在退出之前,保存通讯录。

    //保存通讯录
    void SaveContact(struct Contact* pc)
    {
    	//打开文件,用二进制的方式写
    	FILE* tt = fopen("Contact.txt", "wb");
    	//判断是否为空指针
    	if (tt == NULL)
    	{
    		perror("SaveContact:fopen");
    		return;
    	}
    	//可以写了
    	for (int i = 0; i < pc->sz; i++)
    	{
    		fwrite(pc->data + i, sizeof(struct PeoInfo), 1, tt);
    	}
    
    	//关闭文件
    	fclose(tt);
    	tt = NULL;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    🦊加载通讯录

    ⭐将通讯录保存了,但是在打开通讯录的时候,需要能够读取文件的信息,但是这个操作在哪进行呀,我们可以在初始化通讯录的时候进行读取文件的信息操作。

    static int check_capacity(struct Contact* pc);
    
    void loadContact(struct Contact* pc)
    {
    	//打开文件
    	FILE* tt = fopen("Contact.txt", "rb");
    	if (tt == NULL)
    	{
    		perror("loadContact:fopen");
    		return;
    	}
    	//读文件
    	//创建一个临时结构体,当中介
    	struct PeoInfo tmp = { 0 };
    	//因为这是动态版本,可能涉及到增容问题
    	//用他的返回值看,读取失败返回0;
    	while (fread(&tmp, sizeof(struct PeoInfo), 1, tt))
    	{
    		//考虑增容问题
    		check_capacity(pc);
    		pc->data[pc->sz] = tmp;
    		pc->sz++;
    	}
    	//关闭文件
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    🦊文件test.c

    文件的代码其实大致无差,就是多了这个功能,为了以防万一还是放在这里了。欢迎大家食用。

    #define _CRT_SECURE_NO_WARNINGS 1
    #define _CRT_SECURE_NO_WARNINGS 1
    #include"contact.h"
    void menu()
    {
    	printf("***********************************\n");
    	printf("****1-增加联系人   2-删除联系人****\n");
    	printf("****3-修改联系人   4-查找联系人****\n");
    	printf("****5-排序         6-显示通讯录****\n");
    	printf("****       0-退出程序          ****\n");
    	printf("***********************************\n");
    }
    int main()
    {
    	//创建一个通讯录
    	struct Contact con;
    	//初始化通讯录
    	InitContact(&con);
    	int input = 0;
    	do
    	{
    		menu();
    		printf("请选择操作->");
    		scanf("%d", &input);
    		switch (input)
    		{
    		case 1:
    			AddContact(&con);
    			break;
    		case 2:
    			DelContact(&con);
    			break;
    		case 3:
    			ModifyContact(&con);
    			break;
    		case 4:
    			SerchContact(&con);
    			break;
    		case 5:
    			SortContact(&con);
    			break;
    		case 6:
    			ShowContact(&con);
    			break;
    		case 0:
    			SaveContact(&con);
    			DistoryContact(&con);
    			printf("退出程序\n");
    			break;
    		default:
    			printf("输入错误,请重新输入\n");
    			break;
    		}
    
    	} while (input);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    🦊文件contact.h
    #pragma once
    #pragma once
    #include
    #include
    #define MAX 100
    #define NAME 20
    #define SEX 20
    #define TELE 12
    #define ADDR 30
    #include
    #include
    #define CAPATICY 3
    struct PeoInfo
    {
    	char name[NAME];
    	char sex[SEX];
    	char tele[TELE];
    	int age;
    	char addr[ADDR];
    };
    //通讯录
    struct Contact
    {
    	struct PeoInfo *data ;
    	int sz;
    	int capacity;
    };
    //初始化通讯录
    void InitContact(struct Contact* pc);
    //增加通讯录的信息
    void AddContact(struct Contact* pc);
    //显示通讯录的信息
    void ShowContact(const struct Contact* pc);
    //删除通讯录的信息
    void DelContact(struct Contact* pc);
    //查找指定联系人
    void SerchContact(const struct Contact* pc);
    //修改指定联系人
    void ModifyContact(struct Contact* pc);
    //排序通讯录-按照年龄
    void SortContact(struct Contact* pc);
    //销毁通讯录
    void DistoryContact(struct Contact*pc);
    //保存通讯录
    void SaveContact(struct Contact* pc);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    🦊动态contact.c
    #define _CRT_SECURE_NO_WARNINGS 1
    #define _CRT_SECURE_NO_WARNINGS 1
    #include"contact.h"
    static int check_capacity(struct Contact* pc);
    
    void loadContact(struct Contact* pc)
    {
    	//打开文件
    	FILE* tt = fopen("Contact.txt", "rb");
    	if (tt == NULL)
    	{
    		perror("loadContact:fopen");
    		return;
    	}
    	//读文件
    	//创建一个临时结构体,当中介
    	struct PeoInfo tmp = { 0 };
    	//因为这是动态版本,可能涉及到增容问题
    	//用他的返回值看,读取失败返回0;
    	while (fread(&tmp, sizeof(struct PeoInfo), 1, tt))
    	{
    		//考虑增容问题
    		check_capacity(pc);
    		pc->data[pc->sz] = tmp;
    		pc->sz++;
    	}
    	//关闭文件
    }
    void InitContact(struct Contact* pc)
    {
    	//防止是空指针,用断言函数
    	assert(pc);
    	pc->data = (struct PeoInfo*)malloc(sizeof(struct PeoInfo) * 3);
    	if (pc == NULL)
    	{
    		perror("InitContact");
    		return;
    	}
    	else
    	{
    		pc -> sz = 0;
    		//pc->capacity = 3;
    		//我们发现这个3,我们一直再用,可以直接用define定义Capacity = 3
    		//这时我们可以把通讯录中人的信息也用define定义
    		pc->capacity = CAPATICY;
    
    	}
    	//加载通讯录,让文件的信息加载到通讯录
    	loadContact(pc);
    }
    static int check_capacity(struct Contact* pc)
    {
    	if (pc->sz == pc->capacity)
    	{
    		//当前容量满了,现在用realloc增加容量
    		struct PeoInfo* str = (struct PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo));
    		if (str == NULL)
    		{
    			printf("空间申请失败\n");
    			return 0;
    		}
    		else
    		{
    			pc->data = str;
    			//将申请的空间传给pc->data	
    			pc->capacity = pc->capacity + 2;
    			//将容量变大2.
    			printf("增容成功\n");
    			return 1;
    		}
    	}
    	return 1;
    }
    
    //增加通讯录
    void AddContact(struct Contact* pc)
    {
    	//防止是空指针,用断言函数
    	assert(pc);
    	//判断通讯录的信息满了没有,就是看sz的大小
    	//if (pc->sz == 100)
    	//我们发现这个100,我们一直再用,可以直接用define定义MAX=100
    	//这时我们可以把通讯录中人的信息也用define定义
    
    	//我们可以封装一个函数来判断他是否需要增容
    	
    	int ret = check_capacity(pc);
    
    	if (ret == 1)
    	{
    		printf("请输入名字:>");
    		scanf("%s", pc->data[pc->sz].name);
    		printf("请输入性别:>");
    		scanf("%s", pc->data[pc->sz].sex);
    		printf("请输入电话:>");
    		scanf("%s", pc->data[pc->sz].tele);
    		printf("请输入年龄:>");
    		scanf("%d", &(pc->data[pc->sz].age));
    		printf("请输入地址:>");
    		scanf("%s", pc->data[pc->sz].addr);
    		pc->sz++;
    		printf("成功增加联系人\n");
    	}
    	else
    	{
    		return;
    	}
    }
    //显示通讯录的信息
    void ShowContact(const struct Contact* pc)
    {
    	int i = 0;
    	printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");
    	for (i = 0; i < pc->sz; i++)
    	{
    		printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[i].name,
    			pc->data[i].sex,
    			pc->data[i].tele,
    			pc->data[i].age,
    			pc->data[i].addr);
    	}
    }
    //查找函数,通过名字找到这个人
    static int Findname(const struct Contact* pc, char name[])
    {
    	int i = 0;
    	for (i = 0; i < pc->sz; i++)
    	{
    		if (0 == strcmp(pc->data[i].name, name))
    		{
    			return i;
    		}
    	}
    	return -1;
    
    }
    //删除通讯录
    void DelContact(struct Contact* pc)
    {
    	char name[NAME];
    	printf("请输入删除人的名字:>");
    	scanf("%s", name);
    	//查找一下指定的人是否存在
    	//就构造一个函数
    	int ret = Findname(pc, name);
    	if (ret == -1)
    	{
    		printf("要删除的人不存在\n");
    	}
    	else
    	{
    		//删除
    		int j = 0;
    		for (j = ret; j < pc->sz - 1; j++)
    		{
    			pc->data[j] = pc->data[j + 1];
    		}
    		pc->sz--;
    		printf("成功删除联系人\n");
    	}
    }
    //查找指定联系人
    void SerchContact(const struct Contact* pc)
    {
    	//跟上面删除操作一样,只不过将删除变为查找
    	char name[NAME];
    	printf("请输入查找联系人的名字:>");
    	scanf("%s", name);
    	//查找一下查找的人是否存在
    	//就会用上面的函数
    	int ret = Findname(pc, name);
    	if (ret == -1)
    	{
    		printf("要查找的人不存在\n");
    	}
    	else
    	{
    		//查找联系人,找到就打印出来
    		printf("%-20s\t %-20s\t %-5s\t %-12s \t%-30s\n", "名字", "性别", "电话", "年龄", "地址");
    		printf("%-20s\t %-20s\t %-5s\t %-12d \t%-30s\n", pc->data[ret].name,
    			pc->data[ret].sex,
    			pc->data[ret].tele,
    			pc->data[ret].age,
    			pc->data[ret].addr);
    	}
    }
    //修改指定联系人
    void ModifyContact(struct Contact* pc)
    {
    	printf("请输入修改人的信息:>");
    	char name[NAME];
    	scanf("%s", name);
    	int ret = Findname(pc, name);
    	if (ret == -1)
    	{
    		printf("要查找的人不存在\n");
    	}
    	else
    	{
    		//修改
    		//就相当于重新录入信息
    		printf("请输入名字:>");
    		scanf("%s", pc->data[ret].name);
    		printf("请输入性别:>");
    		scanf("%s", pc->data[ret].sex);
    		printf("请输入电话:>");
    		scanf("%s", pc->data[ret].tele);
    		printf("请输入年龄:>");
    		scanf("%d", &(pc->data[ret].age));
    		printf("请输入地址:>");
    		scanf("%s", pc->data[ret].addr);
    		printf("修改成功\n");
    	}
    }
    //比较
    int CmpByAge(const void* e1, const void* e2)
    {
    	return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
    }
    //按照年龄来排序
    void SortContact(struct Contact* pc)
    {
    	//用qsort排序
    	qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CmpByAge);
    }
    void DistoryContact(struct Contact* pc) 
    {
    	free(pc->data);
    	pc->data = NULL;
    	pc->capacity = 0;
    	pc->sz = 0;
    }
    
    //保存通讯录
    void SaveContact(struct Contact* pc)
    {
    	//打开文件,用二进制的方式写
    	FILE* tt = fopen("Contact.txt", "wb");
    	//判断是否为空指针
    	if (tt == NULL)
    	{
    		perror("SaveContact:fopen");
    		return;
    	}
    	//可以写了
    	for (int i = 0; i < pc->sz; i++)
    	{
    		fwrite(pc->data + i, sizeof(struct PeoInfo), 1, tt);
    	}
    
    	//关闭文件
    	fclose(tt);
    	tt = NULL;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255

    🐖总结

    ⭐我们现在就将三种形式的通讯录写完了,相信大家肯定或多多少都有点收获,如果大家不太理解,可以私信我,看到必会,如果对大家有点帮助,希望大家一键三联,这将是我的动力。欢迎大家食用。😊😊

  • 相关阅读:
    【Python】六、程序流程控制综合训练
    如何处理C语言中的异常?
    “工会排队”模式:重塑电商生态的新力量
    AI在医疗保健领域:突破界限,救治生命
    Salesforce从业者最重要的6个基础认证!
    【Flutter 面试题】 setState 在哪种场景下可能会失效?
    Apipost:API研发团队的协同利器
    【Java并发编程】——线程池
    docker 搭建 rocketmq
    SwiftUI 4.0:两种方式实现子视图导航功能
  • 原文地址:https://blog.csdn.net/wutongguo/article/details/127346193