用C语言实现简易版通讯录

//动态开辟空间//存储文件//读取数据//排列


前言

对于初学者来说,如何用c语言来实现一个简易版的通讯录呢?下面将简单的介绍。

一、通讯录设计思路

1:首先要明白通讯录所存储的信息,如(姓名、性别、年龄、家庭住址、联系方式等)这里我们简单的写上五种,后续如果有需要可以继续添加。

2:创建好信息结构体后我们想接下来该怎么做?提供给用户选择的操作菜单,菜单的功能要有:

  1. 添加联系人信息。
  2. 删除联系人信息。
  3. 查找联系人信息。
  4. 修改通讯录信息
  5. 展示通讯录信息。
  6. 将通讯录信息进行排序(提供多种排序方法供用户选择)。
  7. 保存通讯录。
  8. 退出通讯录。

3:实现函数功能。

4.通讯录主函数展示

//主函数的架构

int main()
{
	int input = 0;
    Contact con;//创建一个通讯录。
	InitContact(&con);//对通讯录进行初始化。
	printf("请选择你要进行的操作。\n");
	do
	{
		menu();//打印菜单。
		scanf("%d", &input);
		switch (input)
		{
		case add: AddContact(&con);//增加联系人信息的函数。
			break;
		case del:DelContact(&con);//删除联系人信息的函数。
			break;
		case search: SearchContact(&con);//查找联系人的函数。
			break;
		case my:  ModifyContact(&con);//修改联系人信息的函数。
			break;
		case show: ShowContact(&con);//展示联系人信息的函数。
			break;
		case sort :SortContact(&con);//排列联系人信息的函数。
			break;
		case exit_: SaveContact(&con);//保存通讯录的内容。
					DesplayInf(&con);//展示目前通讯录的信息。
				    DestoryContact(&con);//摧毁通讯录信息。
				    printf("退出。\n");
		            break;
		case save:  SaveContact(&con);//保存
					break;
        default :
        printf("选择错误请重新选择。\n");
        break;
		}
	} while (input);
	return 0;
}

5:头文件的展示。

#ifndef CONTACT_H_INCLUDED
#define CONTACT_H_INCLUDED

#endif // CONTACT_H_INCLUDED
#include<stdio.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define  _CRT_SECURE_NO_WARNINGS l
#define Initial_capacity 3//初始容量。
#define Quantity_Increase 2//每次扩容增加的数量。
#define Max_name 20   //名字的长度。
#define Max_sex 5     
#define Max_address 20
#define Max_numbers 20
typedef struct PeoInfo //建立一个人信息的结构体。
{
//姓名,性别,年龄,地址,电话号码。
	char name[Max_name];
	char sex[Max_sex];
	int  age;
	char address[Max_address];
	char numbers[Max_numbers];
}PeoInfo;
typedef struct Contact //结构体的结构体
{
	PeoInfo* date;
	int size;
	int Capacity;

}Contact;
enum Option//枚举,增加数据的可读性。
{      
	    exit_,add,del,search,my,show,sort,save//0 1 2 3 4 5 6 7
};
void SortContact(struct Contact *ps);//排序通讯录的内容。
void menu();//打印菜单。
void InitContact(Contact* pc);//动态通讯录初始化。
void CheckCapacity(Contact* pc);//检测通讯录目前容量。
void AddContact(Contact* pc);//增加联系人。
void DelContact(Contact* pc);//删除联系人。
void SearchContact(Contact* pc);//查找联系人。
void ModifyContact(Contact* pc);//修改联系人信息。
void Modify_menu();//修改选项。
void DestoryContact(Contact* pc);//摧毁通讯录。
void SaveContact(Contact* pc);//保存数据。
void LoadingContact(Contact* pc);//从txt文件读取数据。
void ShowContact( Contact* pc);//展示通讯录的信息。
void DesplayInf(Contact* pc);//通讯录目前情况;


//排序函数
void bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2));
void swap(char* e1, char* e2, int width);
int cmp_age( void* e1,  void* e2);
int cmp_name(void* e1, void* e2);
int cmp_address(void* e1, void* e2);
int cmp_numbers(void* e1, void* e2);
int cmp_sex(void* e1, void* e2);

