当前位置:首页 » 《休闲阅读》 » 正文

C语言实现通讯录(静态版)_chuxinchangcun的博客

14 人参与  2022年02月01日 11:43  分类 : 《休闲阅读》  评论

点击全文阅读


前言:之前,博主已经写过两个有意思的小项目:三子棋和扫雷,接下来,博主继续更新一个小项目-通讯录,包括3种版本,静态版,动态版,文件保存版。接下来,我们先讲解如何实现静态版。


目录

一.静态通讯录的概要

二.静态通讯录接口函数实现

1.静态通讯录的基本结构

2.游戏框架(供用户选择)

3.初始化通讯录

4.打印通讯录

5.增加成员

6.判断通讯录是否为空

7.查找函数

8.删除指定联系人

9.查找指定联系人

10.修改指定联系人

11.以名字排序联系人

12.以年龄排序联系人

13.清空通讯录


一.静态通讯录的概要

静态通讯录:使用的是定长数组,即数组的长度不能发生改变。我们可以设置通讯录可以记录的成员个数为1000个。


二.静态通讯录接口函数实现

文件名功能
Contact.c通讯录函数接口的实现
Contact.h宏定义,头文件,接口函数的声明
test.c函数接口测试


1.静态通讯录的基本结构

通讯录是一个结构体。

包含:1.通讯录成员数组,每一个通讯录成员又是一个结构体,包括:地址,姓名,年龄,性别,地址,电话。

          2.标志通讯录成员个数的变量。

注意:为了方便后序更改通讯录的各种大小,推荐使用宏定义


//注意宏定义后面不要跟分号!!!!不然会有问题
#define NAME_MAX 30	//名字最大长度
#define SEX_MAX 5		//性别最大长度
#define TELE_MAX 12	//电话最大长度
#define ADDR_MAX 30	//地址最大长度

#define MAX 1000	//通讯录数组的成员总数

typedef struct PeoInfo
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char addr[ADDR_MAX];
	char tele[TELE_MAX];
}PeoInfo;

struct Contact	//通讯录
{
	PeoInfo data[MAX];	//结构体成员数组
	int size;	//标志通讯录中所含成员个数, 控制数组下标
};

2.游戏框架(供用户选择)

