声明:由于本人水平有限,文章中难免有不准确和错误之处本人也很想知道这些错误,恳请读者批评指正,大家一起努力,加油!
本章的主要内容为实现通讯录这样的一个小程序,可以存放1000个人的信息,功能主要有(增加联系人,删除联系人,查找联系人,修改联系人,排序)。
程序分为三个模块:
| test.c | 测试程序的运行逻辑 |
| contact.h | 头文件的声明,关于函数相关函数的声明,符号的定义 |
| contact.c | 程序相关函数的实现 |
接下来为大家介绍程序如何从无到有(可以先跳到文章末尾看整体代码,更容易理解)

_____________________________________________________________________________
创建通讯录与每个人的信息
typdef重命名的好处就是,我们以后用他的时候不要每次再加上struct了,省去很多麻烦
用#define来定义每个符号,大大减少了以后代码维护的成本
sz其实就是用来记录数组的下标
#define MAX_NAME 20 #define MAX_SEX 10 #define MAX_TELE 12 #define MAX_ADDR 30 #define MAX 1000 //一个人的信息 typedef struct peoinfo { char name[MAX_NAME];//姓名 char sex[MAX_SEX];//性别 int age; //年龄 char trle[MAX_TELE];//电话 char addr[MAX_ADDR];//住址 }peoinfo; //整个通讯录 typedef struct contact { peoinfo data[MAX];//1000个人的信息 int sz; //每存放一个人记录在数组中的下标 } contact;
初始化函数(将sz和data数组初始化为0)
这里有一点值得注意,在初始化data数组时当然可以直接初始化为0,但用memcpy更好一些,主要是这个思想
函数的声明
void Initcontact(contact *pc);
函数的实现
void Initcontact(contact* pc) { pc->sz = 0; memset(pc->data, 0, sizeof(pc->data));//初始化0 }
增加人员函数
注意,scanf在接受年龄时千万别忘了加&(),年龄就是一个数字
逻辑其实很简单,首先判断,然后你输进来一个值scanf接受一下,完了后sz++
函数传参
addcontact(&con);//增加人员要改变con内部的值所以传地址
函数声明
void Initcontact(contact *pc);
函数实现
void addcontact(contact* pc) { //判断通讯录是否满 if (pc->sz == 1000) { printf("通讯录已满,不可增加"); } printf("请输入名字:>\n"); scanf("%s", pc->data->name); printf("请输入年龄:>\n"); scanf("%d", &(pc->data[pc->sz].age)); printf("请输入性别:>\n"); scanf("%s", pc->data[pc->sz].sex); printf("请输入电话:>\n"); scanf("%s", pc->data[pc->sz].tele); printf("请输入地址:>\n"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; printf("增加成功"); }
打印函数
逻辑也很简单,一个for循环就搞定了,需要注意的是for循环内部年龄的打印用%d
函数的声明
函数的实现
void printcontact(contact* pc) { int i = 0; //打印目录表 printf("%-20s\t%-5s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址"); //打印成员 for (i = 0; i < pc->sz; i++) { printf("%-20s\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); } }
删除人员函数
要删除人员首先要查找到那个人的名字,而且不管是删除,查找,修改,都要用到findbyname这个查找函数
删除函数的逻辑:首先判断,如果通讯录中没人,无法删除。用查找函数返回要删除的那个人的下标,用覆盖的方法(i=i+1)来进行删除。然后sz–。
这里有人可能会有疑问如果要删除的人是最后一个人这段还能实现吗,答案是可以的,sz–后会直接把最后一个人抹掉,不会访问到他了。就算以后要再次增加人员,新增加的人员信息也会把旧的覆盖。
函数的声明
void delcontact(contact* pc);
函数的实现
//查找函数 int findbyname(contact* pc, char nume[]) { int i = 0; for (i = 0; i < pc->sz; i++) { if (syrcmp(pc->data[i].name, nume) == 0) { return i;//找到返回下标 } } return -1;//找不到返回-1 } void delcontact(contact* pc) { char name[MAX]; //判断,如果通讯录中一个人都没有,无需删除 if (pc->sz == 0) { printf("无需删除"); } //查找要删除的人 printf("请输入要删除的人的名字"); scanf("%s", name); int ret = findbyname(pc, name); if (ret == -1) printf("要查找的人不存在"); //删除信息,用覆盖的方法 int i = 0; for (i = 0; i < pc->sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--; printf("删除成功\n"); }
查找函数
查找函数上述已经写过
打印的时候只需把把下标换成要查找的人的下标就可以
函数声明
void sercontact(contact* pc);
函数实现
void sercontact(contact* pc) { char name[MAX] = { 0 }; printf("请输入要删除的人的名字"); scanf("%s", name); int ret = findbyname(pc, name); if (ret == -1) printf("要查找的人不存在"); else { printf("%-20s\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); //下标换成ret(要查找的人的下标) } }
修改人员函数
整体的逻辑和上述一样
把要修改的人的信息重新录一遍就实现了修改的效果
函数的声明
void modcontact(contact* pc);
函数的实现
void modcontact(contact* pc) { char name[MAX] = { 0 }; printf("请输入要修改的人的名字"); scanf("%s", name); int ret = findbyname(pc, name); if (ret == -1) printf("要修改的人不存在"); else { printf("请输入名字:>\n"); scanf("%s", pc->data[ret].name); printf("请输入年龄:>\n"); scanf("%d", &(pc->data[ret].age)); printf("请输入性别:>\n"); scanf("%s", pc->data[ret].sex); printf("请输入电话:>\n"); scanf("%s", pc->data[ret].tele); printf("请输入地址:>\n"); scanf("%s", pc->data[ret].addr); } printf("修改成功\n"); }
排序函数(按年龄)
qsort函数的应用
int com_name(const void* e1, const void* e2) { return ((contact*)e1)->data->name - ((contact*)e2)->data->name; } void sortcontacy(contact* pc) { qsort(pc->data, pc->sz, sizeof(pc->data[0]), com_name); }
整体代码
test.c
#include"contact.h" void menu() { printf("*\n"); printf(" 1.add 2.del *\n"); printf(" 3.search 4.modify *\n"); printf(" 5.sort 6.print *\n"); printf(" 7.exit *\n"); printf("*\n"); } enum option { EXIT, //退出 ADD, //增加 DEL, //删除 SEARCH, //查 MODIFY, //改 SORT, //排序 PRINT, //打印 }; int main() { int input = 0; //通讯录 contact con; //初始化为0 Initcontact(&con); do { menu(); printf("请选择:\n"); scanf("%d", &input); switch (input) { case ADD: addcontact(&con); break; case DEL: delcontact(&con); break; case SEARCH: seacontact(&con); break; case MODIFY: modcontact(&con); break; case SORT: sortcontact(&con); break; case PRINT: printcontact(&con); break; case EXIT: printf("退出\n"); break; default: printf("选择错误\n"); break; } } while (input); }
contact.h
#pragma once #include
#include
#include
#define MAX_NAME 20 #define MAX_SEX 10 #define MAX_TELE 12 #define MAX_ADDR 30 #define MAX 1000 //一个人的信息 typedef struct peoinfo { char name[MAX_NAME];//名字 char sex[MAX_SEX];//性别 int age; //年龄 char tele[MAX_TELE];//电话 char addr[MAX_ADDR];//地址 }peoinfo; //每次用的时候都要加struct,我们不如直接typedef重命名 //通讯录 typedef struct contact { peoinfo data[MAX];//存放添加进来的人的信息 int sz; //记录当前通讯录中有效信息的个数 }contact; //初始化函数 void Initcontact(contact* pc); //增加信息 void addcontact(contact* pc); //打印函数 void printcontact(const contact* pc); //删除函数(查找函数) void delcontact(contact* pc); //查找函数 void seacontact(contact* pc); //修改信息函数 void modcontact(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));//初始化0 } void addcontact(contact* pc) { //判断通讯录是否满 if (pc->sz == MAX) { printf("通讯录已满,不能存放\n"); return; } printf("请输入名字:>\n"); scanf("%s", pc->data[pc->sz].name); printf("请输入年龄:>\n"); scanf("%d", &(pc->data[pc->sz].age)); printf("请输入性别:>\n"); scanf("%s", pc->data[pc->sz].sex); printf("请输入电话:>\n"); scanf("%s", pc->data[pc->sz].tele); printf("请输入地址:>\n"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; printf("增加成功\n"); } void printcontact(const contact* pc) { int i = 0; //打印目录表 printf("%-20s\t%-5s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址"); //打印数据 for (i = 0; i < pc->sz; i++) { printf("%-20s\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); } } //查找函数 static int findbyname(contact* pc, char name[])//static起保护作用,其他源文件看不到这个函数 { int i = 0; for (i = 0; i < pc->sz; i++) { if (strcmp(pc->data[i].name, name) == 0) { return i; } } return -1; } void delcontact(contact* pc) { char name[MAX_NAME] = { 0 }; //判断 if (pc->sz == 0) { printf("通讯录中没有人员,无需删除"); return; } //查找这个人 printf("请输入要删除的人的名字;>"); scanf("%s", name); int ret = findbyname(pc, name); if (ret == -1) printf("通讯录中没有这个人"); //删除 int i = 0; for (i = ret; i < pc->sz-1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--; printf("删除成功\n"); } void seacontact(contact* pc) { char name[MAX_NAME] = { 0 }; printf("请输入要查找的人的名字;>"); scanf("%s", name); int ret = findbyname(pc, name); if (ret == -1) printf("通讯录中没有这个人"); else { printf("%-20s\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 modcontact(contact* pc) { char name[MAX_NAME] = { 0 }; printf("请输入要修改的人的名字;>"); scanf("%s", name); int ret = findbyname(pc, name); if (ret == -1) printf("通讯录中没有这个人"); else { printf("请输入名字:>\n"); scanf("%s", pc->data[ret].name); printf("请输入年龄:>\n"); scanf("%d", &(pc->data[ret].age)); printf("请输入性别:>\n"); scanf("%s", pc->data[ret].sex); printf("请输入电话:>\n"); scanf("%s", pc->data[ret].tele); printf("请输入地址:>\n"); scanf("%s", pc->data[ret].addr); } printf("修改成功\n"); } //qsort排序年龄 int com_age(void* e1, void* e2) { return ((contact*)e1)->data->age - ((contact*)e2)->data->age; } void sortcontact(contact* pc) { qsort(pc->data, pc->sz, sizeof(pc->data[0]), com_age); }
程序的整体逻辑并不算太复杂,精髓就在与两个结构体的定义,和typedef的重命名,省去了不少写代码过程中的麻烦
通讯录程序到这里就结束啦,感谢您的阅读 –
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/222075.html原文链接:https://javaforall.net
