c实现一个可扩容的通讯录

本文详细解析了如何在C语言中使用二级指针和malloc/realloc函数初始化并动态扩展通讯录结构,展示了AddPersonToContact函数中的关键技巧。通过实例介绍了通讯录增删改查的基本操作,以及如何避免通讯录满载问题。
摘要由CSDN通过智能技术生成

个人觉得这个代码主要难度在于使用二级指针先初始化通讯录容量用malloc()函数,然后realloc()自动增加通讯录容量。
直接看代码:

1.头文件contact.h

#ifndef __CONTACT_H__
#define __CONTACT_H__

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include <windows.h>
#pragma warning(disable:4996)

#define SIZE 128
#define INIT  5      //初始通讯录大小
#define INC_SIZE 2   //每次扩容的大小

typedef struct persons {
	char name[SIZE / 16];
	char telphone[SIZE / 8];
	int age;
	char sex;
	char adress[SIZE / 4];
}person_t;

typedef struct contact {
	int cap;
	int size;
	person_t persons[0];
}contact_t;

void InitContact(contact_t** ct);
void AddPersonToContact(contact_t** ct);
void ShowContact(contact_t* ct,int pos);
void SearchContact(contact_t* ct);
void DelPersonContact(contact_t*  ct);
void ClearContact(contact_t*  ct);
void ModContact(contact_t*  ct);
void SortContact(contact_t*  ct);


#endif

2.main.c

着部分主要为通讯录增删改查的主要逻辑:

#include "contact.h"

static void Menu()
{
	printf("###############################\n");
	printf("# 1. add   2. del   3. search #\n");
	printf("# 4. mod   5. show  6. clear  #\n");
	printf("# 7. sort           0. exit   #\n");
	printf("###############################\n");
	printf("Please Select:> ");
}

int main()
{
	int quit = 0;
	int select = 0;
	contact_t* ct = NULL;
	InitContact(&ct);

	while (!quit) {
		Menu();
		scanf("%d", &select);
		switch (select) {
		case 1:
			AddPersonToContact(&ct);
			break;
		case 2:
			DelPersonContact(ct);
			break;
		case 3:
			SearchContact(ct);
			break;
		case 4:
			ModContact(ct);
			break;
		case 5:
			ShowContact(ct,-1);//参数为-1则显示全部
			break;
		case 6:
			ClearContact(ct);
			break;
		case 7:
			SortContact(ct);
			break;
		default:
			quit = 1;
			break;
		}
	}
	printf("byebye!\n");
	system("pause");
	return 0;
}

3.contact.c

这部分主要为增删改查排序等各个模块功能的具体函数实现:

#include "contact.h"

void InitContact(contact_t** ct) //初始化通讯录大小
{
	*ct =(contact_t*)malloc(sizeof(contact_t) + INIT * sizeof(person_t));
	if (NULL == *ct) {
		printf("malloc error!\n");
		exit(1);
	}
	(*ct)->size = 0;
	(*ct)->cap = INIT;
}

static int  IsFull(contact_t*  ct) //判断通讯录是否满了
{
	assert(ct);
	return ct->size == ct->cap;
}

static int Inc(contact_t** ct) //通讯录扩容
{
	assert(*ct);
	int ret = 0;
	contact_t* p = (contact_t*)realloc(*ct, sizeof(contact_t) + sizeof(person_t) * ((*ct)->cap + INC_SIZE));
	if (NULL != p) {
		printf("realloc success!\n");
		*ct = p;
		ret = 1;
		p->cap = (*ct)->cap + INC_SIZE;
	}
	return ret;
}

static int IsExist(contact_t* ct, char* name)//判断输入的用户是否已经存在
{
	assert(ct);
	person_t* p = ct->persons;
	person_t* end = ct->persons +ct->size;
	int index = 0;
	for (p; p < end; p++, index++) {
		if (0 == strcmp(name, p->name)) {
			return index;
		}
	}
	return -1;
}

