🌟如何构思?
根据C语言所存在的数据类型,我们很直观的联系我们手机上的通讯录,那么通讯录肯定是以每个联
系人为单位的,而联系人是一个复合的数据集合体,他不能单独由整形或者字符串等简单表示,我们
自然想到C语言结构体类型,struct PeoInfo 就可以代表一个联系人的信息 。我们创建这样的结构体:
struct PeoInfo {
char name[20];
char sex[5];
char tele[12];
int age;
char address[30];
};
这样就依靠结构体来实现联系人的信息表示 。那么进一步考虑一个通讯录是什么样子,大的通讯录是
以N个联系人为单位组成的,这是显然的,那么我们可以增加一个计数变量来保存当前的通讯录有多
少个联系人,这样一来就可以实现通讯录的定义,同样使用结构体:
struct Contact {
struct PeoInfo data[100];
int sz;
};
😊 考虑联系人属性:
考虑设计时能不能更加灵活,比如我们通讯录的数据上限个数能不能将来好根据需求变化,数组的大
小能否变化,可以考虑将这些变量的大小采用宏定义:
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDRESS 30
struct PeoInfo {
char name[MAX_NAME];
char sex[MAX_SEX];
char tele[MAX_TELE];
int age;
char address[MAX_ADDRESS];
};
struct Contact {
struct PeoInfo data[MAX];
int sz;
};
至此,我们考虑主函数main.c的设计
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");
}
这里注意要实现的功能:
1.增加联系人
2.删除联系人
3.查找联系人
4.修改联系人
5.排序
6.退出程序
struct Contact con;
InitContact(&con);
创建一个通讯录(结构体变量)con,并且通过结构体指针传参的方式来进行功能操作,这很重要,指
针传参可以有效减少程序内存消耗开支,传指针更加直观。
menu();
printf("请输入你想要的操作:");
scanf("%d", &input);
switch (input)
{
case 1:
AddContact(&con);
break;
case 2:
DelContact(&con);
break;
case 3:
Search(&con);
break;
case 4:
Modify(&con);
break;
case 5:
ShowContact(&con);
break;
case 6:
Sort(&con);
break;
case 0:
printf("退出程序.");
break;
default:
break;
}
😊 main.c
将功能整合一下即可,这是主函数的实现:
# 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;
struct Contact con;
InitContact(&con);
do {
menu();
printf("请输入你想要的操作:");
scanf("%d", &input);
switch (input)
{
case 1:
AddContact(&con);
break;
case 2:
DelContact(&con);
break;
case 3:
Search(&con);
break;
case 4:
Modify(&con);
break;
case 5:
ShowContact(&con);
break;
case 6:
Sort(&con);
break;
case 0:
printf("退出程序.");
break;
default:
break;
}
} while (input);
}
那么这时候需要考虑头文件的构建,在项目需要多个文件时,不妨将头文件整合到一起,同时将一些
全局定义的类型、变量、函数声明也放入头文件。
😊 Contact.h
# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDRESS 30
struct PeoInfo {
char name[MAX_NAME];
char sex[MAX_SEX];
char tele[MAX_TELE];
int age;
char address[MAX_ADDRESS];
};
struct Contact {
struct PeoInfo data[MAX];
int sz;
};
void InitContact(struct Contact* con);
void AddContact(struct Contact* con);
void ShowContact(const struct Contact* con);
void DelContact(struct Contact* con);
void Search(const struct Contact* con);
void Modify(struct Contact* con);
void Sort(struct Contact* con);
显然,在头文件里声明这几个功能函数。
😊 Contact.c 函数功能
至此,我们就要构建这些个主题功能如何实现,首先我们实现将通讯录初始化,这是功能实现前的必
要操作。
void InitContact(struct Contact* con) {
assert(con);
con->sz = 0;
memset(con->data, 0, 100 * sizeof(struct PeoInfo));
}
考虑Add函数,向通讯录增加联系人:
void AddContact(struct Contact* con) {
if (con->sz == MAX) {
printf("当前通讯录已满!\n");
return;
}
printf("请输入姓名:");
scanf("%s", con->data[con->sz].name);
printf("请输入性别:");
scanf("%s", con->data[con->sz].sex);
printf("请输入电话号码:");
scanf("%s", con->data[con->sz].tele);
printf("请输入年龄:");
scanf("%d", &(con->data[con->sz].age));
printf("请输入地址:");
scanf("%s", &(con->data[con->sz].address));
con->sz++;
printf("添加成功!\n");
}
显然,在添加之前肯定要判断通讯录是否已经存满。
Show函数来打印通讯录:
void ShowContact(const struct Contact* con) {
printf("%-10s\t%-5s\t%-12s\t%-5s\t%-20s\n\n","姓名","性别","电话号码","年龄","地址");
for (int i = 0; i < con->sz; i++) {
printf("%-10s\t%-5s\t%-12s\t%-5d\t%-20s\n", con->data[i].name,
con->data[i].sex,
con->data[i].tele,
con->data[i].age,
con->data[i].address);
}
}
Del删除联系人:
static int FindName(struct Contact* con,char name[]) {
for (int i = 0; i < con->sz; i++) {
if (strcmp(con->data[i].name, name) == 0) {
return i;
}
}
return -1;
}
void DelContact(struct Contact* con) {
char name[MAX_NAME];
printf("请输入要删除的联系人姓名:");
scanf("%s", name);
int ret = FindName(con,name);
if (ret == -1) {
printf("该联系人不存在!\n");
}
else {
for (int j = ret; j < con->sz - 1; j++) {
con->data[j] = con->data[j + 1];
}
con->sz--;
printf("删除联系人成功!\n");
}
}
在这里我们设计了一个静态查找姓名的函数来实现通过姓名发现联系人,来决定能否删除。当然,后
续的Find查找联系人、和修改联系人也同理都要根据查找姓名来判断该联系人是否存在。
void Search(const struct Contact* con) {
char name[MAX_NAME];
printf("请输入要查找的联系人的姓名:");
scanf("%s", name);
int ret = FindName(con,name);
if (ret == -1) {
printf("要查找的联系人不存在!\n");
}
else {
printf("%-10s\t%-5s\t%-12s\t%-5s\t%-20s\n\n", "姓名", "性别", "电话号码", "年龄", "地址");
printf("%-10s\t%-5s\t%-12s\t%-5d\t%-20s\n", con->data[ret].name,
con->data[ret].sex,
con->data[ret].tele,
con->data[ret].age,
con->data[ret].address);
}
}
void Modify(struct Contact* con) {
char name[MAX_NAME];
printf("请输入要修改的联系人的姓名:");
scanf("%s", name);
int ret = FindName(con, name);
if (ret == -1) {
printf("要修改的联系人不存在\n");
}
else {
printf("请输入姓名:");
scanf("%s", con->data[ret].name);
printf("请输入性别:");
scanf("%s", con->data[ret].sex);
printf("请输入电话号码:");
scanf("%s", con->data[ret].tele);
printf("请输入年龄:");
scanf("%d", &(con->data[ret].age));
printf("请输入地址:");
scanf("%s", &(con->data[ret].address));
printf("修改成功\n");
}
}
Sort为通讯录的联系人进行排序,这里我们可以使用C语言通过的qsort函数
int CmpByAge(const void* e1, const void* e2) {
return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
}
int CmpByName(const void* e1, const void* e2) {
return strcmp(((struct PeoInfo*)e1)->name, ((struct PeoInfo*)e2)->name);
}
void Sort(struct Contact* con) {
qsort(con->data, con->sz, sizeof(struct PeoInfo), CmpByName);
}
关于比较规则,CmpBy***可以自行设计,这里根据年龄来排序,也可以按照姓名来排序。
🌟 程序结构
整个的项目结构已经很清晰:
对整个功能核心函数进行整合,在Contact.c中实现:
🌟 Contact.c
# define _CRT_SECURE_NO_WARNINGS 1
# include "contact.h"
void InitContact(struct Contact* con) {
assert(con);
con->sz = 0;
memset(con->data, 0, 100 * sizeof(struct PeoInfo));
}
void AddContact(struct Contact* con) {
if (con->sz == MAX) {
printf("当前通讯录已满!\n");
return;
}
printf("请输入姓名:");
scanf("%s", con->data[con->sz].name);
printf("请输入性别:");
scanf("%s", con->data[con->sz].sex);
printf("请输入电话号码:");
scanf("%s", con->data[con->sz].tele);
printf("请输入年龄:");
scanf("%d", &(con->data[con->sz].age));
printf("请输入地址:");
scanf("%s", &(con->data[con->sz].address));
con->sz++;
printf("添加成功!\n");
}
void ShowContact(const struct Contact* con) {
printf("%-10s\t%-5s\t%-12s\t%-5s\t%-20s\n\n","姓名","性别","电话号码","年龄","地址");
for (int i = 0; i < con->sz; i++) {
printf("%-10s\t%-5s\t%-12s\t%-5d\t%-20s\n", con->data[i].name,
con->data[i].sex,
con->data[i].tele,
con->data[i].age,
con->data[i].address);
}
}
static int FindName(struct Contact* con,char name[]) {
for (int i = 0; i < con->sz; i++) {
if (strcmp(con->data[i].name, name) == 0) {
return i;
}
}
return -1;
}
void DelContact(struct Contact* con) {
char name[MAX_NAME];
printf("请输入要删除的联系人姓名:");
scanf("%s", name);
int ret = FindName(con,name);
if (ret == -1) {
printf("该联系人不存在!\n");
}
else {
for (int j = ret; j < con->sz - 1; j++) {
con->data[j] = con->data[j + 1];
}
con->sz--;
printf("删除联系人成功!\n");
}
}
void Search(const struct Contact* con) {
char name[MAX_NAME];
printf("请输入要查找的联系人的姓名:");
scanf("%s", name);
int ret = FindName(con,name);
if (ret == -1) {
printf("要查找的联系人不存在!\n");
}
else {
printf("%-10s\t%-5s\t%-12s\t%-5s\t%-20s\n\n", "姓名", "性别", "电话号码", "年龄", "地址");
printf("%-10s\t%-5s\t%-12s\t%-5d\t%-20s\n", con->data[ret].name,
con->data[ret].sex,
con->data[ret].tele,
con->data[ret].age,
con->data[ret].address);
}
}
void Modify(struct Contact* con) {
char name[MAX_NAME];
printf("请输入要修改的联系人的姓名:");
scanf("%s", name);
int ret = FindName(con, name);
if (ret == -1) {
printf("要修改的联系人不存在\n");
}
else {
printf("请输入姓名:");
scanf("%s", con->data[ret].name);
printf("请输入性别:");
scanf("%s", con->data[ret].sex);
printf("请输入电话号码:");
scanf("%s", con->data[ret].tele);
printf("请输入年龄:");
scanf("%d", &(con->data[ret].age));
printf("请输入地址:");
scanf("%s", &(con->data[ret].address));
printf("修改成功\n");
}
}
int CmpByAge(const void* e1, const void* e2) {
return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
}
int CmpByName(const void* e1, const void* e2) {
return strcmp(((struct PeoInfo*)e1)->name, ((struct PeoInfo*)e2)->name);
}
void Sort(struct Contact* con) {
qsort(con->data, con->sz, sizeof(struct PeoInfo), CmpByName);
}
🌟 总结
整个程序需要进行分块实现,分块为了让整个代码的思路更加清晰,函数独自封装,头文件整合在一
起,主函数实现外部功能选择框架,这些都是需要注意。
关于qsort函数的更多用法可以参考· cplusplus
|