二、主要步骤

1.宏定义通讯录信息,便于修改

#define Initial_capacity 3//初始容量
#define Quantity_Increase 2//每次扩容增加的数量
#define Max_name 20   //名字的长度。
#define Max_sex 5     //性别长度
#define Max_address 20  //地址长度
#define Max_numbers 20 //电话长度

2.创建通讯录信息结构体

通讯录结构体代码如下:

typedef struct PeoInfo //建立一个人信息的结构体。
{
//姓名,性别,年龄,地址,电话号码。
	char name[Max_name];
	char sex[Max_sex];
	int  age;
	char address[Max_address];
	char numbers[Max_numbers];
}PeoInfo;
typedef struct Contact //结构体的结构体
{
	PeoInfo* date; //创建一个PeoInfo*的指针,指向信息结构体。
	int size; //记录目前通讯录所存储的数量。
	int Capacity; //通讯录总容量。

}Contact;

3.菜单的简单设置

//定义一个菜单函数,在主函数打印。
void menu()
{
	printf("*******************************\n");
	printf("***1->添加     2->删除*********\n");
	printf("***3->查找     4->修改*********\n");
	printf("***5->展示     6->排序*********\n");
	printf("***7->保存     0->退出*********\n");

}

4.初始化函数的实现

 在主函数中我们已经进行了传参:InitContact(&con);//对通讯录进行初始化。

我们用Contact*类型的指针进行接收;

pc->date指向malloc函数动态开辟一段空间。

 

 if (pc->date == NULL)
    {
        perror("InitContact");//打印错误消息。
        return ;
    }.

判断是否开辟成功;没开辟成功会让他指向NULL.

 

让通讯录内容和容量都为0.



void InitContact(Contact* pc)//初始化通讯录。
{
    pc->date = (PeoInfo*)malloc(Initial_capacity * sizeof(PeoInfo));//动态开辟一段空间
    if (pc->date == NULL)
    {
        perror("InitContact");//打印错误消息。
        return ;
    }
    pc->size = 0;//让通讯录的信息清零;
    pc->Capacity = Initial_capacity;//容量
    printf("通讯录初始化成功。\n");
    LoadingContact(pc);//加载文件信息。
  //这个函数后面会出现。
}

5.增加通讯录的信息

  • 增加之前我们是不是要考虑通讯录的容量需不需要扩容的问题。因此我们增加一个函数进行判断是否需要进行扩容。

 


void CheckCapacity(Contact* pc)//检测通讯录容量是否满;
{
    PeoInfo* _ = NULL;//创建一个人物信息的结构体指针。
    if (pc->size == pc->Capacity)//目前存储人数和总人数进行比较;
    {
        _ = (PeoInfo*)realloc(pc->date, (pc->Capacity + Quantity_Increase) * sizeof(PeoInfo));
        //realloc对原来malloc开辟的空间将进行扩容。
        //
    }
    if (_ != NULL)
    {
        pc->date = _;//将新开辟的空间交给数据信息指针date
        pc->Capacity += Quantity_Increase;//增加容量
        printf("扩容成功。\n");
    }
    else
    {
        perror("AddContact");
        return;
    }
}

现在进行增加联系人的函数。

void AddContact(Contact* pc)//添加人物信息
{
            CheckCapacity(pc);//检测容量问题
            printf("请输入姓名->");
    		scanf("%s", (pc->date[pc->size].name));
    		printf("请输入年龄->");
    		scanf("%d", &(pc->date[pc->size].age));
    		printf("请输入地址->");
    		scanf("%s", (pc->date[pc->size].address));
    		printf("请输入性别->");
    		scanf("%s", (pc->date[pc->size].sex));
    		printf("请输入电话号码->");
    		scanf("%s", (pc->date[pc->size].numbers));
    		pc->size++;
    		printf("添加成功。\n");
}

6.精确查找联系人

后面的函数实现都要需要对联系人进行精确查找,因此我们写一个函数进行查找。

创立一个静态函数,只在这个项目中使用。