void AddPersonToContact(contact_t** ct) //向通讯录中增加用户
{
	assert(*ct);
	if (!IsFull(*ct) || Inc(ct)) {
		person_t* p = (*ct)->persons + (*ct)->size;

		printf("请输入姓名\n");
		char name[SIZE / 16];
		scanf(" %s", name);
		if (IsExist(*ct , name) >= 0) {
			printf("user exist!\n");
			return;
		}
		else {
			strcpy(p->name,name); 
		}

		printf("请输入电话\n");
		scanf(" %s", p->telphone);
		printf("请输入性别\n");
		scanf(" %s", &(p->sex));
		printf("请输入年龄\n");
		scanf(" %d", &(p->age));
		printf("请输入地址\n");
		scanf(" %s", p->adress);
		
		(*ct)->size++;
		printf("add %s success!\n", p->name);
	}
	else {
		printf("扩容失败!\n");
	}
}

void SearchContact(contact_t* ct)  //按姓名查找用户
{
	assert(ct);
	char name[SIZE / 16];
	printf("请输入要查好的联系人姓名:\n");
	scanf("%s", &name);
	int x = IsExist(ct, name);
	if (x >= 0) {
		ShowContact(ct,x);
		return;
	}
	printf("用户不存在!\n");
}

void DelPersonContact(contact_t* ct) //按姓名删除用户
{
	assert(ct);
	char name[SIZE / 16];
	printf("请输入要删除的联系人姓名:\n");
	scanf("%s", &name);
	int index = IsExist(ct, name);
	if (index >= 0) {
		person_t *p = ct->persons+ct->size;
		p[index] = p[ct->size];
		ct->size--;
		printf("delate success!\n");
		return;
	}
	printf("用户不存在!\n");
}

void ClearContact(contact_t* ct)  //清空整个通讯录
{
	assert(ct);
	ct->size = 0;
}

void ModContact(contact_t* ct)   //修改用户信息,只写了修改姓名和电话部分
{
	assert(ct);
	char name[SIZE / 16];
	printf("请输入要修改的联系人姓名:\n");
	scanf("%s", &name);
	int index = IsExist(ct, name);
	person_t* p = ct->persons + index;
	if (index >= 0) {
		ShowContact(ct, index);
		printf("请输入要修改后的联系人姓名:\n");
		scanf(" %s",p->name );
		printf("请输入要修改后的联系人电话:\n");
		scanf(" %s", p->telphone);
		return;
	}
	printf("%s用户不存在!\n",name);
}


void *Cmp(const void * p1, const void* p2) //qsort中需要用到的的回调函数
{
	person_t* x_p = (person_t*)p1;
	person_t* y_p = (person_t*)p2;
	return strcmp(x_p->name, y_p->name);
}
void SortContact(contact_t* ct) //利用qsort函数对通讯录中的姓名进行排序
{
	assert(ct);
	qsort(ct->persons, ct->size,sizeof(person_t),Cmp);
}

void ShowContact(contact_t* ct, int pos)//显示模块  pos = -1 则显示全部  否则显示第pos个用户通讯录信息   即index+1个人的通讯录信息
{
	assert(ct);
	if (pos == -1) {
		if (ct->size == 0) {
			printf("empty!\n");
		}
		printf("当前容量:%d/%d\n", ct->size, ct->cap);
		for (int i = 0; i < ct->size; i++) {
			printf("%10s | %10s\n", ct->persons[i].name, ct->persons[i].telphone);
		}
	}
	else {
		printf("当前容量:%d/%d     %s位于第%d个联系人\n", ct->size, ct->cap, ct->persons[pos].name,pos+1);
		printf("%10s | %10s\n", ct->persons[pos].name, ct->persons[pos].telphone);
	}
}

这部分每个函数要实现的功能我已注释上去了,AddPersonToContact(contact_t** ct)这个函数中需要注意二级指针和一级指针的使用;
由于这只是一个简单的练习版本,没来得及对用户输入的性别年龄等信息并没有做判断是否合法,替他各个部分功能均正常,感兴趣的小伙伴们可以加上用户输入信息的判断。下一步准备将这个代码修改为可将通讯录保存在文件中的,方便存和读取,不用每次进来都重新添加信息。

测试效果:

增加联系人

增加联系人
排序(可以看见 张  和 黄 两个用户信息排序发生了变化),然后修改信息
修改信息后结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值