0
点赞
收藏
分享

微信扫一扫

学会编写一个简单的通讯录

Separes 2023-03-24 阅读 45

要完成一个通讯录,首先我们要有一个简单的界面

界面代码:

#include<stdio.h>
void menu()
{
  printf("******************************\n");
	printf("*****1.Add******2.Del*********\n");
	printf("******3.Ser****4.Mod**********\n");
	printf("******5.Show  6.ALL_DEL  *****\n");
	printf("*****0.Exit   7.SORT**********\n");
	printf("******************************\n");
	printf("******************************\n");
}
int main()
{
  int input = 0;
  do
  {
   menu();
   printf("请选择-》\n");
   scanf("%d",&input);
   switch(input)
   {
   case 0:
   printf("退出通讯录\n");
   break;
   case 1:
         //这里写添加人员信息函数
         break;
   case 2:
        //这里写删除指定人员信息函数
        break;
   case 3:
       //这里写查找指定人员信息函数
       break;
   case 4:
       //这里写修改指定联系人信息函数
       break;
   case 5:
       //这里写展示已储存所有人员信息函数
       break;
   case 6:
       //这里写删除所有储存联系人的函数
       break;
   case 7:
       //这里写按名字或年龄排序的函数
       break;
    default:
    printf("选择错误请重新选择\n");
   }
  }while(input);
  return 0;
}

因为我打算写的这个通讯录应该具有添加联系人,删除联系人,查找特定联系人,修改特定联系人,展示已储存的联系人,删除所有练习人的信息,按名字或年龄排序联系人,最后退出通讯录,所以我做的这个简单的界面就显示了这些功能。

但是我们很快就会发现一个问题那就是当我们写代码的时候若没有注释,我们不知道1,2这些数字到底要我们完成什么函数,所以这时候就需要运用到我们的枚举了

修改上面的代码

#include<stdio.h>
void menu()
{
    printf("******************************\n");
    printf("*****1.Add******2.Del*********\n");
    printf("******3.Ser****4.Mod**********\n");
    printf("******5.Show  6.ALL_DEL  *****\n");
    printf("*****0.Exit   7.SORT**********\n");
    printf("******************************\n");
    printf("******************************\n");
}
enum Option
{
    EXIT,
    ADD,
    DEL,
    SER,
    MOD,
    SHOW,
    ALL_DEL,
    SORT
};
int main()
{
    int input = 0;
    do
    {
        menu();
        printf("请选择-》\n");
        scanf("%d", &input);
        switch (input)
        {
        case EXIT:
            printf("退出通讯录\n");
            break;
        case ADD:
            //这里写添加人员信息函数
            printf("添加信息\n");
            break;
        case DEL:
            //这里写删除指定人员信息函数
            printf("添加信息\n");
            break;
        case SER:
            //这里写查找指定人员信息函数
            printf("添加信息\n");
            break;
        case MOD:
            //这里写修改指定联系人信息函数
            printf("添加信息\n");
            break;
        case SHOW:
            //这里写展示已储存所有人员信息函数
            printf("添加信息\n");
            break;
        case ALL_DEL:
            //这里写删除所有储存联系人的函数
            printf("添加信息\n");
            break;
        case SORT:
            //这里写按名字或年龄排序的函数
            printf("添加信息\n");
            break;
        default:
            printf("选择错误请重新选择\n");
        }
    } while (input);
    return 0;
}

运行逻辑验证

学会编写一个简单的通讯录_#define

没有问题,同时使用枚举,能让我们再没有注释和不去看菜单的情况下知道这里要写什么函数。

接下来我们就先去实现增加一个成员信息的函数。

首先对于一个通讯录肯定会有它的容量我们这里就用define定义一个宏,让其作为通讯录的容量,

然后一个通讯录肯定是一个结构体,而它的成员1肯定就是一个人的信息,而一个人的信息又有很多所以一个人的信息肯定也是结构体。