static int FindByName(Contact* pc, char name[])//创建一个静态函数用来查询人物姓名;
{
    int i = 0;
    for (i = 0; i < pc->size; i++)
    {
        if (strcmp(pc->date[i].name ,name)==0)//比较通讯录中人的名字和你所要查找人的名字是否相同 
            return i;//返回这个人在数组中的位置。
    }
    return -1;//表示错误,该通讯录中没有这个人。
}

7.删除联系人信息

void DelContact(Contact* pc)//动态删除。
{
    char name[Max_name] = { 0 };
    if (pc->size == 0)
    {
        printf("通讯录为空,不用删除。\n");
        return;
    }
    printf("请输入你要删除联系人的姓名:   ");
    fscanf(stdin, "%s", name);
   int pos=FindByName(pc, name);//用pos接受FindByName的返回值;
   if (pos == -1)
   {
       printf("通讯录查无此人。\n");
       return;
   }
   int i = 0;
   for (i = pos; i < pc->size - 1; i++)//将要删除的元素用后一个元素覆盖,以此类推
   {
       pc->date[i] = pc->date[i + 1];//实现覆盖信息
   }
   pc->size--;//每进行一次将通讯录的目前存储信息减1
   printf("删除成功。\n");
}

 8.查找联系人

void SearchContact(Contact* pc)//查找联系人
{
    char name[Max_name] = { 0 };
    if (pc->size == 0)
    {
        printf("通讯录为空,无法查找。\n");
        return;
    }
    printf("请输入你要查找联系人的姓名:   ");
    fscanf(stdin, "%s", name);
    int pos = FindByName(pc, name);
    if (pos == -1)
    {
        printf("通讯录查无此人。\n");
        return;
    }
    else
    {
        printf("%-20s\t%-20s\t%-20s\t%-20s\t%-20s\t\n", "姓名", "年龄", "地址", "性别", "电话号码");
               printf("%-20s\t%-20d\t%-20s\t%-20s\t%-20s\t\n",
        		pc->date[pos].name,
        		pc->date[pos].age,
        		pc->date[pos].address,
        		pc->date[pos].sex,
       			pc->date[pos].numbers);
    }
}

9.修改联系人信息

精确修改人物信息

void ModifyContact(Contact* pc)//修改信息
{
    char name[Max_name] = { 0 };
    if (pc->size == 0)
    {
        fprintf(stdout, "通讯录为空。\n");
    }
    fprintf(stdout, "%s\n", "请输入要修改人的姓名。");
    fscanf(stdin, "%s", name);
    int pos = FindByName(pc, name);
    if (pos == -1)
    {
        fprintf(stdout, "该人没在通讯录中,无法进行修改。\n");
    }
    else
    {
        fprintf(stdout, "请选择你要修改的的内容。\n");
        Modify_menu();
        int input_number = 0;
        fscanf(stdin, "%d", &input_number);
        static enum Choice_Modify
        {
            exit, name, age, address, sex, contact_way
        };
        switch (input_number)
        {
        case name:
        {
            char name[Max_name] = { 0 };
            fprintf(stdout, "你想修改为->");
            fscanf(stdin, "%s", name);
            strcpy(pc->date[pos].name, name);
        }break;
        case age:
        {
            int age = 0;
            fprintf(stdout, "你想修改为->");
            fscanf(stdin, "%d", &age);
            pc->date[pos].age = age;
        }break;
        case address:
        {
            char address[Max_address] = { 0 };
            fprintf(stdout, "你想修改为->");
            fscanf(stdin, "%s", address);
            strcpy(pc->date[pos].address, address);
        }break;
        case sex:
        {
            char sex[Max_sex] = { 0 };
            fprintf(stdout, "你想修改为->");
            fscanf(stdin, "%s", sex);
            strcpy(pc->date[pos].sex, sex);
        }break;
        case contact_way:
        {
            char contact_way[Max_numbers] = { 0 };
            fprintf(stdout, "你想修改为->");
            fscanf(stdin, "%s", contact_way);
            strcpy(pc->date[pos].numbers, contact_way);
        }break;
        case exit:
        {
            fprintf(stdout, "退出。\n");
        }break;
        default:
            fprintf(stdout, "选择错误,请重新选择。\n");
            break;
        }
    }
}

