目录
1. 通讯录模块
1.1 主函数(main)
int main()
{
int input = 0;//通讯录中当前有几个元素,也可以说是通讯录所要实现的功能有多少,增加、删除
//修改等,每个功能对应一个数字,通讯录首先最需要考虑的就是用户的需求,加好友或者 ……
struct Contact con;//创建通讯录,通过结构体的成员变量来表达,增加了代码的可读性
InitContact(&con);//初始化通讯录
do//do while 循环保证不管程序正确与否的前提下,我先运行一次菜单,输入用户的需求
{
menu();
printf("请选择:>");
scanf("%d", &input);//用户输入需要,加好友、删好友、修改好友情况等等
switch (input)//switch case 进行判断,我要进行哪种功能,对应哪种需要,进入哪种情况
{
//添加好友
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 SORT:
SortContact(&con);
break;
//清空通讯录
case CLEAR:
ClearContact(&con);
break;
//退出
case EXIT:
printf("退出通讯录\n");
break;
//switch选择的情况,也可以说是功能不在菜单里
default:
printf("选择错误\n");
break;
}
} while (input);//只要通讯录的功能在case 里有显示,就进行do while 循环;
return 0;
}//因为所有case的功能函数都是传址调用,所以对应的外部函数都需要用指针来接收传过去的地址
1.2 通讯录的菜单
void menu()
{
printf("************************************\n");
printf("****** 1. add 2. del ******\n");
printf("****** 3. search 4. modify ******\n");
printf("****** 5. show 6. sort ******\n");
printf("****** 7. clear 0. exit ******\n");
printf("************************************\n");
}
// 主函数调用menu函数,menu()放在主函数do while循环体中首行,保证程序一旦运行,首先出现的就是供用
// 户选择的菜单,菜单上对应增加、删除、查找、修改、显示、分类、离开通讯录等功能,每个功能对应每
// 个不同的代码1 2 3 4 5 6 0, 为了防止修改数字而影响主函数case的使用,可以进行宏定义或者枚举, // 本程序 我们采用的是枚举
1.3 通讯录枚举类型的声明
enum Option
{
EXIT,//0
ADD,//1
DEL,//2
SEARCH,//3
MODIFY,//4
SHOW,//5
SORT//6
CLEAR//7
};
//通过枚举来进行通讯录功能的声明,可以大大增加代码的可读性
使用枚举来声明通讯录功能有诸多好处:首先枚举大大增加了代码的可读性,其次为了防止不经意的看错菜单里的功能代码,可以在枚举的成员变量里直接写明菜单的功能,ag . EXIT离开;ADD增加 等等,防止因看错数字而干扰到用户的使用;
枚举的使用需要注意:首先枚举的成员变量通常用大写来表示,其次枚举的成员变量先天规定默认第一个成员变量代码为0 ,依次类推;并且枚举的成员变量是用逗号隔开的,最后一个成员变量没有符号;
1.4 初始化通讯录
struct Peopleinformation
{
char name[20];
int age;
char sex[5];
char tel[12];
char address[20];
};//结构体定义成员信息,简单来说就是我每加一个好友,该好友必备的信息存储
struct Contact
{
struct Peopleinformation data[MAX];//给定成员信息结构体一个结构体变量data[]表示该通讯录最多可以加多少好友
int size;//记录当前通讯录有效信息的个数
};//通讯录结构体
void InitContact(struct Contact* ps)//初始化函数的参数为struct Contact* ps,表示在struct Contact结构体的基础上定义了一个结构体变量指针ps,拿到ps就相当于拿到了整个数组,也可以说是拿到ps就可以操作整个数组
{
//memset内存设置函数
memset(ps->data, 0, sizeof(ps->data));//ps->data相当于找到了整个数组,没有sizeof和&所以代表的是首元素的地址,
//第二个参数表示把每一个字节都设置为0,但三个参数中sizeof表示计算结构体的大小,sizeof(ps->data)表示计算整个data整个数组的大小;
ps->size = 0;//初始化设置当前通讯录的有效人数为0;也可以说我创建一个全新的号,在一个全新的号上进行通讯录好久的处理
}
1.5 增加好友的功能函数
#define MAX 1000
void AddContact(struct Contact* ps)//因为主函数case中是传址调用,所以用结构体指针来接收地址,拿到ps相当于拿到了整个数组
{
if (ps->data == MAX)//ps->data表示结构体中数组data可以存放多少个有效信息,简单来说就是加好友的上限,此处宏定义为1000
{
printf("通讯录已满,无法增加\n");//如果进入if判断中,则表示加的好友已经上限了
}
else//如果还没有上限,则通过我们定义的结构体struct Peopleinformation中个人信息进行依次输入,以达到添加一个好友的目的
{
printf("请输入名字:>");
scanf("%s", ps->data[ps->size].name);
printf("请输入年龄:>");
scanf("%d", &(ps->data[ps->size].age));
printf("请输入性别:>");
scanf("%s", ps->data[ps->size].sex);
printf("请输入电话:>");
scanf("%s", ps->data[ps->size].tel);
printf("请输入地址:>");
scanf("%s", ps->data[ps->size].address);
ps->size++;//有效信息++
printf("添加成功\n");
}//在此->和[]的优先级是一样的,但是需要注意,还是要从左到右进行计算,如果直接进行data[ps->size],操作系统根本不知道data是什么,因为data是定义在
}//嵌套结构体里面的,所以还是要从左到右进行计算,ps->data拿到整个数组,整个数组是可以用数组名表示的,知道数组名就可以通过 . 进行结构体成员的访问
1.6 显示好友的功能函数
static int FindByName(struct Contact* ps, char name[20])//static在此处的意义为每循环一次外部函数,上次查找过得名字不会再次被查找
{
int i = 0;
for (i = 0; i < ps->size; i++)//循环的范围时通讯录中已经添加的有效人员的个数
{
if (0 == strcmp(ps->data[i].name, name))//字符串比较函数,==0 表示相等的情况
{//if判断语句的意思是结构体变量数组data中的名字和要查找的名字相同,我就返回该名字对应数组的下角标
return i;
}
}
return -1;//返回-1,表示两个不相等,也可以说是没有找到该人
}
void ShowContact(const struct Contact* ps)//const 它限定一个变量不允许被改变,产生静态作用。
{
if (ps->size == 0)
{
printf("通讯录为空\n");//ps->size表示通讯录中的有效人数
}
else//通讯录目前是有好友的,显示出来也可以说是将通讯录中好友的信息打印出来
{
int i = 0;
printf("%-5s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");
for (i = 0; i < ps->size; i++)//循环的次数为通讯录中具有有效信息的好友个数
{
printf("%-5s\t %-4d\t %-5s\t %-12s\t %-20s\n",
ps->data[i].name,
ps->data[i].age,
ps->data[i].sex,
ps->data[i].tel,
ps->data[i].address);
}
}//for循环打印结构体信息
}
1.7 删除好友的功能函数
static int FindByName(struct Contact* ps, char name[20])//static在此处的意义为每循环一次外部函数,上次查找过得名字不会再次被查找
{
int i = 0;
for (i = 0; i < ps->size; i++)//循环的范围时通讯录中已经添加的有效人员的个数
{
if (0 == strcmp(ps->data[i].name, name))//字符串比较函数,==0 表示相等的情况
{//if判断语句的意思是结构体变量数组data中的名字和要查找的名字相同,我就返回该名字对应数组的下角标
return i;
}
}
return -1;//返回-1,表示两个不相等,也可以说是没有找到该人
}
void DelContact(struct Contact* ps)
{
char name[20];
printf("请输入要删除人的名字:>");
scanf("%s", name);
int pos = FindByName(ps, name);//同样的,先通过外部函数找到所要找的人
if (pos == -1)
{
printf("要删除的人不存在\n");//无
}
else
{
int j = 0;
for (j = 0; j < ps->size - 1; j++)//之所以j < ps->size - 1;是因为ps->size是已经添加的有效人数
//该代码的意思是将我举例子0 1 2 3 5 6 7 8 9 9中的最后一个9删除,打印时不访问最后一个元素,相当于把最后一个9删除了
{
ps->data[pos] = ps->data[j + 1];
//该循环的意思是:假如数组中的成员为0 1 2 3 4 5 6 7 8 9,我想要删除4,该代码的意思是我用5覆盖4,6覆盖5
//7覆盖6,8覆盖7,9覆盖8,这样数组会变成0 1 2 3 5 6 7 8 9 9,成功达到了删除4的目的,并且没有改变原数组中其他元素的顺序
}
ps->size--;//通讯录有效人数随循环次数--
printf("删除成功\n");
}
}
1.8 查找好友的功能函数
static int FindByName(struct Contact* ps, char name[20])//static在此处的意义为每循环一次外部函数,上次查找过得名字不会再次被查找
{
int i = 0;
for (i = 0; i < ps->size; i++)//循环的范围时通讯录中已经添加的有效人员的个数
{
if (0 == strcmp(ps->data[i].name, name))//字符串比较函数,==0 表示相等的情况
{//if判断语句的意思是结构体变量数组data中的名字和要查找的名字相同,我就返回该名字对应数组的下角标
return i;
}
}
return -1;//返回-1,表示两个不相等,也可以说是没有找到该人
}
void SearchContact(struct Contact* ps)//结构体指针接收传址调用的地址
{
char name[20];
printf("请输入要查找人的名字\n");
scanf("%s", name);
int pos = FindByName(ps, name);//通过外部函数的返回值查找到想要找到的人
if (pos == -1)
{
printf("要查找的人不存在\n");//无
}
else
{//找到了,打印出该人的信息
printf("%-5s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");
printf("%-5s\t %-4d\t %-5s\t %-12s\t %-20s\n",
ps->data[pos].name,
ps->data[pos].age,
ps->data[pos].sex,
ps->data[pos].tel,
ps->data[pos].address);
}//%s 打印字符,%d打印整型,%-5s\t表示对齐
//"\t"在C语言里表示水平制表(HT) (跳到下一个TAB位置)
}
1.9 修改好友的功能函数
static int FindByName(struct Contact* ps, char name[20])//static在此处的意义为每循环一次外部函数,上次查找过得名字不会再次被查找
{
int i = 0;
for (i = 0; i < ps->size; i++)//循环的范围时通讯录中已经添加的有效人员的个数
{
if (0 == strcmp(ps->data[i].name, name))//字符串比较函数,==0 表示相等的情况
{//if判断语句的意思是结构体变量数组data中的名字和要查找的名字相同,我就返回该名字对应数组的下角标
return i;
}
}
return -1;//返回-1,表示两个不相等,也可以说是没有找到该人
}
void ModifyContact(struct Contact* ps)//传址调用通过结构体指针来接收
{
char name[20];//通过名字找到所要修改人的信息
printf("请输入要修改人的名字:>");
scanf("%s", name);
int pos = FindByName(ps, name);//定义外部函数
if (pos == -1)
{
printf("要修改人的信息不存在\n");//找不到该人
}
else
{//如果找到该人,则通过外部函数的返回值找到该名字在数组中对应的下角标,并且修改该人的信息
printf("请输入名字:>");
scanf("%s", ps->data[pos].name);
printf("请输入年龄:>");
scanf("%d", &(ps->data[pos].age));
printf("请输入性别:>");
scanf("%s", ps->data[pos].sex);
printf("请输入电话:>");
scanf("%s", ps->data[pos].tel);
printf("请输入地址:>");
scanf("%s", ps->data[pos].address);
printf("修改完成\n");
}
}
1.10 排序好友的功能函数
qsort冒泡排序函数,函数定义:void qsort(void* base,size_t num,size_t size,int(*compar)(const void*,const void*))
void* base:首元素的地址;size_t num:待排序的数据个数;size_t size:所占字节的大小;int(*compar)(const void*,const void*):比较两个数据的大小;
enum Option_qsort
{
exit_sort,//0
name,//1
age,//2
sex,//3
address,//4
tel//5
};
void menu_qsort()
{
printf("************************************\n");
printf("****** 1. name 2. age ******\n");
printf("****** 3. sex 4. address ******\n");
printf("****** 5. tel 0. exit_sort ******\n");
printf("************************************\n");
}
int compare_tel(const void*e1, const void*e2)
{
return strcmp(((struct Peopleinformation*)e1)->tel, ((struct Peopleinformation*)e2)->tel);
}
int compare_address(const void*e1, const void*e2)
{
return strcmp(((struct Peopleinformation*)e1)->address, ((struct Peopleinformation*)e2)->address);
}
int compare_sex(const void*e1, const void*e2)
{
return strcmp(((struct Peopleinformation*)e1)->sex, ((struct Peopleinformation*)e2)->sex);
}
int compare_age(const void*e1, const void*e2)
{
return strcmp(((struct Peopleinformation*)e1)->age, ((struct Peopleinformation*)e2)->age);
}
int compare_name(const void*e1, const void*e2)
{
return strcmp(((struct Peopleinformation*)e1)->name, ((struct Peopleinformation*)e2)->name);
}
void print(struct Contact* ps)
{
int i = 0;
printf("%-5s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");
for (i = 0; i < ps->size; i++)
{
printf("%-5s\t %-4d\t %-5s\t %-12s\t %-20s\n",
ps->data[i].name,
ps->data[i].age,
ps->data[i].sex,
ps->data[i].tel,
ps->data[i].address);
}
}
void SortContact(struct Contact* ps)
{//通讯录排序仿照main函数来进行;
int input = 0;
do
{
menu_qsort();//打印排序的菜单方式
printf("请选择排序的方式:>");
scanf("%d", &input);
switch (input)
{
case name://按照名字排序
qsort(ps->data, ps->size, sizeof(ps->data[0]), compare_name);
print(ps);//打印排序以后的个人信息
break;
case age://按照年龄排序
qsort(ps->data, ps->size, sizeof(ps->data[0]), compare_age);
print(ps);
break;
case sex://按照性别排序
qsort(ps->data, ps->size, sizeof(ps->data[0]), compare_sex);
print(ps);
break;
case address://按照住址排序
qsort(ps->data, ps->size, sizeof(ps->data[0]), compare_address);
print(ps);
break;
case tel://按照电话排序
qsort(ps->data, ps->size, sizeof(ps->data[0]), compare_tel);
print(ps);
break;
case exit_sort://离开排序功能
printf("通讯录排序功能退出成功\n");
printf("\n");
break;
default:
printf("选择排序的方式错误,请重新选择:>");
break;
}
} while (input);
}
1.11 清除好友的功能函数
void ClearContact(struct Contact* ps)
{
(ps->size) = 0;
memset(ps->data, 0, sizeof(ps->data));
printf("清空成功\n");
printf("\n");
}//清空所有联系人的函数很好理解,用memset内存设置函数,将数组data设置为0,通讯录中有效人数设置为0
2. 总的程序代码
此处并没有进行模块化,总的程序看起来可能比较混乱;
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <stddef.h>
#include <errno.h>
#include <stdlib.h>
#define MAX 1000 //宏定义总人数
void menu()//功能菜单
{
printf("************************************\n");
printf("****** 1. add 2. del ******\n");
printf("****** 3. search 4. modify ******\n");
printf("****** 5. show 6. sort ******\n");
printf("****** 7. clear 0. exit ******\n");
printf("************************************\n");
}
struct Peopleinformation//个人信息的结构体
{
char name[20];
int age;
char sex[5];
char tel[12];
char address[20];
};
struct Contact//结构体嵌套
{
struct Peopleinformation data[MAX];
int size;
};
enum Option_qsort//排序的枚举类型
{
exit_sort,//0
name,//1
age,//2
sex,//3
address,//4
tel//5
};
void menu_qsort()//排序依据的菜单
{
printf("************************************\n");
printf("****** 1. name 2. age ******\n");
printf("****** 3. sex 4. address ******\n");
printf("****** 5. tel 0. exit_sort ******\n");
printf("************************************\n");
}
int compare_tel(const void*e1, const void*e2)//按电话进行比较的外部函数
{
return strcmp(((struct Peopleinformation*)e1)->tel, ((struct Peopleinformation*)e2)->tel);
}
int compare_address(const void*e1, const void*e2)//按地址进行比较的外部函数
{
return strcmp(((struct Peopleinformation*)e1)->address, ((struct Peopleinformation*)e2)->address);
}
int compare_sex(const void*e1, const void*e2)//按性别进行比较的外部函数
{
return strcmp(((struct Peopleinformation*)e1)->sex, ((struct Peopleinformation*)e2)->sex);
}
int compare_age(const void*e1, const void*e2)//按年龄进行比较的外部函数
{
return ((struct Peopleinformation*)e1)->age- ((struct Peopleinformation*)e2)->age;
}
int compare_name(const void*e1, const void*e2)//按名字进行比较的外部函数
{
return strcmp(((struct Peopleinformation*)e1)->name, ((struct Peopleinformation*)e2)->name);
}
void print(struct Contact* ps)//打印排序之后的信息
{
int i = 0;
printf("%-5s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");
for (i = 0; i < ps->size; i++)
{
printf("%-5s\t %-4d\t %-5s\t %-12s\t %-20s\n",
ps->data[i].name,
ps->data[i].age,
ps->data[i].sex,
ps->data[i].tel,
ps->data[i].address);
}
}
void ClearContact(struct Contact* ps)//清除功能
{
(ps->size) = 0;
memset(ps->data, 0, sizeof(ps->data));
printf("清空成功\n");
printf("\n");
}//清空所有联系人的函数很好理解,用memset内存设置函数,将数组data设置为0,通讯录中有效人数设置为0
void SortContact(struct Contact* ps)//排序功能
{//通讯录排序仿照main函数来进行;
int input = 0;
do
{
menu_qsort();//打印排序的菜单方式
printf("请选择排序的方式:>");
scanf("%d", &input);
switch (input)
{
case name://按照名字排序
qsort(ps->data, ps->size, sizeof(ps->data[0]), compare_name);
print(ps);//打印排序以后的个人信息
break;
case age://按照年龄排序
qsort(ps->data, ps->size, sizeof(ps->data[0]), compare_age);
print(ps);
break;
case sex://按照性别排序
qsort(ps->data, ps->size, sizeof(ps->data[0]), compare_sex);
print(ps);
break;
case address://按照住址排序
qsort(ps->data, ps->size, sizeof(ps->data[0]), compare_address);
print(ps);
break;
case tel://按照电话排序
qsort(ps->data, ps->size, sizeof(ps->data[0]), compare_tel);
print(ps);
break;
case exit_sort://离开排序功能
printf("通讯录排序功能退出成功\n");
printf("\n");
break;
default:
printf("选择排序的方式错误,请重新选择:>");
break;
}
} while (input);
}
void InitContact(struct Contact* ps)//初始化通讯录
{
memset(ps->data, 0, sizeof(ps->data));
ps->size = 0;
}
void AddContact(struct Contact* ps)//添加通讯录
{
if (ps->data == 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].sex);
printf("请输入电话:>");
scanf("%s", ps->data[ps->size].tel);
printf("请输入地址:>");
scanf("%s", ps->data[ps->size].address);
ps->size++;
printf("添加成功\n");
}
}
void ShowContact(const struct Contact* ps)//显示通讯录
{
if (ps->size == 0)
{
printf("通讯录为空\n");
}
else
{
int i = 0;
printf("%-5s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");
for (i = 0; i < ps->size; i++)
{
printf("%-5s\t %-4d\t %-5s\t %-12s\t %-20s\n",
ps->data[i].name,
ps->data[i].age,
ps->data[i].sex,
ps->data[i].tel,
ps->data[i].address);
}
}
}
static int FindByName(struct Contact* ps, char name[20])//在已经存在的好友中找到某个人
{
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (0 == strcmp(ps->data[i].name, name))
{
return i;
}
}
return -1;
}
void DelContact(struct Contact* ps)//删除某位好友
{
char name[20];
printf("请输入要删除人的名字:>");
scanf("%s", name);
int pos = FindByName(ps, name);
if (pos == -1)
{
printf("要删除的人不存在\n");
}
else
{
int j = 0;
for (j = 0; j < ps->size - 1; j++)
{
ps->data[pos] = ps->data[j + 1];
}
ps->size--;
printf("删除成功\n");
}
}
void SearchContact(struct Contact* ps)//查找某位好友
{
char name[20];
printf("请输入要查找人的名字\n");
scanf("%s", name);
int pos = FindByName(ps, name);
if (pos == -1)
{
printf("要查找的人不存在\n");
}
else
{
printf("%-5s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");
printf("%-5s\t %-4d\t %-5s\t %-12s\t %-20s\n",
ps->data[pos].name,
ps->data[pos].age,
ps->data[pos].sex,
ps->data[pos].tel,
ps->data[pos].address);
}
}
void ModifyContact(struct Contact* ps)//修改某位好友的信息
{
char name[20];
printf("请输入要修改人的名字:>");
scanf("%s", name);
int pos = FindByName(ps, name);
if (pos == -1)
{
printf("要修改人的信息不存在\n");
}
else
{
printf("请输入名字:>");
scanf("%s", ps->data[pos].name);
printf("请输入年龄:>");
scanf("%d", &(ps->data[pos].age));
printf("请输入性别:>");
scanf("%s", ps->data[pos].sex);
printf("请输入电话:>");
scanf("%s", ps->data[pos].tel);
printf("请输入地址:>");
scanf("%s", ps->data[pos].address);
printf("修改完成\n");
}
}
enum Option//通讯录功能的枚举类型
{
EXIT,//0
ADD,//1
DEL,//2
SEARCH,//3
MODIFY,//4
SHOW,//5
SORT,//6
CLEAR//7
};
int main()//主函数
{
int input = 0;
struct Contact con;
InitContact(&con);
do
{
menu();
printf("请选择:>");
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 SORT:
SortContact(&con);
break;
case CLEAR:
ClearContact(&con);
break;
case EXIT:
printf("退出通讯录\n");
break;
default:
printf("选择错误\n");
break;
}
} while (input);
return 0;
}