enum Option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	DESTORY,
};
void menu()
{
	printf("******************************\n");
	printf("****  1. add     2. del  *****\n");
	printf("****  3. search  4. modify****\n");
	printf("****  5. show    6. Destory   ***\n");
	printf("****  0. exit               **\n");
	printf("******************************\n");
}
int main()
{
	int input = 0;
	struct Contact con;	//创建通讯录,内含MAX个结构体成员
	InitContact(&con);	//初始化通讯录
	do
	{
		menu();
		printf("请选择->\n");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			ADDContact(&con);
			break;
		case DEL:
			DelContact(&con);
			break;
		case SEARCH:
			SearchContact(&con);
			break;
		case MODIFY:
			ModifyContact(&con);
			break;
		case SHOW :
			ShowContact(&con);
			break;
		case DESTORY:
			DesContact(&con);
			break;
		case EXIT:
			printf("退出成功!欢迎再次使用!\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

3.初始化通讯录

使用memset初始化通讯录成员数组


写法1:每个成员的大小*成员个数 

void InitContact(struct Contact* ps)
{
	assert(ps);
	//最初没有数据
	memset(ps->data, 0, sizeof(PeoInfo) * MAX);	//通讯录成员数组初始化为0
	ps->size = 0;//默认成员为0
}

写法2:数组单独放在sizeof内部->计算的是整个数组的大小 

//写法2
void InitContact(struct Contact* ps)
{
	memset(ps->data, 0, sizeof(ps->data));	
//ps->data拿到了通讯录中PenInfo数组的数组名
//数组名单独放在sizeof内部,计算的是整个数组的大小
	ps->size = 0;
}

4.打印通讯录

为了更直观,我们可以把标题也进行打印。通过遍历通讯录成员数组,即可把成员打印出来。

//这是右对齐 如果想要左对齐-> -%30d前面加符号  在%前面数字加负号
void ShowContact(struct Contact* ps)
{
	int i = 0;
	//打印标题
    printf("%15s\t%5s\t%8s\t%15s\t%30s\t\n\n", "name", "age", "sex", "tele", "addr");

	//打印数组中每个结构体成员的内容
	for (i = 0; i < ps->size; i++)
	{
		printf("%15s\t%5d\t%8s\t%15s\t%30s\n",
			ps->data[i].name,
			ps->data[i].age,
			ps->data[i].sex,
			ps->data[i].tele,
			ps->data[i].addr);
	}
}

5.增加成员

写法1:直接对通讯录成员数组进行操作

void ADDContact(struct Contact* ps)
{
	//先判断通讯录是否满了
	if (ps->size == MAX)
	{
		printf("通讯录已满\n");
	}
	else
	{
		printf("请输入名字:");
		scanf("%s", ps->data[ps->size].name);	//数组名不用&
		printf("请输入年龄: ");
		scanf("%d", &(ps->data[ps->size].age));
		printf("请输入地址:");
		scanf("%s", ps->data[ps->size].addr);
		printf("请输入号码:");
		scanf("%s", ps->data[ps->size].tele);
		printf("请输入性别:");
		scanf("%s", ps->data[ps->size].sex);

		printf("添加成功\n");
		ps->size++;	//添加了一个成员,size++
	}
}

 写法2:先创建一个临时结构体成员,然后赋值后,赋给通讯录结构体数组中ps->size位置

//增加成员的写法2:
void ADDContact(struct Contact* ps)
{
	PeoInfo tmp = { 0 };
	//先判断通讯录是否满了
	if (ps->size == MAX)
	{
		printf("通讯录已满\n");
	}
	else
	{
		printf("请输入名字:");
		scanf("%s", tmp.name);	//数组名不用&
		printf("请输入年龄: ");
		scanf("%d", &(tmp.age));
		printf("请输入地址:");
		scanf("%s", tmp.addr);
		printf("请输入号码:");
		scanf("%s", tmp.tele);
		printf("请输入性别:");
		scanf("%s", tmp.sex);

		ps->data[ps->size] = tmp;
		printf("添加成功\n");
		ps->size++;
	}
}

6.判断通讯录是否为空

因为size 标志的是通讯录中的成员个数,所以只要判断size是否为0即可知道通讯录是否为空

//如果为空,判断成立,返回1
bool EmptyContact(struct Contact* ps)
{
    return ps->size == 0;
}

7.查找函数

因为后续删除指定联系人,更改指定联系人的信息都需要进行查找,所以可以把查找函数单独封装

找到了,返回对应的下标,找不到返回-1

因为不作修改,所以可以加上const修饰

方法:遍历结构体成员数组进行查找

int FindContactByName(const struct Contact* ps,const char*name )
{
    //遍历查找
    int i = 0;
    for(i = 0;i< ps->size;i++)
    {
        if( strcmp(name,ps->data[i].name) == 0)
        {
            //返回下标
            return i;
        }
    }
    return -1;
}

8.删除指定联系人

注意:删除联系人->从该位置开始后面的数据往前覆盖

如通讯录为空,则不删除,直接返回.

void DelContact(struct Contact* ps)
{
	if (EmptyContact(ps))
	{
		printf("通讯录为空,无法删除\n");
		return ;
	}
	char name[NAME_MAX] = { 0 };	//用来存储要删除的指定联系人的名字
	printf("请输入要删除人得名字:>");
	scanf("%s",name);
	//查找
	int pos = FindContactByName(ps, name);
	if (pos == -1)
	{
		printf("指定的联系人不存在\n");
	}
	else
	{
		//删除操作
		//从pos位置开始,后面的往前覆盖
		int i = 0;
		for (i = pos; i < ps->size - 1; i++)
		{
			ps->data[i] = ps->data[i + 1];
		}
		//删除了元素,size--
		ps->size--;
		printf("删除成功\n");
	}
}

9.查找指定联系人

方法:输入要查找的联系人名字,调用查找函数进行查找,若找到,返回对应下标,就把该下标对应的联系人对应信息打印出来

void SearchContact(const struct Contact* ps)
{
    char name[NAME_MAX] = {0};
    printf("输入要查找的联系人:>");
    scanf("%s",name);
    int pos  =FindContactByName(ps,name);
    if(pos == -1)
    {
        printf("要查找的联系人不存在\n");
    }
    else
    {
        // 打印该联系人对应的信息
		//打印标题       
        printf("%15s\t%5s\t%8s\t%15s\t%30s\t\n\n", "name", "age", "sex", "tele", "addr");
		printf("%15s\t%5d\t%8s\t%15s\t%30s\n",
			ps->data[pos].name,
			ps->data[pos].age,
			ps->data[pos].sex,
			ps->data[pos].tele,
			ps->data[pos].addr);
	}
    }
}

10.修改指定联系人

方法:输入要查找的联系人名字,调用查找函数进行查找,找到了返回对应下标,然后修改对应数组下标的内容

void ModifyContact(struct Contact* ps)
{
	char name[NAME_MAX] = { 0 };
	printf("请输入要修改人名字:>");
	scanf("%s", name);
	int pos = FindContactByName(ps, name);
	if (-1 == pos)
	{
		printf("查无此人\n");
	}
	else
	{
		printf("请输入新名字:");
		scanf("%s", ps->data[pos].name);	//数组名不用&
		printf("请输入新年龄: ");
		scanf("%d", &(ps->data[pos].age));
		printf("请输入新地址:");
		scanf("%s", ps->data[pos].addr);
		printf("请输入新号码:");
		scanf("%s", ps->data[pos].tele);
		printf("请输入新性别:");
		scanf("%s", ps->data[pos].sex);
	}
}

11.以名字排序联系人

相当于字符串比较->使用strcmp

这里可以使用两种方法:冒泡排序或者qsort排序

关于qsort:qsort函数详解


 比较的是通讯录成员数组中的成员名字!!!

void SortContact(struct Contact* pcon)
{
  int i, j;
  struct PeoInfo tmp;
  for(i = 0; i < pcon->sz - 1; i++)
 {
    for(j = 0; j < pcon->sz - 1 - i; j++)
   {
      if(0 < strcmp(pcon->data[j].name, pcon->data[j + 1].name))
     {
        tmp = pcon->data[j];
        pcon->data[j] = pcon->data[j + 1];
        pcon->data[j + 1] = tmp;
     }
   }
 }
}

void SortContactByName(struct Contact* ps)
{
	qsort(ps->data, ps->size, sizeof(ps->data[0]), cmp_ContactByName);
}

int cmp_ContactByName(const void* e1, const void* e2)
{
	return strcmp( ((struct PeoInfo*)e1)->name, ((struct PeoInfo*)e2)->name);
}
//注意
//  ((struct PeoInfo*)e1)->name 要括起来,
//  (struct PeoInfo*)e1->name  这样写是错误的

12.以年龄排序联系人

注意排序的是通讯录里面的成员数组ps->data:每个元素的类型为struct PenInfo ( 结构体成员类型)要排序的个数为ps->size

size标志的是通讯录成员个数

比较函数:比较的是成员的年龄

void SortContact(struct Contact* ps)
{
	qsort(ps->data, ps->size, sizeof(ps->data[0]), cmp_ContactbyAge);
}

int cmp_ContactbyAge(const void* e1, const void* e2)
{
	return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
}

13.清空通讯录

清空通讯录:相当于堆通讯录重新初始化.

void ClearContact(Contact* pcon)
{
    InitContact(pcon);
}

三.静态通讯录的缺点

成员有限:容易造成空间浪费/空间不够的情况。

为了解决这个问题,下一篇文章,博主将会带大家了解动态通讯录.

很感谢你能看到这里,~如果感觉对你有帮助,欢迎给博主一个三连呀~



点击全文阅读


本文链接:http://zhangshiyu.com/post/34149.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1