提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
通过对C语言结构体的深入学习,终于能够自主实现简单通讯录的程序编写,希望在这里记录自己对C语言的学习,以及分享自己对该程序的思路和见解。
一、分析问题
1.通讯录,包括联系人的姓名,年龄,性别,电话号码和家庭地址五个成员变量,且他们的数据类型各不相同,所以首先创建一个结构体来存放联系人的信息。
2.通讯录不可能只包含一个人的信息,所以我们应该创建一个结构体数组以存放多个人的信息。因为我们需要一个标记来记录当前通讯录中存放了多少人的信息,又结构体可以成为另一个结构体的成员变量,所以我们可以再创建一个结构体,把结构体数组和标记作为新的结构体的成员变量。
3.通讯录的主要功能有增删改查,打印通讯录,对通讯录进行排序和清空。
增加联系人:往数组中增加元素,联系人个数加一;
删除联系人:找到想要删除联系人的数组下标,把该下标后的每一个元素向前覆盖,联系人个数减一。
修改联系人:按名字找到想要修改的联系人的下标,然后对其元素进行修改。
搜索联系人:按名字找到联系人的下标,进行打印。
打印通讯录:打印结构体数组。
排序通讯录:用C语言自带的库函数qsort()按名字进行排序。
清空通讯录:用内存函数memset()把结构体数组元素置零,再把标记置零。
4.通过对不同函数的说明可以发现,删,改,搜索都要利用联系人的名字来找到下标,所以我们可以创建这样一个函数,利用联系人的名字来找到他在结构体数组的下标。
二、函数具体功能的实现
1.结构体的创建
定义两个结构体,一个结构体用来保存联系人信息,另一个结构体用来报仇呢通讯录。
#define MAX_NAME 20
#define MAX_SEX 12
#define MAX_TELE 12
#define MAX_ADDR 20
#define MAX_SIZE 1000
//存储个人信息
typedef struct PeoInfo
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tele[MAX_TELE];
char addr[MAX_ADDR];
}PeoInfo;
//通讯录
typedef struct Contact
{
PeoInfo data[MAX_SIZE];//最多能存储1000个人的信息
int sz;//当前存储的联系人的个数
}Contact;
2.对结构体进行初始化
结构体刚初始化时,没有联系人的信息,所以sz置为0,用memset()内存函数初始化结构体数组。
void InitContact(Contact* pc)
{
pc->sz = 0;
memset(pc->data,0,sizeof(pc->data));//用memset内存函数初始化
}
3.增加联系人
首先判断通讯录是否装满,如果装满,给出提醒并返回,没有装满,存储联系人信息,通讯录存储联系人的个数加一。
void AddContact(Contact* pc)
{
//判断通讯录是否已满
if (pc->sz == MAX_SIZE)
{
printf("通讯录已满,不能添加!\n");
}
//如果通讯录未满
else
{
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].tele);
printf("请输入地址:");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
}
}
4.find_by_name函数
在问题的分析中我们提出通讯录实现的删除、修改、查找的功能,都要通过名字来查找,所以我们创建一个函数来实现这个功能,且这个函数只能在该程序内使用,因此我们用statci来修饰。
在这个函数中,我们找到下标就返回,没找到,返回-1。
static int find_by_name(Contact* pc, char* tmp)
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, tmp) == 0)
return i;
}
return -1;
}
5.删除联系人
寻找要删除联系人所在的数组下标,如果找到了,该下标后的每一个元素向前覆盖,联系人个数减一。没找到,给出提示并返回。
void DelContact(Contact* pc)
{
//通讯录为空,不需要进行删除
if (pc->sz == 0)
{
printf("该通讯录为空,无需删除!\n");
return;
}
//如果通讯录不为空,先按名字找到需要删除的人的数组下标
char tmp[MAX_NAME] = {0};
printf("请输入需要删除人的姓名:");
scanf("%s", tmp);
int ret = find_by_name(pc, tmp);
if (ret < 0)
{
printf("没有该联系人,删除失败\n");
}
else
{
int i = 0;
for (i = ret; i < pc->sz - 1; i++)
{
pc->data[i] = pc->data[i + 1];
}
printf("删除成功!\n");
pc->sz--;
}
}
6.修改联系人信息
void ModifyContact(Contact* pc)
{
printf("请输入你想修改的人的信息的名字:");
char tmp[MAX_NAME] = { 0 };
scanf("%s", tmp);
int ret = find_by_name(pc, tmp);
if (ret < 0)
{
printf("你想要修改的人信息不存在!");
return;
}
else
{
printf("请输入修改后姓名:");
scanf("%s", pc->data[ret].name);
printf("请输入修改后年龄:");
scanf("%d", &(pc->data[ret].age));
printf("请输入修改后性别:");
scanf("%s", pc->data[ret].sex);
printf("请输入修改后电话号码:");
scanf("%s", pc->data[ret].tele);
printf("请输入修改后地址:");
scanf("%s", pc->data[ret].addr);
printf("修改成功!\n");
}
}
7.查找联系人
void SearchContact(Contact* pc)
{
printf("请输入你要查找人的姓名:");
char tmp[MAX_NAME] = { 0 };
scanf("%s", tmp);
int ret = find_by_name(pc, tmp);
if (ret < 0)
{
printf("你查找的人的信息不存在!\n");
}
else
{
printf("查询成功!\n");
printf("%-15s\t%-5d\t%-5s\t%-12s\t%-20s\n", pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}
}
8.按名字排序通讯录
利用qsort()函数,qsort函数第一个参数填要排序对象的首地址,第二个参数是要排序对象的个数,第三个参数是待排序对象中每个元素的大小(字节),第四个参数是函数,该函数决定了是按升序还是降序排列。
int sort_by_name(const void* e1, const void* e2)
{
return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void SortContact(Contact* pc)
{
qsort(pc->data, pc->sz, sizeof(pc->data[0]), sort_by_name);
printf("排序成功!\n");
}
9.打印通讯录
void PrintContact(Contact* pc)
{
int i = 0;
printf("%-15s\t%-5s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");
for (i = 0; i < pc->sz; i++)
{
printf("%-15s\t%-5d\t%-5s\t%-12s\t%-20s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
}
}
10.销毁通讯录
销毁的操作和创建一样。
void ClearContact(Contact* pc)
{
memset(pc->data, 0, sizeof(pc->data));
pc->sz = 0;
printf("销毁成功!\n");
}
源码
我这里使用的是分文件编写,分别是Contact.h,Contact.c和test.c三个文件。
Contact.h
#define _CRT_SECURE_NO_WARNINGS 1
//创建一个通讯录
//通讯录包括:名字,年龄,性别,电话,住址
//功能:增加,删除,搜索,修改,排序,输出,清空
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_NAME 20
#define MAX_SEX 12
#define MAX_TELE 12
#define MAX_ADDR 20
#define MAX_SIZE 1000
//存储个人信息
typedef struct PeoInfo
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tele[MAX_TELE];
char addr[MAX_ADDR];
}PeoInfo;
//通讯录
typedef struct Contact
{
PeoInfo data[MAX_SIZE];//最多能存储1000个人的信息
int sz;//当前存储的联系人的个数
}Contact;
//通讯录初始化
void InitContact(Contact* pc);
//通讯录添加
void AddContact(Contact* pc);
//通讯录删除
void DelContact(Contact* pc);
//通讯录的打印
void PrintContact(Contact* pc);
//通讯录的查找
void SearchContact(Contact* pc);
//通讯录的修改
void ModifyContact(Contact* pc);
//通讯录的清空
void ClearContact(Contact* pc);
//通讯录的排序
void SortContact(Contact* pc);
Contact.c
#include "Contact.h"
void InitContact(Contact* pc)
{
pc->sz = 0;
memset(pc->data,0,sizeof(pc->data));//用memset内存函数初始化
}
void AddContact(Contact* pc)
{
//判断通讯录是否已满
if (pc->sz == MAX_SIZE)
{
printf("通讯录已满,不能添加!\n");
}
//如果通讯录未满
else
{
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].tele);
printf("请输入地址:");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
}
}
static int find_by_name(Contact* pc, char* tmp)
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, tmp) == 0)
return i;
}
return -1;
}
void DelContact(Contact* pc)
{
//通讯录为空,不需要进行删除
if (pc->sz == 0)
{
printf("该通讯录为空,无需删除!\n");
return;
}
//如果通讯录不为空,先按名字找到需要删除的人的数组下标
char tmp[MAX_NAME] = {0};
printf("请输入需要删除人的姓名:");
scanf("%s", tmp);
int ret = find_by_name(pc, tmp);
if (ret < 0)
{
printf("没有该联系人,删除失败\n");
}
else
{
int i = 0;
for (i = ret; i < pc->sz - 1; i++)
{
pc->data[i] = pc->data[i + 1];
}
printf("删除成功!\n");
pc->sz--;
}
}
void PrintContact(Contact* pc)
{
int i = 0;
printf("%-15s\t%-5s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");
for (i = 0; i < pc->sz; i++)
{
printf("%-15s\t%-5d\t%-5s\t%-12s\t%-20s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
}
}
void SearchContact(Contact* pc)
{
printf("请输入你要查找人的姓名:");
char tmp[MAX_NAME] = { 0 };
scanf("%s", tmp);
int ret = find_by_name(pc, tmp);
if (ret < 0)
{
printf("你查找的人的信息不存在!\n");
}
else
{
printf("查询成功!\n");
printf("%-15s\t%-5d\t%-5s\t%-12s\t%-20s\n", pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}
}
void ModifyContact(Contact* pc)
{
printf("请输入你想修改的人的信息的名字:");
char tmp[MAX_NAME] = { 0 };
scanf("%s", tmp);
int ret = find_by_name(pc, tmp);
if (ret < 0)
{
printf("你想要修改的人信息不存在!");
return;
}
else
{
printf("请输入修改后姓名:");
scanf("%s", pc->data[ret].name);
printf("请输入修改后年龄:");
scanf("%d", &(pc->data[ret].age));
printf("请输入修改后性别:");
scanf("%s", pc->data[ret].sex);
printf("请输入修改后电话号码:");
scanf("%s", pc->data[ret].tele);
printf("请输入修改后地址:");
scanf("%s", pc->data[ret].addr);
printf("修改成功!\n");
}
}
void ClearContact(Contact* pc)
{
memset(pc->data, 0, sizeof(pc->data));
pc->sz = 0;
printf("清除成功!\n");
}
//排序用qsort()函数
int sort_by_name(const void* e1, const void* e2)
{
return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void SortContact(Contact* pc)
{
qsort(pc->data, pc->sz, sizeof(pc->data[0]), sort_by_name);
printf("排序成功!\n");
}
test.c
在test.c文件中使用枚举类型,是为了使我在使用switch…case语句中实现功能时,混淆不同的函数。
#include "Contact.h"
enum Option
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SORT,
PRINT,
CLEAR
};
void menu()
{
printf("********************************\n");
printf("** 1.add 2.del **\n");
printf("** 3.search 4.modify **\n");
printf("** 5.sort 6.print **\n");
printf("** 7.clear **\n");
printf("** 0.sort **\n");
printf("********************************\n");
}
int main()
{
//创建通讯录,并初始化
Contact con;
InitContact(&con);
int input = 0;
do
{
menu();//打印菜单
printf("请输入你想要进行的操作编号:");
scanf("%d", &input);
switch (input)
{
case ADD:
AddContact(&con);
break;
case DEL:
DelContact(&con);
break;
case PRINT:
PrintContact(&con);
break;
case EXIT:
printf("退出程序");
break;
case SEARCH:
SearchContact(&con);
break;
case MODIFY:
ModifyContact(&con);
break;
case CLEAR:
ClearContact(&con);
break;
case SORT:
SortContact(&con);//按名字
break;
default:
printf("请输入正确的操作数:");
break;
}
} while (input);
return 0;
}
总结
这里只是简单通讯录的编写,代码中有很多不完善的地方,例如如果添加了相同的联系人,并没有去重功能,也不会有提醒,如果两个联系人只是名字相同,程序又该怎么完善,等等。