通讯录(静态)

发布时间:2024年01月03日

cotact.h

#define _CRT_SECURE_NO_WARNINGS 1
#define ?MAX 100
#define ?MAXname 20
#define ?MAXsex 10
#define ?MAXtre 12
#define ?MAXaddr 30
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
//类型声明
//人的信息
typedef struct p
{
?? ?char name[MAXname];
?? ?int age;
?? ?char sex[MAXsex];//性别
?? ?char tele[MAXtre];//电话
?? ?char address[MAXaddr];//地址
}p;//加了typedef,就把结构体类型struct p重命名为了p
//封装一个通讯录(由于data和count都是通讯录的成员,同时变化且变化量相同,所以在头文件中封装,更容易找到)
typedef struct Contact
{
?? ?p data[MAX];//存放100个人的信息
?? ?int count;//记录当前通讯录中人的实时个数,添加一个+1,删除一个-1
}Contact;
//初始化通讯录
void InitContact(Contact* pc);//由于我们要通过pc指针来改变con的内容,所以不需要+const进行修饰
//增加联系人到通讯录
void AddContact(Contact* pc);
//显示通讯录中的信息
void ShowContact(const Contact*pc);//此处添加const是为了保护con的信息不被改动
//删除指定联系人
void DelContact(const Contact* pc);
//查找指定联系人
void SearchContact(Contact* pc);
//修改指定联系人
void ModifyContact(Contact* pc);
//排序通讯录中的联系人
//按照名字、年龄.......来排序
void SortContact(Contact* pc);

test.c


//实现一个通讯录
人的信息:
//名字
//年龄
//性别
//电话
//地址

实现功能:
// 存放100个人的信息
// 1.增添联系人
// 2.删除联系人
// 3.查找联系人
// 4.修改联系人
// 5.显示联系人
// 6.联系人排序

文件构成:
//test6.8.c ? ? ? ?测试功能
//contact.c ? ? 通讯录相关功能的实现
//contact.h ? ? 通讯录相关的声明

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void menu()
{
?? ?printf("****************************\n");
?? ?printf("*** ?1.add ? ? 2.del ? ? ***\n");
?? ?printf("*** ?3.search ?4.modify ?***\n");
?? ?printf("*** ?5.show ? ?6.sort ? ?***\n");
?? ?printf("*** ?0.exit ? ? ? ? ? ? ?***\n");
?? ?printf("****************************\n");
}
int main()
{
?? ?int input = 0;
?? ?Contact con;//通讯录
?? ?//创建一个函数,初始化通讯录
?? ?//为什么不直接初始化,而是借助函数进行初始化。
?? ?//1.我们尽量把代码分装成模块的形式,写一个函数来完成此项工作(模块化工作)
?? ?//2.如果我们想对通讯录的数据初始化的内容不能通过{}来初始化,我们想用另一种方法初始化或初始化成我们指定的内容,即此时用{}初始化不方便
?? ?InitContact(&con);//传参为地址是因为,后续还要对con进行更改,并且结构体传参尽量传地址,这样效率更高(传con,无法对其进行更改)
?? ?do
?? ?{
?? ??? ?menu();//菜单
?? ??? ?printf("请选择:");
?? ??? ?scanf("%d",&input);
?? ??? ?switch (input)
?? ??? ?{
?? ??? ?case 1:
?? ??? ??? ?AddContact(&con);//结构体传参传地址效率更高
?? ??? ??? ?break;
?? ??? ?case 2:
?? ??? ??? ?DelContact(&con);
?? ??? ??? ?break;
?? ??? ?case 3:
?? ??? ??? ?SearchContact(&con);
?? ??? ??? ?break;
?? ??? ?case 4:
?? ??? ??? ?ModifyContact(&con);
?? ??? ??? ?break;
?? ??? ?case 5:
?? ??? ??? ?ShowContact(&con);
?? ??? ??? ?break;
?? ??? ?case 6:
?? ??? ??? ?SortContact(&con);
?? ??? ??? ?break;
?? ??? ?case 0:
?? ??? ??? ?printf("退出通讯录:\n");
?? ??? ??? ?break;
?? ??? ?default:
?? ??? ??? ?printf("选择错误:\n");
?? ??? ??? ?break;
?? ??? ?}
?? ?} while(input);//输入0,为假,就跳出代码
?? ?return 0;
}