现在我们就来写这两个结构体。

#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_ADDR 20
#define MAX_TEL 20
typedef struct PerInfo//一个人的信息
{
    char name[MAX_NAME];//名字
    int age;//年龄
    char sex[MAX_SEX];//性别
    char tel[MAX_TEL];//电话
    char add[MAX_ADDR];//地址
}PerInfo;//因为作为通讯录最好能够修改最大名字的空间所以我们用宏,便于我们修改
//当然这只是一个人的信息,而一个通讯录肯定是很多人的信息集合所以
//我们再写一个结构体来代表通讯录
typedef struct COLST
{
    PerInfo data[MAX];//这就是由100个人的信息组成的集合
    int sz;//这个代表当前存储的有效信息个数,例如有一个人的信息,sz就为1
}colst;

我这里使用typedf为这个结构体重新起了一个名字,便于我们使用。

下面我们就在主函数里面创建一个colst 变量作为通讯录

void menu()
{
	printf("******************************\n");
	printf("*****1.Add******2.Del*********\n");
	printf("******3.Ser****4.Mod**********\n");
	printf("******5.Show  6.ALL_DEL  *****\n");
	printf("*****0.Exit   7.SORT**********\n");
	printf("******************************\n");
	printf("******************************\n");
}
enum option
{
	EXIT,
   ADD,
   DEL,
   SER,
   MOD,
   SHOW,
   ALL_DEL,
   SORT
};
int main()
{
	int input = 0;
	colst con;//这个结构体变量就是一个通讯录
	//初始化结构体
	Info_colst(&con);
	do
	{
		menu();
		printf("请选择功能->");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			Add_colst(&con);
			break;
		case DEL:
			Del_colst(&con);
			break;
		case SER:
			SER_colst(&con);
			break;
		case MOD:
			Mod_colst(&con);
			break;
		case SHOW:
			Show_colst(&con);
			break;
		case ALL_DEL:
			All_Del(&con);
			break;
		case SORT:
			Sort_colst(&con);
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,请重新选择:\n");
		}
	} while (input);
	return 0;
}

我这里就先将各个函数的名字和传参类型先写好了,至于为什么是传址调用有两个理由:

1.有的函数例如Add_colst肯定就要修改con的那片空间里的值,所以要采用传地址调用,

2.就算是不需要修改空间内值得函数例如Show_colst如果是传值调用,那么计算机就会新创一个拷贝,这样就会造成空间得浪费,完全没有传址调用号。

现在我们已经有了一个通讯录,首先要做的肯定就是要将这个通讯录给初始化,不然函数栈帧开辟默认储存的值就会妨碍我们,所以我们就来完成第一个初始化函数

初始化函数:Info_colst(&con)

void Info_colst(colst* p)//初始化通讯录
{
	assert(p);//先断言防止传入的是一个空指针
	p->sz = 0;//先将sz初始化为0
	memset(p->data, 0,sizeof(p->data));//再利用memset函数将从data开始的那个空间到之后sizeof(data)的
  //字节数全部初始化为0,因为data为数组名而数组名在sizeof内部最后求出的就是整个数组的大小
}//这样这个函数就完成了

我们调试窗口试一下效果

未初始化前:

学会编写一个简单的通讯录_#define_02

初始化后:

学会编写一个简单的通讯录_初始化_03

可见代码运行成功。

下面我们就来实现第一个Add_colst函数

首先我们需要改变原结构体空间里的值所以传地址,其次我们既然要改变结构体空间里的值所以不需要const修饰,最后函数不需要返回值所以返回值为void