10.展示通讯录内容

void ShowContact( Contact* pc)//展示通讯录的内容;
{
	if (pc->size == 0)
	printf("通讯录为空。\n");
	else
	{
		int i = 0;
		printf("%-20s\t%-20s\t%-20s\t%-20s\t%-20s\t\n", "姓名", "年龄", "地址", "性别", "电话号码");
		for (i = 0; i < pc->size; i++)
			printf("%-20s\t%-20d\t%-20s\t%-20s\t%-20s\t\n",
				pc->date[i].name,
				pc->date[i].age,
				pc->date[i].address,
				pc->date[i].sex,
				pc->date[i].numbers);
	}

}

11排序函数

这个得自己慢慢体会

void SortContact( Contact* ps)//按名称对通讯的信息进行排序
{
    fprintf(stdout, "请选择排列方式\n  ");
    printf("0->按年龄  "); printf("1->姓名  "); printf("2->按年龄  "); printf("3->按地址  "); printf("4->按电话  "); printf("5->按性别\n");
    int N = 0;
    fscanf(stdin, "%d", &N);
    qsort(ps->date, ps->size, sizeof(PeoInfo), CMPMAIN[N]);
}
int cmp_age(void* e1, void* e2)
{
    return ((PeoInfo*)e1)->age - ((PeoInfo*)e2)->age;
}
int cmp_name(void* e1, void* e2)
{
    return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
int cmp_address(void* e1, void* e2)
{
    return strcmp(((PeoInfo*)e1)->address, ((PeoInfo*)e2)->address);
}
int cmp_numbers(void* e1, void* e2)
{
    return strcmp(((PeoInfo*)e1)->numbers, ((PeoInfo*)e2)->numbers);
}
int cmp_sex(void* e1, void* e2)
{
    return strcmp(((PeoInfo*)e1)->sex, ((PeoInfo*)e2)->sex);
}

 存放函数地址的数组;

int(*CMPMAIN[5])(void* e1, void* e2) ={&cmp_age,&cmp_name,&cmp_address,&cmp_address,&cmp_sex };

 三 将数据写入文件中去

     1.save函数

wb已二进制的形式进行写入。

void SaveContact(Contact* pc)//保存文件。
{
    FILE* pf = fopen("test.txt", "wb");
    if (pf == NULL)
    {
        perror("SaveContact");
        return;
    }
    int i = 0;
    for (i = 0; i < pc->size; i++)
    {
        fwrite(pc->date+i, sizeof(PeoInfo), 1, pf);
    }
    fclose(pf);
    pf = NULL;
    fprintf(stdout, "文件保存成功。\n");
}

2.read函数

这里我们创建了临时的人物结构体信息用来存储缓存空间。

void LoadingContact(Contact* pc)//加载文件
{
    FILE* pf = fopen("test.txt", "rb");
    if (pf == NULL)
    {
        perror("LoadingContact");
        return;
    }
    PeoInfo tmp = { 0 };//建立一个临时的人物信息进行交换;
    while (fread(&tmp, sizeof(PeoInfo), 1, pf))//详细参考fread函数的返回值
    {
        CheckCapacity(pc);
        pc->date[pc->size] = tmp;
        pc->size++;
    }
    fclose(pf);
    pf = NULL;
    fprintf(stdout, "数据加载成功。\n");
}

 3.摧毁函数

void DestoryContact(Contact* pc)//摧毁通讯录。
{
    free(pc->date);//释放通讯录开辟的内存空间;
    pc->date = NULL;//指针指向空指针;
    pc->size = 0;//数据归0;
    pc->Capacity = 0;//容量归0;
}

四 运行结果展示

 二进制文件

 

总结

  • 首先得有一个很好的框架体系,先进行构思,之后进行写入。
  • 排序函数需要进行深入的了解,研究。
  • 为了增加代码的可读性,可以考虑用枚举法列举。
  • 完整代码https://pan.baidu.com/s/1SjE66bzH0svayI53s9xP9g 提取码shdy
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值