一、静态版
1.大体思路
我们知道基本的通讯录应该可以记录一个人的基本信息,比如:姓名、性别、年龄、电话号码、住址等,这个通讯录应该有大小上限的,我们就先在头文件中定义个结构体,里面包含了每个人的基本信息。如下:
struct Information { char name[20]; char sex[6]; int age; char tele[12]; //电话 char addr[30]; //住址 };
这是一个人的基本信息,假设我们要存储100人,那么我们怎么办呢?
我们可以再定义一个结构体,这个结构体包含了一个上面结构体的数组,还包含了一个计数元素 sz ,如下:
struct contacts { struct Information data[100]; //定义一个数组,该数组可以存放100人信息 int sz; //当我们添加或删减数据时,sz 相应的++--,sz 应该从零开始记录下一个要添加元素的下标(后面初始化置零) };
联系人存放问题解决了,接下来应该让通讯录初始化,也就是将其数据清零,方便我们存储,再然后就是增加、删减、查找联系人了。大体思路就这样。
2.主程序
在主程序中,我们要实现菜单的打印,及一个do while循环,我们知道添加联系人这个程序最少要执行一次,根据需求可多次执行,do while循环就正好可以。
代码:
void menu() { //菜单显示 1.增加、2.删减、3.查找、4.修改、5.显示、6.排序、0.退出 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 contacts con; //定义一个结构体变量 con do { menu(); printf("请输入:>"); scanf("%d", &input); switch (input) //根据 input 对应值来跳转到相应语句 { case 1: break; case 2: break; case 3: break; case 4: break; case 5: break; case 6: break; case 0: break; default: //输入数字不在0~6范围内 break; } } while (input); //若 input 为0,也就是退出程序,while 循环也会退出 return 0; }
我们看这个 case 后面是数字不够直观,那么有什么办法呢?
我们之前讲过枚举,我们可以用枚举来解决这个问题,如下:
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"); } enum Option { EXIT, //0 ADD, //1 DEL, //2 SEARCH, MODIFY, SHOW, SORT }; int main() { int input = 0; struct contacts con; do { menu(); printf("请输入:>"); scanf("%d", &input); switch (input) { case ADD: break; case DEL: break; case SEARCH: break; case MODIFY: break; case SHOW: break; case SORT: break; case EXIT: break; default: break; } } while (input); return 0; }
我们知道存放数据之前应该初始化一下,将 con 的数据清零,我们应该设计一个初始化函数,那应该传con的地址呢,还是直接传con?因为我们要对其进行修改,所以传地址。
我们下面的函数也应该的传con的地址。
main函数如下:
int main() { int input = 0; struct contacts con; chu_shi(&con); //初始化 do { menu(); printf("请输入:>"); scanf("%d", &input); switch (input) { //每个模块都有对应函数实现 case ADD: Add(&con); break; case DEL: Del(&con); break; case SEARCH: Search(&con); break; case MODIFY: Modify(&con); break; case SHOW: Show(&con); break; case SORT: Sort(&con); break; case EXIT: break; default: printf("输入错误\n"); //提示一下 break; } } while (input); return 0; }
3.函数实现
3.1初始化函数
我们可以所以 memset 函数来实现:
void chu_shi(struct contacts* pc) { assert(pc); //避免pc为空指针,加个断言,需添加头文件:assert.h memset(pc->data, 0, 100 * sizeof(struct Information)); //使用memset函数需包含头文件:string.h pc->sz = 0; }
初始化如下:
3.2增加函数(Add)
void Add(struct contacts* pc) { printf("请输入联系人姓名:>"); scanf("%s", pc->data[pc->sz].name); //输入字符串时,数组名即是首元素地址 printf("请输入联系人性别:>"); scanf("%s", pc->data[pc->sz].sex); printf("请输入联系人年龄:>"); scanf("%d", &(pc->data[pc->sz].age)); //输入整数时要取地址 printf("请输入联系人电话:>"); scanf("%s", pc->data[pc->sz].tele); printf("请输入联系人住址:>"); scanf("%s", pc->data[pc->sz].addr); printf("添加成功\n"); pc->sz++; //每次添加,sz 便 +1 }
3.3删除函数(Del)
要实现删减联系人,首先我们要找到这个联系人吧,我们写一个函数来专门查找联系人:
int cha_zhao(const struct contacts* pc, char* name) //通过名字查找 { int i = 0; for (i; i < pc->sz; i++) { if (strcmp(pc->data[i].name, name) == 0) return i; } return -1; //找到返回对应下标,否则返回-1 }
有了返回值,我们就好写出以下代码:
void Del(struct contacts* pc) { char name[20]; printf("请输入要删除的联系人:>"); scanf("%s", name); int m = cha_zhao(pc, name); // m 接收返回值 if (m != -1) { pc->data[m] = pc->data[pc->sz-1]; //将最后的元素覆盖到 m 下标的元素处,实现删除 pc->sz--; // sz 对应减一 printf("删除成功\n"); } else printf("没有该联系人\n"); }
除了将最后一个数据往前覆盖,我们还能将后面的数据整体向前移一位来实现删除,还可以用memmove函数来向前平移一个单位长度。
3.4查找函数(Search)
跟删除函数类似:
void Search(const struct contacts* pc) { //无需对数据进行修改,所以加上const进行修饰,防止对其进行修改 char name[20]; printf("请输入要查看的联系人:>"); scanf("%s", name); int m = cha_zhao(pc, name); if (m != -1) { // %-20s里的-20是左对齐20个字符的意思,换成20则是右对齐,\t是水平制表符 printf("%-20s\t%-6s\t%-4s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "住址"); printf("%-20s\t%-6s\t%-4d\t%-12s\t%-30s\n", pc->data[m].name, pc->data[m].sex, pc->data[m].age, pc->data[m].tele, pc->data[m].addr); } else printf("没有该联系人\n"); }
看看实际效果:
3.5修改函数(Modify)
void Modify(struct contacts* pc) { char name[20]; printf("请输入要修改的联系人:>"); scanf("%s", name); int m = cha_zhao(pc, name); if (m != -1) { printf("请输入联系人姓名:>"); scanf("%s", pc->data[m].name); printf("请输入联系人性别:>"); scanf("%s", pc->data[m].sex); printf("请输入联系人年龄:>"); scanf("%d", &(pc->data[m].age)); printf("请输入联系人电话:>"); scanf("%s", pc->data[m].tele); printf("请输入联系人住址:>"); scanf("%s", pc->data[m].addr); printf("添加成功\n"); } else printf("没有该联系人\n"); }
3.6显示函数(Show)
void Show(const struct contacts* pc) { int i = 0; printf("%-20s\t%-6s\t%-4s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "住址"); for (i; i < pc->sz; i++) { printf("%-20s\t%-6s\t%-4d\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].sex, pc->data[i].age, pc->data[i].tele, pc->data[i].addr); } }
3.7排序函数(Sort)
排序我们可以用名字排,也可以用年龄、电话等来排序,我们就用名字排序吧。
int bi_jiao(const void* e1, const void* e2) { return strcmp(((struct Information*)e1)->name, ((struct Information*)e2)->name); } void Sort(struct contacts* pc) { qsort(pc->data, pc->sz, sizeof(struct Information), bi_jiao); }
qsort函数在指针进阶(续)里有讲过,这里就不多介绍了。
4.总代码
4.1 test.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"contacts.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"); } enum Option { EXIT, ADD, DEL, SEARCH, MODIFY, SHOW, SORT }; int main() { int input = 0; struct contacts con; chu_shi(&con); do { menu(); printf("请输入:>"); scanf("%d", &input); switch (input) { case ADD: Add(&con); break; case DEL: Del(&con); break; case SEARCH: Search(&con); break; case MODIFY: Modify(&con); break; case SHOW: Show(&con); break; case SORT: Sort(&con); break; case EXIT: break; default: printf("输入错误\n"); break; } } while (input); return 0; }
4.2 contacts.h
为了方便我们修改名字、性别等字符串长度,我们可以用#define来定义一下,便于后期修改。
#pragma once #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_ADDR 30 struct Information { char name[MAX_NAME]; char sex[MAX_SEX]; int age; char tele[MAX_TELE]; char addr[MAX_ADDR]; }; struct contacts { struct Information data[MAX]; int sz; }; //初始化通讯录 void chu_shi(struct contacts* pc); //增加联系人 void Add(struct contacts* pc); //删除联系人 void Del(struct contacts* pc); //查找联系人 void Search(const struct contacts* pc); //修改联系人 void Modify(struct contacts* pc); //显示联系人 void Show(const struct contacts* pc); //名字排序 void Sort(struct contacts* pc);
4.3 contacts.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"contacts.h" void chu_shi(struct contacts* pc) { assert(pc); memset(pc->data, 0, MAX * sizeof(struct Information)); pc->sz = 0; } void Add(struct contacts* pc) { printf("请输入联系人姓名:>"); scanf("%s", pc->data[pc->sz].name); printf("请输入联系人性别:>"); scanf("%s", pc->data[pc->sz].sex); printf("请输入联系人年龄:>"); scanf("%d", &(pc->data[pc->sz].age)); printf("请输入联系人电话:>"); scanf("%s", pc->data[pc->sz].tele); printf("请输入联系人住址:>"); scanf("%s", pc->data[pc->sz].addr); printf("添加成功\n"); pc->sz++; } int cha_zhao(const struct contacts* pc, char* name) { int i = 0; for (i; i < pc->sz; i++) { if (strcmp(pc->data[i].name, name) == 0) return i; } return -1; } void Del(struct contacts* pc) { char name[20]; printf("请输入要删除的联系人:>"); scanf("%s", name); int m = cha_zhao(pc, name); if (m != -1) { pc->data[m] = pc->data[pc->sz-1]; pc->sz--; printf("删除成功\n"); } else printf("没有该联系人\n"); } void Search(const struct contacts* pc) { char name[20]; printf("请输入要查看的联系人:>"); scanf("%s", name); int m = cha_zhao(pc, name); if (m != -1) { printf("%-20s\t%-6s\t%-4s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "住址"); printf("%-20s\t%-6s\t%-4d\t%-12s\t%-30s\n", pc->data[m].name, pc->data[m].sex, pc->data[m].age, pc->data[m].tele, pc->data[m].addr); } else printf("没有该联系人\n"); } void Modify(struct contacts* pc) { char name[20]; printf("请输入要修改的联系人:>"); scanf("%s", name); int m = cha_zhao(pc, name); if (m != -1) { printf("请输入联系人姓名:>"); scanf("%s", pc->data[m].name); printf("请输入联系人性别:>"); scanf("%s", pc->data[m].sex); printf("请输入联系人年龄:>"); scanf("%d", &(pc->data[m].age)); printf("请输入联系人电话:>"); scanf("%s", pc->data[m].tele); printf("请输入联系人住址:>"); scanf("%s", pc->data[m].addr); printf("添加成功\n"); } else printf("没有该联系人\n"); } void Show(const struct contacts* pc) { int i = 0; printf("%-20s\t%-6s\t%-4s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "住址"); for (i; i < pc->sz; i++) { printf("%-20s\t%-6s\t%-4d\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].sex, pc->data[i].age, pc->data[i].tele, pc->data[i].addr); } } int bi_jiao(const void* e1, const void* e2) { return strcmp(((struct Information*)e1)->name, ((struct Information*)e2)->name); } void Sort(struct contacts* pc) { qsort(pc->data, pc->sz, sizeof(struct Information), bi_jiao); }
效果图: