5.修改联系人
修改联系人就简单了,有了之前那个寻找对应联系人的函数,我们已经能够快速的找到目标下标,也就是说,我们只要对着相应的东西改就行
void dif(con* c1) { assert(c1); if (c1->sz == 0) { printf("通讯录为空,操作失败\n"); return; } else { printf("请输入你要修改的联系人的姓名\n"); int i = find(c1); if (i != -1) { printf("请输入被修改后的姓名\n"); scanf("%s", c1->data[i].name); printf("请输入被修改后的年龄\n"); scanf("%d", &c1->data[i].age); printf("请输入被修改后的性别\n"); scanf("%s", c1->data[i].sex); printf("请输入被修改后的联系方式\n"); scanf("%s", c1->data[i].tel); printf("请输入被修改后的地址\n"); scanf("%s", c1->data[i].address); printf("修改成功\n"); return; } else { printf("查无此人,操作失败\n"); return; } } }
6.查找联系人
这个用我们的下标查找函数,找到下标再多一步打印即可
void search(con* c1) { assert(c1); if (c1->sz == 0) { printf("通讯录为空,操作失败\n"); return; } else { printf("请输入你要查找的联系人姓名\n"); int i=find(c1); if(i!=-1) { printf("%-10s\t%-5s\t%-5s\t%-12s\t%-15s\t\n", "姓名", "年龄", "性别", "联系方式", "家庭住址"); printf("%-10s\t%-5d\t%-5s\t%-12s\t%-15s\t\n", c1->data[i].name, c1->data[i].age, c1->data[i].sex, c1->data[i].tel, c1->data[i].address); return; } else { printf("查无此人,操作失败\n"); return; } } }
7.退出通讯录
最简单的来了,exit()函数即可
8.拓展:通讯录排序
我们存放联系人的时候很可能是随便来的,就是想到谁就放谁,久而久之,通讯录就会变得杂乱无章,因此这里笔者特意写了一个通讯录排序的功能,这里面使用到了qsort函数,如果你对qsort函数不是很理解的话那可以去看笔者之前写的文章手把手教你使用qsort函数http://t.csdn.cn/wSMoW
别忘了将函数放进switch语句中,并重新规划菜单指引操作。
基础款
int cmp_age(const void*ptr1,const void*ptr2 ) { return ((peo*)ptr1)->age - ((peo*)ptr2)->age;//升序排序 } void sort(const con*c1) { qsort(c1->data,c1->sz, sizeof(peo),cmp_age); //c1->data是存放联系人的结构体数组首元素的地址 //c1->sz是要排的人数//sizeof(peo)为联系人结构体数组一个元素的大小 //cmp_age是需要我们自己设计的函数 //如何设计看笔者之前的文章,这里就不再赘述 printf("排序成功\n"); }
升级版
int cmp_age(const void*ptr1,const void*ptr2 ) { return ((peo*)ptr1)->age - ((peo*)ptr2)->age;//升序排序 } int cmp_name(const void* ptr1, const void* ptr2) { return strcmp(((peo*)ptr1)->name,((peo*)ptr2)->name); } int cmp_tel(const void* ptr1, const void* ptr2) { return strcmp(((peo*)ptr1)->tel,((peo*)ptr2)->tel); } void sort(const con* c1) { int choose = 0; do { printf("输入0退出排序\n"); printf("输入1按照年龄排序\n"); printf("输入2按照姓名排序\n"); printf("输入3按照电话号码排序\n"); scanf("%d", &choose); switch (choose) { case 1: qsort(c1->data, c1->sz, sizeof(peo), cmp_age); //c1->data是存放联系人的结构体数组首元素的地址 //c1->sz是要排的人数//sizeof(peo)为联系人结构体数组一个元素的大小 //cmp_age是需要我们自己设计的函数 //如何设计看笔者之前的文章,这里就不再赘述 printf("排序成功\n"); break; case 2: qsort(c1->data, c1->sz, sizeof(peo), cmp_name); printf("排序成功\n"); break; case 3: qsort(c1->data, c1->sz, sizeof(peo), cmp_tel); printf("排序成功\n"); break; case 0: return; break; default: printf("语法错误,请重新输入\n"); break; } } while (1);//无限循环除非choose为0 }
9.全代码
全都被笔者写在了一个文件中,其实最好还是分一下,比如说一个文件放函数的声明,一个文件来实现函数,一个文件来实现操作
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> #include<assert.h> #include<string.h> #define name_max 10 #define sex_max 5 #define tel_max 12 #define address_max 15 #define people_max 100//最多能存放100个联系人 typedef struct people { char name[name_max];//姓名存放的是字符串,故用char int age; //年龄存放的是一个数字,故用int char sex[sex_max];//与名字的原因相同 char tel[tel_max];//与名字的原因相同 char address[address_max];//与名字的原因相同 }peo;//来个别名,使用方便 typedef struct contact { peo data[people_max]; //结构体成员名为data,它是可以存放100个struct people类型元素的数组 int sz; //已经存放了几个联系人 }con;//别名,使用方便 void menu() { printf("**********************************************\n"); printf("**********************************************\n"); printf("*******1.增加联系人******2.删除联系人*********\n"); printf("*******3.修改联系人******4.查找联系人*********\n"); printf("*******5.打印通讯录******6.通讯录排序*********\n"); printf("*******7.退出通讯录***************************\n"); printf("**********************************************\n"); } void init_contact(con* c1)//初始化通讯录 { assert(c1); //断言,避免传空指针,使用这个函数需要引assert.h头文件 memset(c1->data,0,sizeof(c1->data)); //c1->data,指向的是数组名,代表着数组首元素的地址 //sizeof(c1->data)代表计算整个数组的字节数 //0代表把给定地址往后的sizeof(c1->data)个字节都初始化为0 //memset位于stdlib.h头文件中 c1->sz = 0;//把c1指向的sz初始化为0 } void add(con*c1)//增加联系人 { assert(c1);//断言防止传空指针 if (c1->sz == people_max) { printf("通讯录已满,存放失败\n"); //存放失败就直接返回,由于是空类型,所以直接return return; } else//通讯录没满就往里存 { printf("请输入联系人姓名\n"); scanf("%s",c1->data[c1->sz].name);//字符串变量名就是首地址 printf("请输入联系人年龄\n"); scanf("%d", &(c1->data[c1->sz].age));//年龄是整型,得取地址 printf("请输入联系人性别\n"); scanf("%s", c1->data[c1->sz].sex); printf("请输入联系人联系方式\n"); scanf("%s", c1->data[c1->sz].tel); printf("请输入联系人家庭住址\n"); scanf("%s", c1->data[c1->sz].address); printf("添加成功\n"); c1->sz += 1;//联系人增多一名 } } void print_contact(const con* c1)//打印通讯录 { assert(c1);//断言避免传空指针 int i = 0; if (c1->sz == 0) { printf("通讯录未存放联系人\n"); return; } printf("%-10s\t%-5s\t%-5s\t%-12s\t%-15s\t\n", "姓名", "年龄", "性别", "联系方式", "家庭住址"); //根据自己的喜好对齐,使信息更加明了 for (i = 0; i < c1->sz; i++)//写个循环,因为可能不止一个联系人 { printf("%-10s\t%-5d\t%-5s\t%-12s\t%-15s\t\n", c1->data[i].name, c1->data[i].age, c1->data[i].sex, c1->data[i].tel, c1->data[i].address); } } int find(const con* c1) //要有返回值来判断是否找到目标 //只是寻找不修改,用const修饰 { char a1[name_max] = { 0 };//初始化 scanf("%s", &a1); int i = 0; for (i = 0; i < c1->sz; i++) { if (strcmp(a1, c1->data[i].name) == 0) { return i;//找到目标,直接返回下标,注意下标可能为0 } } return -1;//找不到目标,返回-1 } void con_del(con* c1)//删除联系人 { assert(c1); if (c1->sz == 0) { printf("通讯录为空,操作失败\n"); return; } printf("请输入你要删除的联系人的姓名\n"); int i = find(c1); if (i!=-1) {//找到的话返回非0的数,为真,进入删除,没找到返回0,为假,不进入删除 for (; i < c1->sz - 1; i++) //为什么是sz-1呢,避免越界操作,最后一个元素其实我们是可以不用管它的 //因为sz--之后你下一次增加联系人的时候就会把它覆盖掉 //且你不增加联系人的话,你肯定再也访问不到这个下标对应的元素了 { c1->data[i] = c1->data[i + 1]; } printf("删除成功\n"); c1->sz--; } else { printf("查无此人,操作失败\n"); return; } } void dif(con* c1) { assert(c1); if (c1->sz == 0) { printf("通讯录为空,操作失败\n"); return; } else { printf("请输入你要修改的联系人的姓名\n"); int i = find(c1); if (i != -1) { printf("请输入被修改后的姓名\n"); scanf("%s", c1->data[i].name); printf("请输入被修改后的年龄\n"); scanf("%d", &c1->data[i].age); printf("请输入被修改后的性别\n"); scanf("%s", c1->data[i].sex); printf("请输入被修改后的联系方式\n"); scanf("%s", c1->data[i].tel); printf("请输入被修改后的地址\n"); scanf("%s", c1->data[i].address); printf("修改成功\n"); return; } else { printf("查无此人,操作失败\n"); return; } } } void search(con* c1) { assert(c1); if (c1->sz == 0) { printf("通讯录为空,操作失败\n"); return; } else { printf("请输入你要查找的联系人姓名\n"); int i=find(c1); if(i!=-1) { printf("%-10s\t%-5s\t%-5s\t%-12s\t%-15s\t\n", "姓名", "年龄", "性别", "联系方式", "家庭住址"); printf("%-10s\t%-5d\t%-5s\t%-12s\t%-15s\t\n", c1->data[i].name, c1->data[i].age, c1->data[i].sex, c1->data[i].tel, c1->data[i].address); return; } else { printf("查无此人,操作失败\n"); return; } } } int cmp_age(const void*ptr1,const void*ptr2 ) { return ((peo*)ptr1)->age - ((peo*)ptr2)->age;//升序排序 } int cmp_name(const void* ptr1, const void* ptr2) { return strcmp(((peo*)ptr1)->name,((peo*)ptr2)->name); } int cmp_tel(const void* ptr1, const void* ptr2) { return strcmp(((peo*)ptr1)->tel,((peo*)ptr2)->tel); } void sort(const con* c1) { int choose = 0; do { printf("输入0退出排序\n"); printf("输入1按照年龄排序\n"); printf("输入2按照姓名排序\n"); printf("输入3按照电话号码排序\n"); scanf("%d", &choose); switch (choose) { case 1: qsort(c1->data, c1->sz, sizeof(peo), cmp_age); //c1->data是存放联系人的结构体数组首元素的地址 //c1->sz是要排的人数//sizeof(peo)为联系人结构体数组一个元素的大小 //cmp_age是需要我们自己设计的函数 //如何设计看笔者之前的文章,这里就不再赘述 printf("排序成功\n"); break; case 2: qsort(c1->data, c1->sz, sizeof(peo), cmp_name); printf("排序成功\n"); break; case 3: qsort(c1->data, c1->sz, sizeof(peo), cmp_tel); printf("排序成功\n"); break; case 0: return; break; default: printf("语法错误,请重新输入\n"); break; } } while (1);//无限循环除非choose为0 } int main() { int choose = 0; con c1; init_contact(&c1); do { menu(); scanf("%d", &choose); switch (choose) { case 1: add(&c1);//调用增加联系人的函数 break; case 2: con_del(&c1);//调用删除联系人的函数 break; case 3: dif(&c1);//调用修改联系人信息的函数 break; case 4: search(&c1);//调用查找联系人的函数 break; case 5: print_contact(&c1);//调用打印通讯录的函数 break; case 6: sort(&c1);//调用排序函数 break; case 0: exit(1);//调用退出函数 break; default: printf("语法错误,请重新输入\n"); break; } } while (1); //写成无限循环,只能通过输入0退出循环 }
三、动态版
1.结构体修改
动态版本我们通过malloc,realloc和free等一系列动态内存管理函数来实现,如果你对这方面不是很了解的话你可以参考一下笔者之前的文章手把手教你玩转内存函数http://t.csdn.cn/2hntB
首先要修改的是我们的结构体成员, 我们之前采用的是数组的方式实现成员的多少的,但在c环境下数组的定义要求是常量,才能创建数组因此它是不可变的现在我们采用指针的方式来实现一个能随着我们的需要动态分配内存的“数组”,再然后就是容量的大小很重要,它可以判断是否需要扩容
typedef struct contact { peo* data; //使用指针的方式 int sz; //已经存放了几个联系人 int capacity; //总容量的大小 }con;//别名,使用方便
2.初始化修改
void init_contact(con* c1)//初始化通讯录 { c1->sz = 0; c1->capacity = people_max; c1->data =(peo*)malloc(sizeof(peo)*people_max); //开辟数组 if (c1->data == NULL) { perror("init_contact"); //开辟失败,错误提示 exit(1); } }
3.扩容实现
void if_bigger(con* c1) { if (c1->capacity == c1->sz) //当容量和存放的个数相等,空间不够,得扩容 { c1->data = (peo*)realloc(c1->data,sizeof(peo)*(c1->capacity + 2)); //扩容之后比之前的容量大2,按自己喜欢调节 if (c1->data == NULL) { perror("if_bigger"); //开辟失败,错误提示 return; } else { c1->capacity += 2;//开辟成功容量+2 printf("开辟成功,当前可存放联系人个数为%d\n", c1->capacity); } } }
在增加联系人那里添加
void add(con*c1)//增加联系人 { assert(c1);//断言防止传空指针 if_bigger(c1);//放在前面,每次来都先检测一下容量是否够 if (c1->sz == c1->capacity) //这个也要修改,现在是和容量比,之前是和people_max比 { printf("通讯录已满,存放失败\n"); //存放失败就直接返回,由于是空类型,所以直接return return; } else//通讯录没满就往里存 { printf("请输入联系人姓名\n"); scanf("%s",c1->data[c1->sz].name);//字符串变量名就是首地址 printf("请输入联系人年龄\n"); scanf("%d", &(c1->data[c1->sz].age));//年龄是整型,得取地址 printf("请输入联系人性别\n"); scanf("%s", c1->data[c1->sz].sex); printf("请输入联系人联系方式\n"); scanf("%s", c1->data[c1->sz].tel); printf("请输入联系人家庭住址\n"); scanf("%s", c1->data[c1->sz].address); printf("添加成功\n"); c1->sz += 1;//联系人增多一名 } }
这里笔者把people_max调成了3使初始容量减少,这样方便测试扩容效果
4.善后函数
这个东西是用来摧毁通讯录的,放在退出那块就行
void destroy_contact(con*c1) { c1->capacity = 0; c1->sz = 0; free(c1->data);//释放空间 c1->data = NULL;//野指针变空指针 }
5.全代码
#include<stdio.h> #include<stdlib.h> #include<assert.h> #include<string.h> #define name_max 10 #define sex_max 5 #define tel_max 12 #define address_max 15 #define people_max 3 typedef struct people { char name[name_max];//姓名存放的是字符串,故用char int age; //年龄存放的是一个数字,故用int char sex[sex_max];//与名字的原因相同 char tel[tel_max];//与名字的原因相同 char address[address_max];//与名字的原因相同 }peo;//来个别名,使用方便 //typedef struct contact //{ // peo data[people_max]; // //结构体成员名为data,它是可以存放100个struct people类型元素的数组 // int sz; // //已经存放了几个联系人 //}con;//别名,使用方便 typedef struct contact { peo* data; //使用指针的方式 int sz; //已经存放了几个联系人 int capacity; //总容量的大小 }con;//别名,使用方便 void destroy_contact(con*c1) { c1->capacity = 0; c1->sz = 0; free(c1->data);//释放空间 c1->data = NULL;//野指针变空指针 } void menu() { printf("**********************************************\n"); printf("**********************************************\n"); printf("*******1.增加联系人******2.删除联系人*********\n"); printf("*******3.修改联系人******4.查找联系人*********\n"); printf("*******5.打印通讯录******6.通讯录排序*********\n"); printf("*******7.退出通讯录***************************\n"); printf("**********************************************\n"); } void init_contact(con* c1)//初始化通讯录 { //assert(c1); 断言,避免传空指针,使用这个函数需要引assert.h头文件 //memset(c1->data,0,sizeof(c1->data)); c1->data,指向的是数组名,代表着数组首元素的地址 sizeof(c1->data)代表计算整个数组的字节数 0代表把给定地址往后的sizeof(c1->data)个字节都初始化为0 memset位于stdlib.h头文件中 //c1->sz = 0;//把c1指向的sz初始化为0 c1->sz = 0; c1->capacity = people_max; c1->data =(peo*)malloc(sizeof(peo)*people_max); //开辟数组 if (c1->data == NULL) { perror("init_contact"); //开辟失败,错误提示 exit(1); } } void if_bigger(con* c1) { if (c1->capacity == c1->sz)//容量和存放的个数相等,显然空间不够 { c1->data = (peo*)realloc(c1->data,sizeof(peo)*(c1->capacity + 2)); //扩容之后比之前的容量大2 if (c1->data == NULL) { perror("if_bigger"); //开辟失败,错误提示 return; } else { c1->capacity += 2;//开辟成功容量+2 printf("开辟成功,当前可存放联系人个数为%d\n", c1->capacity); } } } void add(con*c1)//增加联系人 { assert(c1);//断言防止传空指针 if_bigger(c1);//放在前面,每次来都先检测一下容量是否够 if (c1->sz == c1->capacity)//这个也要修改,现在是和容量比 { printf("通讯录已满,存放失败\n"); //存放失败就直接返回,由于是空类型,所以直接return return; } else//通讯录没满就往里存 { printf("请输入联系人姓名\n"); scanf("%s",c1->data[c1->sz].name);//字符串变量名就是首地址 printf("请输入联系人年龄\n"); scanf("%d", &(c1->data[c1->sz].age));//年龄是整型,得取地址 printf("请输入联系人性别\n"); scanf("%s", c1->data[c1->sz].sex); printf("请输入联系人联系方式\n"); scanf("%s", c1->data[c1->sz].tel); printf("请输入联系人家庭住址\n"); scanf("%s", c1->data[c1->sz].address); printf("添加成功\n"); c1->sz += 1;//联系人增多一名 } } void print_contact(const con* c1)//打印通讯录 { assert(c1);//断言避免传空指针 int i = 0; if (c1->sz == 0) { printf("通讯录未存放联系人\n"); return; } printf("%-10s\t%-5s\t%-5s\t%-12s\t%-15s\t\n", "姓名", "年龄", "性别", "联系方式", "家庭住址"); //根据自己的喜好对齐,使信息更加明了 for (i = 0; i < c1->sz; i++)//写个循环,因为可能不止一个联系人 { printf("%-10s\t%-5d\t%-5s\t%-12s\t%-15s\t\n", c1->data[i].name, c1->data[i].age, c1->data[i].sex, c1->data[i].tel, c1->data[i].address); } } int find(const con* c1) //要有返回值来判断是否找到目标 //只是寻找不修改,用const修饰 { char a1[name_max] = { 0 };//初始化 scanf("%s", &a1); int i = 0; for (i = 0; i < c1->sz; i++) { if (strcmp(a1, c1->data[i].name) == 0) { return i;//找到目标,直接返回下标,注意下标可能为0 } } return -1;//找不到目标,返回-1 } void con_del(con* c1)//删除联系人 { assert(c1); if (c1->sz == 0) { printf("通讯录为空,操作失败\n"); return; } printf("请输入你要删除的联系人的姓名\n"); int i = find(c1); if (i!=-1) {//找到的话返回非0的数,为真,进入删除,没找到返回0,为假,不进入删除 for (; i < c1->sz - 1; i++) //为什么是sz-1呢,避免越界操作,最后一个元素其实我们是可以不用管它的 //因为sz--之后你下一次增加联系人的时候就会把它覆盖掉 //且你不增加联系人的话,你肯定再也访问不到这个下标对应的元素了 { c1->data[i] = c1->data[i + 1]; } printf("删除成功\n"); c1->sz--; } else { printf("查无此人,操作失败\n"); return; } } void dif(con* c1) { assert(c1); if (c1->sz == 0) { printf("通讯录为空,操作失败\n"); return; } else { printf("请输入你要修改的联系人的姓名\n"); int i = find(c1); if (i != -1) { printf("请输入被修改后的姓名\n"); scanf("%s", c1->data[i].name); printf("请输入被修改后的年龄\n"); scanf("%d", &c1->data[i].age); printf("请输入被修改后的性别\n"); scanf("%s", c1->data[i].sex); printf("请输入被修改后的联系方式\n"); scanf("%s", c1->data[i].tel); printf("请输入被修改后的地址\n"); scanf("%s", c1->data[i].address); printf("修改成功\n"); return; } else { printf("查无此人,操作失败\n"); return; } } } void search(con* c1) { assert(c1); if (c1->sz == 0) { printf("通讯录为空,操作失败\n"); return; } else { printf("请输入你要查找的联系人姓名\n"); int i=find(c1); if(i!=-1) { printf("%-10s\t%-5s\t%-5s\t%-12s\t%-15s\t\n", "姓名", "年龄", "性别", "联系方式", "家庭住址"); printf("%-10s\t%-5d\t%-5s\t%-12s\t%-15s\t\n", c1->data[i].name, c1->data[i].age, c1->data[i].sex, c1->data[i].tel, c1->data[i].address); return; } else { printf("查无此人,操作失败\n"); return; } } } int cmp_age(const void*ptr1,const void*ptr2 ) { return ((peo*)ptr1)->age - ((peo*)ptr2)->age;//升序排序 } int cmp_name(const void* ptr1, const void* ptr2) { return strcmp(((peo*)ptr1)->name,((peo*)ptr2)->name); } int cmp_tel(const void* ptr1, const void* ptr2) { return strcmp(((peo*)ptr1)->tel,((peo*)ptr2)->tel); } void sort(const con* c1) { int choose = 0; do { printf("输入0退出排序\n"); printf("输入1按照年龄排序\n"); printf("输入2按照姓名排序\n"); printf("输入3按照电话号码排序\n"); scanf("%d", &choose); switch (choose) { case 1: qsort(c1->data, c1->sz, sizeof(peo), cmp_age); //c1->data是存放联系人的结构体数组首元素的地址 //c1->sz是要排的人数//sizeof(peo)为联系人结构体数组一个元素的大小 //cmp_age是需要我们自己设计的函数 //如何设计看笔者之前的文章,这里就不再赘述 printf("排序成功\n"); break; case 2: qsort(c1->data, c1->sz, sizeof(peo), cmp_name); printf("排序成功\n"); break; case 3: qsort(c1->data, c1->sz, sizeof(peo), cmp_tel); printf("排序成功\n"); break; case 0: return; break; default: printf("语法错误,请重新输入\n"); break; } } while (1);//无限循环除非choose为0 } int main() { int choose = 0; con c1; init_contact(&c1); do { menu(); scanf("%d", &choose); switch (choose) { case 1: add(&c1);//调用增加联系人的函数 break; case 2: con_del(&c1);//调用删除联系人的函数 break; case 3: dif(&c1);//调用修改联系人信息的函数 break; case 4: search(&c1);//调用查找联系人的函数 break; case 5: print_contact(&c1);//调用打印通讯录的函数 break; case 6: sort(&c1); break; case 0: destroy_contact(&c1);//摧毁通讯录 exit(1);//调用退出函数 break; default: printf("语法错误,请重新输入\n"); break; } } while (1); //写成无限循环,只能通过输入0退出循环 }
今天的分享到这里就结束了,感谢各位友友的来访,祝各位前程似锦O(∩_∩)O