通讯录的实现(结构体与枚举的应用)

目录

一、准备

1.头文件

2.Contact.c

二、具体实现

1.初始化

2.添加新联系人

3.打印联系人

4.删除联系人

5.调整联系人信息

6.查找联系人

7.排序通讯录(按名字首字母)


一、准备

 包含两个.c文件和一个头文件,与三子棋和扫雷类似(具体看我往期博客)

1.头文件

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>

#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 6
#define TELENUM_MAX 12
#define ADDRESS_MAX 30

typedef struct PeoInfo
{
	char Name[NAME_MAX];
	char Sex[SEX_MAX];
	int Age;
	char TeleNum[TELENUM_MAX];
	char Address[ADDRESS_MAX];
}PeoInfo;

typedef struct Contact
{
	PeoInfo data[MAX];
	int sz;
}Contact;

void InitContact(Contact* pc);

void AddContact(Contact* pc);

int FindByName(const Contact* pc, char Name[]);

void DelContact(Contact* pc);

void PrintContact(const Contact* pc);

void SearchByName(const Contact* pc);

void ModifyContact(Contact* pc);

void SortContact(Contact* pc);

void Menu();

int cmp_peo_by_name1(const void* p1, const void* p2);

int cmp_peo_by_name2(const void* p1, const void* p2);

1.包含库函数

2.定义全局变量,方便修改

3.创建struct PeoInfo的结构体变量,相当于通讯录的一页,元素包括姓名,年龄,性别,电话号码,地址,再转换数据类型名为PeoInfo

4.再创建Contact的结构体变量,包含结构体数组和页数,数组每个成员为PeoInfo,相当于整本通讯录

5.存放所有函数的声明

2.Contact.c

#include "contact.h"

enum Option
{
	EXIT,
	ADD,
	SEARCH,
	DELE,
	MODIFY,
	SORT,
	PRINT
};

void menu()
{
	printf("_________________CONTACT___________________\n");
	printf("|**********  1.add   2.search  ***********|\n");
	printf("|**********  3.del   4.modify  ***********|\n");
	printf("|**********  5.sort  6.print   ***********|\n");
	printf("|**********  0.exit            ***********|\n");
}

