• C语言小程序-通讯录(动态内存管理)


    设计思路讲解:
    我们以手机上的通讯录为例,用C来设计一个简单的通讯录版本
    通讯录的功能参照手机上的版本应该有增加,删除,修改,查找,因为我们的代码最终是在终端显示的,所以我们再给出一个显示通讯录的功能,以及最后对通讯录进行排序的功能。

    我们使用结构体来集合关于通讯录中联系人的信息(定义为PeoInfo),这就需要我们要有一个关于PeoInfo的集合来存放多个人的信息,集合的大小可以由动态内存函数来开辟,内存空间不足时自动增加空间以便增添联系人。

    删除时,有很多的方法,可以将要删除的联系人的信息全部改为0,然后qsort一下就ok了。也可以用该联系人后面的联系人覆盖掉要删除的,这样也能实现。方法还有很多,这里不一一给出了。

    修改时我们要先输入该联系人的名字,然后重新输入信息。

    查找也是要先输入联系人的名字,然后显示联系人的信息,我们发现在实现删除,修改查找等功能时,都要涉及到输入联系人的名字进行插查询,所以我们在写代码时,可以将这一功能封装成一个函数,以减少我们重复的代码。

    显示通讯录就很容易实现了,只需要将所有的联系人信息全部打印出来就好了,这里可以使用循环来解决。

    排序我们就使用qsort进行,可以按照名字,年龄,或者其他的信息来进行排
    序,这个取决于程序员自己。

    接下来我们就来开始对各个功能的代码实现,在最后会给出最后的代码。有基础的小伙伴可以直接跳到最后查看最终代码。

    初始化通讯录

    首先要创建一个通讯录出来才能对其初始化,前面我们说过使用PeoInfo来收集联系人的信息

    struct PeoInfo
    {
    char name[MAX_NAME];
    char sex[SEX];
    int age;
    char telephone[TelePhone];
    };

    大小我们统一使用宏定义来操作,方便我们后续的修改。
    只有一个结构体行吗??
    肯定是不行的,因为我们还需要一个集合体来存放PeoInfo的信息,所以还要有一个结构体,这个结构体包含我们的PeoInfo。

    //通讯录结构体
    struct Contact
    {
    //创建sz的目的是为了在进行添加删除等操作时,好找到元素的下标
    int sz;
    struct PeoInfo* arr;
    int capacity;//容量大小.
    };

    这还给出了sz和capacity两个参数,capacity是记录通讯录结构体的大小,sz是用来记录当前联系人的个数,以方便我们后续的增加,删除和查找等功能的实现,这一点如果能想到的话,后面的实现就很容易了,因为后续的大多功能都是以这两个参数为工具进行的。

    结构体创建好了之后,我们就要对其初始化了,除了capacity需要给定一个初始大小之外,剩下的都要全部初始化为0。

    //初始化为全0;
    void InitContact(struct Contact* pc)
    {
    assert(pc);
    pc->sz = 0;
    pc->capacity = 3;//默认容量大小是3
    pc->arr = (struct PeoInfo*)malloc(3 * sizeof(struct PeoInfo));
    if (pc->arr == NULL)
    {
    strerror(errno);
    return; //exit(-1)
    }
    }

    我们把有关通讯录的实现的代码放到contact.c的文件中,把所有包含的头文件放在contact.h的头文件当中,把代码的主主体躯干放在test.c的测试文件当中。

    相关功能的实现(增删查改显排)

    剩下功能的实现以及注意事项我们在代码中注释了,大家留意一下就好,另外我把上面初始化的代码也一并在这里给大家展示出来,这里的代码就是contact.c中的代码啦~

    #include "contact.h"
    
    //初始化为全0;
    void InitContact(struct Contact* pc)
    {
    	assert(pc);
    	pc->sz = 0;
    	pc->capacity = 3;//默认容量大小是3
    	pc->arr = (struct PeoInfo*)malloc(3 * sizeof(struct PeoInfo));
    	if (pc->arr == NULL)
    	{
    		strerror(errno);//打印错误信息
    		return;
    	}
    }
    
    //增加联系人
    void ADDContact(struct Contact* pc)
    {
    	assert(pc);
    	//如果空间已满的话,要先增加一定的空间
    	if (pc->sz == pc->capacity)
    	{
    		//增加容量
    		struct PeoInfo* ptr = (struct PeoInfo*)realloc(pc->arr, (pc->capacity + 2)*sizeof(struct PeoInfo));//一次扩充两个大小的空间
    		if (ptr == NULL)
    		{
    			strerror(errno);//对应的头文件, 
    			return;
    		}
    		else
    		{
    			pc->capacity += 2;
    			pc->arr = ptr;
    			ptr = NULL;
    			printf("增容成功!\n");
    		}
    	}
    
    	//增加
    	printf("请输入名字:>");
    	scanf("%s", pc->arr[pc->sz].name);
    	printf("请输入性别:>");
    	scanf("%s", pc->arr[pc->sz].sex);
    	printf("请输入年龄:>");
    	scanf("%d", &(pc->arr[pc->sz].age));
    	printf("请输入电话:>");
    	scanf("%s", pc->arr[pc->sz].telephone);
    
    	//sz++指向下一个空白的元素,方便下次直接添加联系人
    	pc->sz++;
    	printf("成功增加联系人\n");
    }
    
    //将查找指定联系人封装成一个函数,因为在后续的功能中还要用到这个
    int FindByName(const struct Contact* pc, char* n)
    {
    	assert(pc && n);
    	int i = 0;
    	for (i = 0; i < pc->sz; i++)
    	{
    		//strcmp比较两个字符串是否相同
    		if (0 == strcmp(pc->arr[i].name, n))
    		{
    			return i;
    		}
    	}
    	return -1;
    }
    
    //删除void DeleContact(struct Contact* pc);
    
    void DeleContact(struct Contact* pc)
    {
    	assert(pc);
    	char n[MAX_NAME];
    	printf("请输入查找联系人的名字:>");
    	scanf("%s", n);
    	int ret = FindByName(pc, n);
    	if (ret == -1)
    		printf("该联系人不存在\n");
    	else
    	{
    		//删除
    		for (int j = ret; j < pc->sz - 1; j++)
    		{
    			pc->arr[j] = pc->arr[j + 1];
    		}
    		//记得减减!!!!
    		pc->sz--;
    		printf("成功删除指定联系人\n");
    		//方法2,qsort排序,将要删除的人的数据改为0,再qsort排序一下也行,同样记得pc->sz--;
    	}
    
    
    }
    
    //修改
    void ModifyContact(struct Contact* pc)
    {
    	assert(pc);
    	printf("请输入要修改人的名字:>");
    	char name[MAX_NAME];
    	scanf("%s", name);
    	int ret = FindByName(pc, name);
    	if (ret == -1)
    		printf("要修改的人不存在\n");
    	else
    	{
    		//将要修改的人的信息重新录入,并提示修改成功!
    		printf("请输入名字:>");
    		scanf("%s", pc->arr[ret].name);
    		printf("请输入性别:>");
    		scanf("%s", pc->arr[ret].sex);
    		printf("请输入年龄:>");
    		scanf("%d", &(pc->arr[ret].age));
    		printf("请输入电话:>");
    		scanf("%s", pc->arr[ret].telephone);
    
    		printf("修改成功\n");
    	}
    }
    
    //查找
    void SearchContact(const struct Contact* pc)
    {
    	assert(pc);
    	char name[MAX_NAME];
    	printf("请输入要查找的人的名字:>");
    	scanf("%s", name);
    	//查找一下指定的人是否存在
    	int ret = FindByName(pc, name);
    	if (ret == -1)
    		printf("要查找的人不存在\n");
    	else
    	{
    		printf("%-20s\t%-5s\t%-5s\t%-12s\n", "姓名", "性别", "年龄", "电话");
    		printf("%-20s\t%-5s\t%-5d\t%-12s\n", pc->arr[ret].name,
    			pc->arr[ret].sex,
    			pc->arr[ret].age,
    			pc->arr[ret].telephone);
    	}
    }
    
    //显示联系人
    void ShowContact(const struct Contact* pc)
    {
    	assert(pc);
    	int i = 0;
    	printf("%-20s\t%-5s\t%-5s\t%-12s\n", "姓名", "性别", "年龄", "电话");
    	for (i = 0; i < pc->sz; i++)
    	{
    		printf("%-20s\t%-5s\t%-5d\t%-12s\n", pc->arr[i].name,
    			pc->arr[i].sex,
    			pc->arr[i].age,
    			pc->arr[i].telephone);
    	}
    }
    
    //按照名字排
    //大家也可以自己写一个使用年龄排序的代码
    int cmp_name(const void* e1, const void* e2)
    {
    	return strcmp(((struct PeoInfo*)e1)->name, ((struct PeoInfo*)e2)->name);//这里排的是升序
    }
    
    void SortContact(const struct Contact* pc)
    {
    	assert(pc);
    	qsort(pc->arr, pc->sz, sizeof(pc->arr[0]), cmp_name);
    	printf("排序成功!结果如下:\n");
    	//在tect.c文件中在调用一次ShowContact函数即可
    }
    
    //退出通讯录的最后一定要记得释放空间!!!!!
    void Destroy(struct Contact* pc) 
    {
    	free(pc->arr);
    	pc->arr = NULL;
    }
    

    最终的代码

    下面就给出有关test.c和contact.h的相关代码。
    test.c

    #include "contact.h"
    
    enum ST
    {
    	退出通讯录,//0
    	增加联系人,//1
    	删除联系人,//2
    	修改联系人,//3
    	查找联系人,//4
    	显示联系人,//5
    	排序联系人//6
    };
    
    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;
    	//创建通讯录
    	struct Contact contact;
    	//初始化通讯录数组
    	InitContact(&contact);
    
    	do
    	{
    		menu();
    		printf("请选择:>");
    		scanf("%d", &input);
    		switch (input)
    		{
    		case 增加联系人:
    			ADDContact(&contact);
    			system("pause");
    			system("cls");
    			break;
    		case 删除联系人:
    			DeleContact(&contact);
    			system("pause");
    			system("cls");
    			break;
    		case 修改联系人:
    			ModifyContact(&contact);
    			system("pause");
    			system("cls");
    			break;
    		case 查找联系人:
    			SearchContact(&contact);
    			system("pause");
    			system("cls");
    			break;
    		case 显示联系人:
    			ShowContact(&contact);
    			system("pause");
    			system("cls");
    			break;
    		case 排序联系人:
    			//qsort排序
    			SortContact(&contact);
    			ShowContact(&contact);
    			system("pause");
    			system("cls");
    			break;
    		case 0:
    			//释放指针-当程序退出的时候,释放掉自己开创的空间,防止内存泄露!!
    			Destroy(&contact);
    			printf("再见!\n");
    			break;
    		default:
    			printf("选择错误,请重新选择!\n");
    			break;
    		}
    	} while (input);
    	
    	return 0;
    }
    

    contact.h

    #include  
    #include 
    #include 
    #include 
    #include 
    #include 
    
    //方便以后的修改
    #define MAX_NAME 30
    #define SEX 6
    #define TelePhone 13
    
    //联系人信息
    struct PeoInfo
    {
    	char name[MAX_NAME];
    	char sex[SEX];
    	int age;
    	char telephone[TelePhone];
    };
    
    //通讯录结构体
    struct Contact
    {
    	//创建sz的目的是为了在进行添加删除等操作时,好找到元素的下标
    	int sz;
    	struct PeoInfo* arr;
    	int capacity;//容量大小.
    };
    
    void InitContact(struct Contact* pc);
    
    void ADDContact(struct Contact* pc);
    
    void DeleContact(struct Contact* pc);
    
    void ModifyContact(struct Contact* pc);
    
    void SearchContact(const struct Contact* pc);
    
    void ShowContact(const struct Contact* pc);
    
    void SortContact(const struct Contact* pc);
    
    void Destroy(struct Contact* pc);
    

    热心老铁,在线答疑!

  • 相关阅读:
    数据库问题汇总
    Java#数据结构----1
    121. 买卖股票的最佳时机
    Day 64 栈的顺序和链式存储 队列
    优化您的Spring应用程序:缓存注解的精要指南
    SqueezeNet 一维,二维网络复现 pytorch 小白易懂版
    【LIN总线测试】——LIN从节点物理层测试
    flink 1.13.2的pom.xml文件模板
    【SpringBoot】实现引入登录时的验证码功能
    idea远程拉取新项目
  • 原文地址:https://blog.csdn.net/Javaxaiobai/article/details/127041187