cotact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void InitContact(Contact* pc)
{
?? ?assert(pc);
?? ?pc->count = 0;
?? ?memset(pc->data, 0, sizeof(pc->data));
?? ?//memset内存设置函数,将每个字节都进行设置,个数取决于第三个参数sizeof(pc->data)
?? ?//若不是用memset,则需要借助循环进行初始化
}
//增添
void AddContact(Contact* pc)
{
?? ?assert(pc);
?? ?if (pc->count == MAX)
?? ?{
?? ??? ?printf("通讯录已满,无法添加\n");
?? ??? ?return 0;
?? ?}
?? ?printf("请输入名字:");
?? ?scanf("%s",pc->data[pc->count].name);//scanf中,需要将数据输入到地址中,而name为数组,本身就是地址,所以不需要&
?? ?printf("请输入年龄:");
?? ?scanf("%d", &(pc->data[pc->count].age));//而age为变量,因此想要更改其值就要使用其地址,即&age
?? ?printf("请输入性别:");
?? ?scanf("%s", pc->data[pc->count].sex);
?? ?printf("请输入电话:");
?? ?scanf("%s", pc->data[pc->count].tele);
?? ?printf("请输入地址:");
?? ?scanf("%s", pc->data[pc->count].address);
?? ?pc->count++;//此联系人添加完,就轮到下一个人
?? ?printf("增加成功");
}
//显示
void ShowContact(const Contact* pc)
{
?? ?assert(pc);
?? ?int i = 0;
?? ?printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话","地址");//由于1个汉字占2个字符
?? ?//左对齐让占位符前面的数字为负数即可
?? ?for (i = 0; i < pc->count; i++)
?? ?{
?? ??? ?printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n",pc->data[i].name
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ? , pc->data[i].age
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ? , pc->data[i].sex
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ? ? ? , pc->data[i].tele
?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ? , pc->data[i].address);//\t:水平制表符,让其空开
?? ?}
}
//此程序所有的信息只存于内存中,不能长时间保存,要长时间保存需要放在数据库中!!!!
static int Fingbyname(Contact* pc, char name[])//此处添加static会让此函数声明仅能在contact.c文件中看到。
//该函数未在头文件声明是为了不想让别人看到。并且后续功能的实现还需要此函数
{
?? ?assert(pc);
?? ?int i = 0;
?? ?for (i = 0; i < pc->count; i++)
?? ?{
?? ??? ?if (0 == strcmp(pc->data[i].name, name))
?? ??? ?{
?? ??? ??? ?return i;//找到了,返回其下标
?? ??? ?}
?? ?}
?? ?//由于函数返回类型为int,所以就不再设置else,返回-1了,直接作为函数返回值
?? ?return -1;
}
//删除
void DelContact(Contact* pc)
{
?? ?char name[MAXname] = {0};
?? ?int i = 0;
?? ?assert(pc);
?? ?if (pc->count == 0)
?? ?{
?? ??? ?printf("通讯录为空,没有信息可删除:");
?? ??? ?return;
?? ?}
?? ?printf("q请输入要删除人的名字:");
?? ?scanf("%s",name);
?? ?//删除之前,要先查找,再删除
?? ?//1.查找
?? ?int n=Fingbyname(pc,name);//找不到返回-1,即n就相当于下标
?? ?if (n == -1)
?? ?{
?? ??? ?printf("要删除的人不存在:");
?? ??? ?return;//退出该函数
?? ?}
?? ?//2.删除(要将此位置为空的地方,存放后续添加的联系人)
?? ?for (i = n; i < pc->count-1; i++)
?? ?{
?? ??? ?//加入现在有100个人的信息,即count=100,i=99,+1=100,而下标最大为99(就已经是最后一个元素,再大就越界了)
?? ??? ?//所以for语句中pc->count要-1,避免越界,也刚好满足条件
?? ??? ?pc->data[i] = pc->data[i + 1];
?? ?}//若删除最后一个元素,就相当于最后一个元素的后面的一个元素进行覆盖,相当于没覆盖,最后一个元素覆不覆盖无所谓
?? ?pc->count--;//但是通过pc->count--,假设100个元素,删除最后一个元素的话,只需要count--,我们最后一个元素不覆盖也可以,count--为99,最后一个元素我们也访问不到,因为我们是拿count来访问我们的数据的
?? ?printf("删除成功!!!");
}
//查找
void SearchContact(Contact* pc)
{
?? ?assert(pc);
?? ?char name[MAXname] = {0};
?? ?printf("请输入要要查找人的名字:");
?? ?scanf("%s", name);
?? ?//1.查找
?? ?int n = Fingbyname(pc, name);
?? ?if (n == -1)
?? ?{
?? ??? ?printf("要查找的人不存在!!!");
?? ??? ?return;//找不到就返回
?? ?}
?? ?else//(找到了,打印出来)
?? ?{
?? ??? ?printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");//由于1个汉字占2个字符
?? ??? ?//左对齐让占位符前面的数字为负数即可
?? ??? ?printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n", pc->data[n].name
?? ??? ??? ??? ?, pc->data[n].age
?? ??? ??? ??? ?, pc->data[n].sex
?? ??? ??? ??? ?, pc->data[n].tele
?? ??? ??? ??? ?, pc->data[n].address);
?? ?}
}
//修改
void ModifyContact(Contact* pc)
{
?? ?assert(pc);
?? ?char name[MAXname] = { 0 };
?? ?printf("请输入要修改人的名字:");
?? ?scanf("%s", name);
?? ?//1.查找
?? ?int n = Fingbyname(pc, name);
?? ?if (n == -1)
?? ?{
?? ??? ?printf("要修改的人不存在!!!");
?? ??? ?return;//找不到就返回
?? ?}
?? ?printf("要修改的联系人已经查找到,请您进行修改:");
?? ?//修改,并重新录入
?? ?printf("请输入名字:");
?? ?scanf("%s", pc->data[n].name);?? ?//此时下标为n
?? ?printf("请输入年龄:");
?? ?scanf("%d", &(pc->data[n].age));
?? ?printf("请输入性别:");
?? ?scanf("%s", pc->data[n].sex);
?? ?printf("请输入电话:");
?? ?scanf("%s", pc->data[n].tele);
?? ?printf("请输入地址:");
?? ?scanf("%s", pc->data[n].address);
?? ?printf("修改成功!!!");
}
//排序
int cmp_peo_by_name(const void* e1, const void* e2)
{
?? ?return strcmp(((p*)e1)->name,((p*)e2)->name);
}
//按照名字来排序
void SortContact(Contact* pc)
{
?? ?assert(pc);
?? ?qsort(pc->data, pc->count, sizeof(p), cmp_peo_by_name);// sizeof(p)可替换为 sizeof(pc->data[0]),p只是元素pc->data的类型,拿下标为0的元素来计算也可以
?? ?printf("排序成功!!!");
}
//qsort:比较函数(可以排序任意类型的数据),头文件<stdlib.h>,<search.h>
//其参数为:void qsort(void* base, size_t num, size_t width,int(*cmp)(const void* e1,const void* e2))
//void* base:指的是我们要排序的数据的起始位置
// size_t num:待排序的数据元素的个数
// size_t width:待排序的数据元素的大小(占几个字节)
//int(*cmp)(const void* e1,const void* e2):函数指针,需声明新的函数,并使用strcmp去比较所想比较的内容

循环结束标志
//return: 从当前的方法中退出,返回到该调用的方法的语句处,继续执行。
//continue: 终止当前的一次循环过程,其 不 跳出循环,而是继续往下判断循环条件执行语句。
// ? ? ? ? ?只能结束循环中的一次过程, 但不能终止循环继续进行。
//break: 直接跳出 当前 的循环,从当前循环外面开始执行,忽略循环体中任何其他语句和循环条件测试。
// ? ? ? 它只能跳出一层循环,如果你的循环是嵌套循环,那么你需要按照你嵌套的层次,逐步使用break来跳出。

文章来源:https://blog.csdn.net/2201_75570527/article/details/135360518
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。