void Add_colst(colst* p)
{
    if (p->sz < MAX)//MAX是我们定义的宏100
    {
        printf("请输入姓名:->");
        scanf("%s", p->data[p->sz].name);
        printf("请输入年龄->:");
        scanf("%d", &p->data[p->sz].age);
        printf("请输入性别->");
        scanf("%s", p->data[p->sz].sex);
        printf("请输入电话->");
        scanf("%s", p->data[p->sz].tel);
        printf("请输入地址->");
        scanf("%s", p->data[p->sz].add);
    }
    else
    {
        printf("空间不足,无法添加\n");
        return;//既然已经无法添加了我们便不再让程序向下运行,防止出现bug
    }
    p->sz++;//成功添加一次信息之后让sz++
    printf("添加信息成功\n");
}

为了验证是否真的将信息储存到了data数组里面,我们就先完成显示已有成员的功能

Show_colst展示已储存信息人员信息,虽然这个函数不需要改变结构体里的值,但为了能少浪费空间我们这里还是传递地址。

void Show_colst(const colst* p)//因为我们只是查看信息并不打算修改信息所以用const修饰
{
    //既然要展示已储存人员的信息,所以首先就要判断是否
    //已有人的信息被储存否则不打印
    assert(p);//断言防止传入空指针
    if (p->sz != 0)
    {
        printf("%-10s %-3s %-4s %-20s %-20s\n", "姓名", "年龄", "性别", "电话", "地址");
        for (int i = 0; i < p->sz; i++)
        {
            printf("%-10s %-3d %-4s %-20s %-20s\n", p->data[i].name, p->data[i].age, p->data[i].sex, p->data[i].tel, p->data[i].add);
        }
    }
    else
    {
        printf("暂未人员信息被储存\n");
        return;
    }
}

现在我们来运行

学会编写一个简单的通讯录_初始化_04

没有出错。继续我们来实现下一个功能,修改指定联系人的信息

Mod_colst函数

void Mod_colst(colst* p)
{
    if (p->sz != 0)
    {
        assert(p);
        int i = 0;
        char na[MAX_NAME] = { 0 };
        printf("请输入要修改人员的名字:");
        scanf("%s", na);
        for (i = 0; i < p->sz; i++)
        {
            if (0 == strcmp(p->data[i].name,na))
            {
                printf("请输入姓名:->");
                scanf("%s", p->data[i].name);
                printf("请输入年龄->:");
                scanf("%d", &p->data[i].age);
                printf("请输入性别->");
                scanf("%s", p->data[i].sex);
                printf("请输入电话->");
                scanf("%s", p->data[i].tel);
                printf("请输入地址->");
                scanf("%s", p->data[i].add);
                return;
            }
        }
        printf("没有查询到该人员信息\n");
        return;
    }
    else
    {
        printf("暂无人员信息被储存,无法修改人员信息\n");
    }
}

学会编写一个简单的通讯录_4s_05

学会编写一个简单的通讯录_初始化_06

接下来我们来完成SER_colst

void SER_colst(const colst* p)//这个函数要我们找特定人员的信息那么就和上一个修改一样,我们要通过名字来找到
//那个人所在的下标然后将其打印出啦,但因为我们不需要修改任意值所以我们使用const修饰
//那么我们可不可以将寻找特定人员写成一个函数呢?
{
    assert(p);
    if (p->sz != 0)
    {
        printf("请输入要查找人员的名字");
        char na[MAX_NAME] = { 0 };
        scanf("%s", na);
        int count = -1;
        count = FindByName(p, na);
        if (count != -1)
        {
            printf("%-10s %-3s %-4s %-20s %-20s\n", "姓名", "年龄", "性别", "电话", "地址");
            printf("%-10s %-3d %-4s %-20s %-20s\n", p->data[count].name, p->data[count].age, p->data[count].sex, p->data[count].tel, p->data[count].add);
            printf("查找完毕\n");
        }
        else
        {
            printf("该人员信息不存在\n");
        }
        
    }
}

FindByName函数:

int FindByName(const colst* p, char* na)
{
    int i = 0;
    for (i = 0; i < p->sz; i++)
    {
        if (0 == strcmp(p->data[i].name, na))
            return i;
    }
    return -1;
}