int main()
{
	Contact con;
	int input = 0;
	InitContact(&con);
	do
	{
		int ret = 0;
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DELE:
			DelContact(&con);
			break;
		case SEARCH:
			SearchByName(&con);
			break;
		case MODIFY:
			ModifyContact(&con);
			break;
		case SORT:
			SortContact(&con);
			break;
		case PRINT:
			PrintContact(&con);
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

1.创建结构体变量con

2.初始化con

3.利用do while语句循环实现通讯录多种功能重复使用,创建枚举类型使得关键字成为自然数常量,赋予其意义。

二、具体实现

1.初始化

void InitContact(Contact* pc)
{
	assert(pc);

	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
}

1.传过来结构体地址,接收为结构体指针

2.确保pc不为空指针

3.将页数初始化为0

4.利用memset,

2.添加新联系人

void AddContact(Contact* pc)
{
	if (pc->sz == MAX)
	{
		printf("通讯录已满,无法添加新信息\n");
        return;
	}
	printf("请输入名字:>");
	scanf("%s", pc->data[pc->sz].Name);
	printf("请输入年龄:>");
	scanf("%d", &pc->data[pc->sz].Age);
	printf("请输入性别:>");
	scanf("%s", pc->data[pc->sz].Sex);
	printf("请输入电话号码:>");
	scanf("%s", pc->data[pc->sz].TeleNum);
	printf("请输入地址:>");
	scanf("%s", pc->data[pc->sz].Address);
	pc->sz++;
	printf("添加成功\n");
}

1.pc为结构体指针,通过->找到成员,当页数满了后不能添加新联系人

2.pc->data找到结构体数组,而pc->sz找到数组下标,即PeoInfo结构体,通过.找到结构体成员

3.最后pc->sz++,增加页数

4.除了age以外其他都为数组首元素地址,因此age需要&

效果示意gif

3.打印联系人

void PrintContact(const Contact* pc)
{
	assert(pc);

	int i = 0;
	printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话号码", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[i].Name, pc->data[i].Age, pc->data[i].Sex, pc->data[i].TeleNum, pc->data[i].Address);
	}
}

       1.打印时使用左对齐

       2.使用for循环遍历结构体数组

效果图

4.删除联系人

void DelContact(Contact* pc)
{
	assert(pc);

	if (pc->sz == 0)
	{
		printf("通讯录已空,无法删除、\n");
		return;
	}
	char Name[NAME_MAX] = { 0 };
	printf("请输入要删除人的名字:>");
	scanf("%s", Name);
	int pos = FindByName(pc, Name);
	if (pos == -1)
	{
		printf("要调整的人不存在,请重新输入\n");
		return;
	}
	int j = 0;
	for (j = pos; j < pc->sz-1; j++)
	{
		pc->data[j] = pc->data[j + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

 

 1.删除的原理为用后面一组数据覆盖前面一组

 2.当页数为0,或找不到目标联系人时提前结束函数(return)

int FindByName(const Contact* pc, char Name[])
{
	assert(pc);

	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (0 == strcmp(Name, pc->data[i].Name))
		{
			return i;
		}
	}
	return -1;
}

1.遍历整个结构体数组,利用strcmp比对输入数组与PeoInfo中的Name数组

2.找到后return当前下标,else return -1

 效果图

5.调整联系人信息

void ModifyContact(Contact* pc)
{
	assert(pc);

	if (pc->sz == 0)
	{
		printf("通讯录已空,无法查找\n");
		return;
	}
	int input = 0;
	char Name[NAME_MAX] = { 0 };
	printf("请输入你要调整的联系人:>\n");
	scanf("%s", Name);
	int pos = FindByName(pc, Name);
	if (pos == -1)
	{
		printf("要调整的人的信息不存在,请重新输入\n");
		return;
	}
	printf("请输入你需要调整的信息\n");
	getchar();
	Menu();
	do
	{ 
		scanf("%d", &input);
		switch (input)
		{
		case NAME:
			printf("请输入需要修改的姓名\n");
			scanf("%s", pc->data[pos].Name);
			break;
		case AGE:
			printf("请输入需要修改的年龄\n");
			scanf("%d", &pc->data[pos].Age);
			break;
		case SEX:
			printf("请输入需要修改的性别\n");
			scanf("%s", pc->data[pos].Sex);
			break;
		case TELENUM:
			printf("请输入需要修改的电话号码\n");
			scanf("%s", pc->data[pos].TeleNum);
			break;
		case ADDRESS:
			printf("请输入需要修改的地址\n");
			scanf("%s", pc->data[pos].Address);
			break;
		case EXIT:
			printf("退出查找\n");
			return;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input<=0 || input>=5);
	printf("修改成功\n");
}
void Menu()
{
	printf("__________________INFORMATION_____________________\n");
	printf("|**********  1.Name      2.Age     **************|\n");
	printf("|**********  3.Sex       4.TeleNum **************|\n");
	printf("|**********  5.Address   0.Exit    **************|\n");
}
enum Option1
{
    EXIT,
	NAME,
	AGE,
	SEX,
	TELENUM,
	ADDRESS
};

1.利用之前写的FindByName找到目标的pos

2.用getchar把缓冲区的\n吃掉

3.同理创建枚举常量

4.创建菜单选择需要更改的信息

 效果图

6.查找联系人

void SearchByName(const Contact* pc)
{
	assert(pc);

	int i = 0;
	char Name[20] = { 0 };
	printf("请输入需要查找的名字\n");
	scanf("%s", &Name);
	for (i = 0; i < pc->sz; i++)
	{
		if (0 == strcmp(Name, pc->data[i].Name))
		{
			printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话号码", "地址");
			printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[i].Name, pc->data[i].Age, pc->data[i].Sex, pc->data[i].TeleNum, pc->data[i].Address);
			return;
		}
	}
	printf("找不到目标名字\n");
}

与FineByName同理,不过函数类型是void,直接函数内打印不返回任何值

7.排序通讯录(按名字首字母)

void SortContact(Contact* pc)
{
	assert(pc);

	int input = 0;
	if (pc->sz == 0)
	{
		printf("通讯录已空,无法排序\n");
		return;
	}
	printf("请选择排升序还是降序\n1.升序 2.降序 0.退出排序\n");
	scanf("%d", &input);
	do
	{
		switch (input)
		{
		case ASC:
			qsort(pc->data, (size_t)pc->sz, (size_t)sizeof(PeoInfo), cmp_peo_by_name1);
			break;
		case DEASC:
			qsort(pc->data, (size_t)pc->sz, (size_t)sizeof(PeoInfo), cmp_peo_by_name2);
			break;
		case EXIT:
			return;
			break;
		default:
			printf("选择错误,请重新输入\n");
			break;
		}
	} while (input < 0 || input>2);
	printf("排序成功\n");
}

 1.排序要考虑升序与降序的情况

 2.qsort第一个参数(Contact),data结构体数组,(PeoInfo)的首结构体地址

 3.第三个为全部PeoInfo结构体的字节大小

4.比较函数中需要强制类型转换为结构体指针,然后->目标成员

5.枚举类型Option2中T为凑数成员,因为EXIT已经在Option1中定义

效果图

                                                                                                                                     

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值