那么此时上面的修改函数也可以改了:

void Mod_colst(colst* p)
{
    if (p->sz != 0)
    {
        assert(p);
        int i = 0;
        char na[MAX_NAME] = { 0 };
        printf("请输入要修改人员的名字:");
        scanf("%s", na);
        i = FindByName(p, na);
        if (-1 != i)
        {
            printf("请输入姓名:->");
            scanf("%s", p->data[i].name);
            printf("请输入年龄->:");
            scanf("%d", &p->data[i].age);
            printf("请输入性别->");
            scanf("%s", p->data[i].sex);
            printf("请输入电话->");
            scanf("%s", p->data[i].tel);
            printf("请输入地址->");
            scanf("%s", p->data[i].add);
            return;
        }
        if(-1==i)
        printf("没有查询到该人员信息\n");
        return;
    }
    else
    {
        printf("暂无人员信息被储存,无法修改人员信息\n");
    }
}

现在我们继续完成下一个功能,删除功能:

Del_colst函数:

void Del_colst(colst* p)
{
    if (p->sz != 0)
    {
        printf("请输入要删除人的姓名:");
        char na[MAX_NAME] = { 0 };
        scanf("%s", na);
        int i = FindByName(p, na);
        if (-1 != i)
        {
            int j = 0;
            for (j = i; j < p->sz - 1; j++)
            {
                p->data[j] = p->data[j + 1];
            }
            p->sz--;
            printf("删除成功\n");
        }
        else
            printf("查找人员信息不存在\n");
    }
    else
    {
        printf("暂无人员信息被储存\n");
    }
}

我们这里删除的原理就是使用待删除数据的下一组覆盖上一组,以此达到删除的效果。

最后我们来完成排序功能

Sort_colst函数:

int Compare_By_Name(const void* p1, const void* p2)
{
	return strcmp(((PerInfo*)p2)->name, ((PerInfo*)p1)->name);
}
int Compare_By_Age(const void* e1, const void* e2)
{
	return (((PerInfo*)e1)->age - ((PerInfo*)e2)->age);
}
void Sort_colst(colst* p)
{
	assert(p);
	if (p->sz == 0)
	{
		printf("暂未有人被储存,无法排序\n");
		return;
	}
	printf("请选择使用年龄(0)还是名字(1)排序\n");
	int input = -1;
	scanf("%d", &input);
	if (input == 0)
	{
		qsort(p->data, p->sz, sizeof(PerInfo), Compare_By_Name);
	}
	else if (input == 1)
	{
		qsort(p->data, p->sz, sizeof(PerInfo), Compare_By_Age);
	}
	printf("排序完成\n");
}

这里排序运用的是qsort函数。

学会编写一个简单的通讯录_4s_07

运行成功。

至于最后的All_Del函数直接调用以此初始化函数就可以了

void All_Del(colst* p)
{
	int input = -1;
	do
	{
		printf("请确定是否需要删除全部联系人的资料\n");
		printf("如果是请输入1取消则输入2");
		scanf("%d", &input);
		if (input == 2)
		{
			printf("取消删除\n");
			return;
		}
		else if (input == 1)
		{
			Info_colst(p);
			printf("删除成功\n");
			return;
		}
		printf("选择错误,请重新选择\n");
	} while (input);
}

最后我们将上面的代码分别存入到不同的头文件,源文件和测试逻辑源文件中就完成了

如下:

头文件

#define MAX_COLST 1000
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TEL 12
#define MAX_ADR 30
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
typedef struct PerInfo//一个人的信息
{
	char name[MAX_NAME];//名字
	int age;//年龄
	char sex[MAX_SEX];//性别
	char tel[MAX_TEL];//电话
	char add[MAX_ADR];//地址
}PerInfo;
typedef struct COLST
{
	PerInfo data[MAX_COLST];
	int sz;
}colst;
void Info_colst(colst* p);//初始化通讯录
void Add_colst(colst* p);//添加信息
void Show_colst(const colst* p);//打印现已储存的信息
void Del_colst(colst* p);//删除指定人信息
void SER_colst(const colst* p);//查找指定联系人
void Mod_colst(colst* p);//修改指定联系人
void Sort_colst(colst* p);//排序按照姓名或年龄
void All_Del(colst* p);//删除所有人的信息

测试逻辑源文件:

#include"简易通讯录.h"
void menu()
{
	printf("******************************\n");
	printf("*****1.Add******2.Del*********\n");
	printf("******3.Ser****4.Mod**********\n");
	printf("******5.Show  6.ALL_DEL  *****\n");
	printf("*****0.Exit   7.SORT**********\n");
	printf("******************************\n");
	printf("******************************\n");
}
enum option
{
	EXIT,
   ADD,
   DEL,
   SER,
   MOD,
   SHOW,
   ALL_DEL,
   SORT
};
int main()
{
	int input = 0;
	colst con;//这个结构体变量t就是一个通讯录
	//初始化结构体
	Info_colst(&con);
	do
	{
		menu();
		printf("请选择功能->");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			Add_colst(&con);
			break;
		case DEL:
			Del_colst(&con);
			break;
		case SER:
			SER_colst(&con);
			break;
		case MOD:
			Mod_colst(&con);
			break;
		case SHOW:
			Show_colst(&con);
			break;
		case ALL_DEL:
			All_Del(&con);
			break;
		case SORT:
			Sort_colst(&con);
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,请重新选择:\n");
		}
	} while (input);
	return 0;
}

最后各函数实现源文件:

#include"简易通讯录.h"
void Info_colst(colst* p)//初始化通讯录
{
	assert(p);
	p->sz = 0;
	memset(p->data, 0,sizeof(p->data));
}
void Add_colst(colst* p)
{
	assert(p);
	if (p->sz < 100)
	{
		printf("请输入姓名:->");
		scanf("%s", p->data[p->sz].name);
		printf("请输入年龄->:");
		scanf("%d", &p->data[p->sz].age);
		printf("请输入性别->");
		scanf("%s", p->data[p->sz].sex);
		printf("请输入电话->");
		scanf("%s", p->data[p->sz].tel);
		printf("请输入地址->");
		scanf("%s", p->data[p->sz].add);
	}
	else
	{
		printf("通讯库储存人员已达上线,无法添加");
		return;
	}
	p->sz++;
	printf("添加成功\n");
}
void Show_colst(const colst* p)
{
	assert(p);
	printf("%-10s %-3s %-4s %-20s %-20s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < p->sz; i++)
	{
		printf("%-10s %-3d %-4s %-20s %-20s\n", p->data[i].name, p->data[i].age, p->data[i].sex, p->data[i].tel, p->data[i].add);
	}
}
static int FindByName(colst* p, char na[])//加入了static让这个函数只能在这一个源文件
//使用其它源文件无法使用
{
	int count = -1;
	int i = 0;
	for (i = 0; i < p->sz; i++)
	{
		int ret = strcmp(p->data[i].name, na);
		if (ret == 0)
		{
			return i;
		}
	}
	if (count == -1)
	{
		return -1;
	}
}
void Del_colst(colst* p)
{
	assert(p);
	if (p->sz == 0)
	{
		printf("通讯录暂时没有任何人的信息无法删除\n");
		return;
	}
	printf("请输入要删除人的名字->");
	char na[MAX_NAME];
	scanf("%s", na);
	int count = FindByName(p, na);
	if (count == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	for (int i = count; i < p->sz - 1; i++)
	{
		p->data[i] = p->data[i + 1];
	}
	p->sz--;
	printf("删除完成\n");
}
void SER_colst(const colst* p)
{
	char na[MAX_NAME];
	printf("请输入要查找人的姓名:\n");
	scanf("%s", na);
	int count = FindByName(p, na);
	if (count == -1)
	{
		printf("要查找的人,不存在\n");
		return;
	}
	printf("%-10s %-3s %-4s %-20s %-20s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-10s %-3d %-4s %-20s %-20s\n", p->data[count].name, p->data[count].age
		, p->data[count].sex, p->data[count].tel, p->data[count].add);
	printf("查找完毕\n");
}
void Mod_colst(colst* p)
{
	printf("请输入要修改人的姓名->");
	char na[MAX_NAME];
	scanf("%s", na);
	int count = FindByName(p, na);
	if (count == -1)
	{
		printf("需要修改的人不存在\n");
		return;
	}
	printf("请输入姓名:->");
	scanf("%s", p->data[count].name);
	printf("请输入年龄->:");
	scanf("%d", &p->data[count].age);
	printf("请输入性别->");
	scanf("%s", p->data[count].sex);
	printf("请输入电话->");
	scanf("%s", p->data[count].tel);
	printf("请输入地址->");
	scanf("%s", p->data[count].add);
	printf("修改完毕");
}
int Compare_By_Name(const void* p1, const void* p2)
{
	return strcmp(((PerInfo*)p2)->name, ((PerInfo*)p1)->name);
}
int Compare_By_Age(const void* e1, const void* e2)
{
	return (((PerInfo*)e1)->age - ((PerInfo*)e2)->age);
}
void Sort_colst(colst* p)
{
	assert(p);
	if (p->sz == 0)
	{
		printf("暂未有人被储存,无法排序\n");
		return;
	}
	printf("请选择使用年龄(0)还是名字(1)排序\n");
	int input = -1;
	scanf("%d", &input);
	if (input == 0)
	{
		qsort(p->data, p->sz, sizeof(PerInfo), Compare_By_Name);
	}
	else if (input == 1)
	{
		qsort(p->data, p->sz, sizeof(PerInfo), Compare_By_Age);
	}
	printf("排序完成\n");
}
void All_Del(colst* p)
{
	int input = -1;
	do
	{
		printf("请确定是否需要删除全部联系人的资料\n");
		printf("如果是请输入1取消则输入2");
		scanf("%d", &input);
		if (input == 2)
		{
			printf("取消删除\n");
			return;
		}
		else if (input == 1)
		{
			Info_colst(p);
			printf("删除成功\n");
			return;
		}
		printf("选择错误,请重新选择\n");
	} while (input);
}

在这个文件里有的函数例如那个查找名字的函数被static修饰了,也就意味着这个函数只能在这一个源文件里面使用在其它源文件里无法使用。

当然我的这个通讯录还有很多不足,例如固定死了人员信息为100,不能增加,以及无法处理同名人的情况等。

对于固定为100信息的问题可以使用malloc和realloc函数解决即将静态通讯录,修改为动态的

要修改的内容包括:

头文件:

#include<stdio.h>
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TEL 12
#define MAX_ADR 30
#define Add_Info 2//代表每一次扩容都增加两个人的信息
#define More 3//代表一开始默认的通讯录可以储存三个人的信息
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>
typedef struct PerInfo//一个人的信息
{
	char name[MAX_NAME];//名字
	int age;//年龄
	char sex[MAX_SEX];//性别
	char tel[MAX_TEL];//电话
	char add[MAX_ADR];//地址
}PerInfo;
typedef struct COLST
{
	PerInfo* data;//可以看到这里不再是数组了,因为我们运用malloc开辟空间后将开辟空间的首地址交给data
  //也就相当于了数组。
	int sz;//表示通讯录到第几个了,即若要储存信息能找到
	//这个信息储存的位置。
	int contst;//表示当前通讯录的容量,默认为3,不够扩大空间即可
	//
}colst;
void Info_colst(colst* p);//初始化通讯录
void Add_colst(colst* p);//添加信息
void Show_colst(const colst* p);//打印现已储存的信息
void Del_colst(colst* p);//删除指定人信息
void SER_colst(const colst* p);//查找指定联系人
void Mod_colst(colst* p);//修改指定联系人
void Sort_colst(colst* p);//排序按照姓名或年龄
void All_Del(colst* p);//删除所有人的信息
void Free_Allspace(colst* p);//在退出通讯录后,free掉malloc开辟的空间

测试逻辑源文件:

#include"动态通讯录.h"
void menu()
{
	printf("******************************\n");
	printf("*****1.Add******2.Del*********\n");
	printf("******3.Ser****4.Mod**********\n");
	printf("******5.Show  6.ALL_DEL  *****\n");
	printf("*****0.Exit   7.SORT**********\n");
	printf("******************************\n");
	printf("******************************\n");
}
enum option
{
	EXIT,
	ADD,
	DEL,
	SER,
	MOD,
	SHOW,
	ALL_DEL,
	SORT
};
int main()
{
	int input = 0;
	colst con;//这个结构体变量t就是一个通讯录
	//初始化结构体
	Info_colst(&con);//和静态通讯录不同要做修改
	do
	{
		menu();
		printf("请选择功能->");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			Add_colst(&con);
			break;
		case DEL:
			Del_colst(&con);
			break;
		case SER:
			SER_colst(&con);
			break;
		case MOD:
			Mod_colst(&con);
			break;
		case SHOW:
			Show_colst(&con);
			break;
		case ALL_DEL:
			All_Del(&con);
			break;
		case SORT:
			Sort_colst(&con);
			break;
		case EXIT:
			Free_Allspace(&con);//新增的函数功能已在头文件中说明
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,请重新选择:\n");
		}
	} while (input);
	return 0;
}

最后我们来看实现函数的源文件:

#include"动态通讯录.h"
static int Is_Enough(colst* p)
{
	if (p->sz == p->contst)//如果当前有效数据个数等于了默认的数据数
	//那么添加就需要括容
	{
		p->data=(PerInfo*)realloc(p->data, (p->contst + Add_Info) * sizeof(PerInfo));
		if (p->data == NULL)
		{
			printf("Is_Eough中扩容失败,失败原因为:%s", strerror(errno));
			return 0;
		}
		p->contst += Add_Info;
		printf("扩容成功");
		printf("当前容量为%d\n", p->contst);
		return 1;
	}
	return 1;
}
void Info_colst(colst* p)//初始化通讯录
{
	assert(p);
	p->sz = 0;
	p->contst = More;
	p->data = (PerInfo*)malloc(sizeof(PerInfo) * More);
	if (p->data == NULL)
	{
		printf("Info_colst初始化失败,原因是:%s\n", strerror(errno));
		return NULL;
	}
	else
	{
		printf("初始化成功\n");
	}
}
void Add_colst(colst* p)
{
	assert(p);
	if (1 == Is_Enough(p))
	{
			printf("请输入姓名:->");
			scanf("%s", p->data[p->sz].name);
			printf("请输入年龄->:");
			scanf("%d", &p->data[p->sz].age);
			printf("请输入性别->");
			scanf("%s", p->data[p->sz].sex);
			printf("请输入电话->");
			scanf("%s", p->data[p->sz].tel);
			printf("请输入地址->");
			scanf("%s", p->data[p->sz].add);
			p->sz++;
			printf("添加成功\n");
	}
	else
	{
		printf("通讯录增容失败,无法再次添加信息\n");
		return;
	}
}
void Show_colst(const colst* p)
{
	assert(p);
	printf("%-10s %-3s %-4s %-20s %-20s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < p->sz; i++)
	{
		printf("%-10s %-3d %-4s %-20s %-20s\n", p->data[i].name, p->data[i].age, p->data[i].sex, p->data[i].tel, p->data[i].add);
	}
}
static int FindByName(colst* p, char na[])//加入了static让这个函数只能在这一个源文件
//使用其它源文件无法使用
{
	int count = -1;
	int i = 0;
	for (i = 0; i < p->sz; i++)
	{
		int ret = strcmp(p->data[i].name, na);
		if (ret == 0)
		{
			return i;
		}
	}
	if (count == -1)
	{
		return -1;
	}
}
void Del_colst(colst* p)
{
	assert(p);
	if (p->sz == 0)
	{
		printf("通讯录暂时没有任何人的信息无法删除\n");
		return;
	}
	printf("请输入要删除人的名字->");
	char na[MAX_NAME];
	scanf("%s", na);
	int count = FindByName(p, na);
	if (count == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	for (int i = count; i < p->sz - 1; i++)
	{
		p->data[i] = p->data[i + 1];
	}
	p->sz--;
	printf("删除完成\n");
}
void SER_colst(const colst* p)
{
	char na[MAX_NAME];
	printf("请输入要查找人的姓名:\n");
	scanf("%s", na);
	int count = FindByName(p, na);
	if (count == -1)
	{
		printf("要查找的人,不存在\n");
		return;
	}
	printf("%-10s %-3s %-4s %-20s %-20s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-10s %-3d %-4s %-20s %-20s\n", p->data[count].name, p->data[count].age
		, p->data[count].sex, p->data[count].tel, p->data[count].add);
	printf("查找完毕\n");
}
void Mod_colst(colst* p)
{
	printf("请输入要修改人的姓名->");
	char na[MAX_NAME];
	scanf("%s", na);
	int count = FindByName(p, na);
	if (count == -1)
	{
		printf("需要修改的人不存在\n");
		return;
	}
	printf("请输入姓名:->");
	scanf("%s", p->data[count].name);
	printf("请输入年龄->:");
	scanf("%d", &p->data[count].age);
	printf("请输入性别->");
	scanf("%s", p->data[count].sex);
	printf("请输入电话->");
	scanf("%s", p->data[count].tel);
	printf("请输入地址->");
	scanf("%s", p->data[count].add);
	printf("修改完毕");
}
int Compare_By_Name(const void* p1, const void* p2)
{
	return strcmp(((PerInfo*)p2)->name, ((PerInfo*)p1)->name);
}
int Compare_By_Age(const void* e1, const void* e2)
{
	return (((PerInfo*)e1)->age - ((PerInfo*)e2)->age);
}
void Sort_colst(colst* p)
{
	assert(p);
	if (p->sz == 0)
	{
		printf("暂未有人被储存,无法排序\n");
		return;
	}
	printf("请选择使用年龄(0)还是名字(1)排序\n");
	int input = -1;
	scanf("%d", &input);
	if (input == 0)
	{
		qsort(p->data, p->sz, sizeof(PerInfo), Compare_By_Name);
	}
	else if (input == 1)
	{
		qsort(p->data, p->sz, sizeof(PerInfo), Compare_By_Age);
	}
	printf("排序完成\n");
}
void All_Del(colst* p)
{
	int input = -1;
	do
	{
		printf("请确定是否需要删除全部联系人的资料\n");
		printf("如果是请输入1取消则输入2");
		scanf("%d", &input);
		if (input == 2)
		{
			printf("取消删除\n");
			return;
		}
		else if (input == 1)
		{
			Info_colst(p);
			printf("删除成功\n");
			return;
		}
		printf("选择错误,请重新选择\n");
	} while (input);
}
void  Free_Allspace(colst* p)
{
	free(p->data);
	p->data = NULL;
	printf("堆区空间已清空\n");
}

动态通讯录和静态不同的就是在初始化函数我们开辟空间,以及添加人员时要判断是否需要扩容,需要就用realloc函数扩容,不需要就就行添加。以及最后的结束函数我们要将malloc函数开辟的空间free掉。

希望这篇博客能对你有所帮助,如果发现任何错误,恳请指出,我一定改正。

举报

相关推荐

0 条评论