没修完的bug。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
2.实现一个通讯录;
姓名、性别、年龄、电话、住址
提供方法:
1. 添加联系人信息
2. 删除指定联系人信息
3. 查找指定联系人信息
4. 修改指定联系人信息
5. 显示所有联系人信息
6. 清空所有联系人
7. 以名字排序所有联系人
完整代码请滑到页尾
1. 添加联系人信息函数
思路:判断当前从主函数过来的结构体指针是否为空,为空就为它开辟一块空间,然后给这块空间添加联系人信息,如果不是空就找到链表的最后一个结点,在该结点后面开辟一块空间,然后给这块空间添加联系人信息,添加完毕后,最后的结点的结构体成员变量一定要指向空。
void add_contacts(struct contacts **pp) { //临时字符串 char tmp_string[20]; //临时联系人结构体指针 struct contacts *tmp; //临时联系人结构体指针 struct contacts *tmp_end; if (*pp == NULL) { *pp = (struct contacts *)malloc(sizeof(struct contacts)); tmp = *pp; } else { tmp = (struct contacts *)malloc(sizeof(struct contacts)); tmp_end = *pp; while (tmp_end->next )//找到最后一个结点 { tmp_end = tmp_end->next; } tmp_end->next = tmp;//最后一个结点指向新开辟的结点 } printf("输入姓名\n"); getchar();//接收回车键 gets(tmp_string); strcpy(tmp->name, tmp_string); printf("输入地址\n"); gets(tmp_string); strcpy(tmp->address, tmp_string); printf("输入年龄\n"); scanf("%d", &(tmp->age)); printf("输入性别 1代表男 2代表女\n"); scanf("%d",&(tmp->sex)); printf("输入电话\n"); getchar();//接收回车键 gets(tmp_string); strcpy(tmp->phone, tmp_string); tmp->next = NULL;//最后一个结点的指针指向空, printf("添加成功\n"); peopple_num++; }
2. 删除指定联系人信息函数
思路:输入你所要删除联系人的姓名,然后遍历整个链表,如果找到匹配的先分类讨论,如果是第一个结点找到,并且后面没有结点了,直接释放第一个结点内存,并让*pp(等同于主函数中的con)指向空;如果是第一个结点找到,并且后面依然有结点,让*pp(等同于主函数中的con)指向它后面的结点,然后释放该结点;如果是在最后一个结点找到,释放该结点,前一个结点的后面指向空;其他在中间找到匹配的情况则上一个结点指向下一个结点,释放当前结点。
void delete_contacts(struct contacts **pp) { //临时字符串 char tmp_string[20]; //找到的匹配的人数 int count = 0; //定义一个临时联系人结构体变量 struct contacts *tmp = *pp;//指向第一个结点 struct contacts *tmp_delete;//指向第二个结点 if (*pp == NULL) { printf("\n\r\n通讯录暂时没有联系人\n\r\n"); } else { tmp_delete = tmp->next; getchar();//接收回车键 printf("请输入所要删除联系人的姓名\n"); gets(tmp_string); printf("删除结果\n"); if (!strcmp(tmp->name, tmp_string))//如果在第一个结点找到了的话 { if (tmp->next == NULL)//如果只有一个结点 *pp=NULL; else *pp = tmp->next;//让链表本身指向第二个结点 free(tmp);//释放第一个结点的内存 tmp = NULL; tmp_delete = NULL; count++; printf("删除成功!\n"); peopple_num--; } while (tmp_delete!=NULL) { if (!strcmp(tmp_delete->name, tmp_string))//如果找到了的话 { if (tmp_delete->next == NULL)//如果在最后一个结点找到 { tmp->next=NULL; } else { tmp->next = tmp_delete->next; } free(tmp_delete); count++; printf("删除成功!\n"); peopple_num--; break; } tmp = tmp->next; tmp_delete = tmp_delete->next; } if (0 == count) { printf("通讯录里没有此人\n\r\n"); } } }
3. 查找指定联系人信息函数
思路:与删除结点的寻找方式差不多,遍历整个链表,然后打印出匹配的结点的数据。
void seek_contacts(struct contacts **pp) { //临时字符串 char tmp_string[20]; //找到的匹配的人数 int count = 0; //定义一个临时联系人结构体变量 struct contacts *tmp=*pp; if (*pp == NULL) { printf("\n\r\n通讯录暂时没有联系人\n\r\n"); } else { getchar();//接收回车键 printf("请输入所要查找联系人的姓名\n"); gets(tmp_string); printf("查找结果\n"); while (tmp) { if (!strcmp(tmp->name, tmp_string))//如果找到了的话 { printf("姓名: %-10s 地址:%-10s 年龄:%-10d 性别:%-10s 电话:%-20s \n", tmp->name, tmp->address, tmp->age, Sex[tmp->sex], tmp->phone);//打印所有信息 count++;//找到一人匹配 } tmp = tmp->next; } if (0 == count) { printf("查无此人\n\r\n"); } } }
4. 修改指定联系人信息函数
思路:依然是先遍历整个链表,找到匹配的结点,进行修改结点的数据
void alter_contacts(struct contacts **pp) { //临时字符串 char tmp_string[20]; //定义一个临时联系人结构体变量 struct contacts *tmp = *pp; //找到的匹配的人数 int count = 0; //输入量 int input=0; if (*pp == NULL) { printf("\n\r\n通讯录暂时没有联系人\n\r\n"); } else { getchar();//接收回车键 printf("请输入所要修改联系人的姓名\n"); gets(tmp_string); while (tmp) { if (!strcmp(tmp->name, tmp_string))//如果找到了的话 { do { printf("请选择修改联系人的属性\n"); printf("0.退出\n"); printf("1.姓名\n"); printf("2.年龄\n"); printf("3.性别\n"); printf("4.电话\n"); printf("5.地址\n"); printf("请选择>"); scanf("%d",&input); switch (input) { case 1:getchar(); printf("新名字\n"); scanf("%s", tmp->name); break; case 2:getchar(); printf("新年龄\n"); scanf("%d", &(tmp->age)); break; case 3:getchar(); printf("新性别 1男 2女\n"); scanf("%d", &(tmp->sex)); break; case 4:getchar(); printf("新电话\n"); scanf("%s", tmp->phone); break; case 5:getchar(); printf("新地址\n"); scanf("%s", tmp->address); break; } } while (input); printf("修改结果\n"); printf("姓名: %-10s 地址:%-10s 年龄:%-10d 性别:%-10s 电话:%-20s \n", tmp->name, tmp->address, tmp->age, Sex[tmp->sex], tmp->phone);//打印所有信息 count++;//找到一人匹配 break; } tmp = tmp->next; } if (0 == count) { printf("没有搜索到此人\n\r\n"); } } }
5. 显示所有联系人信息
思路:遍历整个链表,把每一项都打印出来
void show_all(struct contacts **pp) { //定义一个临时联系人结构体变量 struct contacts *tmp; if (*pp == NULL) { printf("\n\r\n通讯录暂时没有联系人\n\r\n"); } else { tmp = *pp; printf("显示所有联系人\n"); while (tmp) { printf("姓名: %-10s 地址:%-10s 年龄:%-10d 性别:%-10s 电话:%-20s \n",tmp->name, tmp->address,tmp->age,Sex[tmp->sex],tmp->phone); tmp = tmp->next; } } }
6. 清空所有联系人函数
思路:利用递归先找到最后一个结点释放掉,再回到上一级递归把倒数第二个结点释放掉,一次类推,最后释放掉第一个结点
并且最后一定要*pp=NULL;
void clear(struct contacts *p) { if (p->next == NULL)//如果当前结点是最后一个结点 { free(p);//释放本结点的内存 p = NULL; } else //如果当前结点不是最后一个结点 { clear(p->next);//递归到下一结点 free(p);//释放本结点内存 p= NULL; } } //6. 清空所有联系人 void clear_all(struct contacts **pp) { //定义一个临时联系人结构体变量 if (*pp == NULL) { printf("\n\r\n通讯录暂时没有联系人\n\n\r\n"); } else { clear(*pp);//反向递归删除链表 *pp = NULL; printf("\n\r\n已清空所有联系人!\n\n\r\n"); peopple_num = 0; } }
7. 以名字排序所有联系人函数
思路:排序中交换位置的方式不是用交换数据的方法,而是通过改变指向关系达到改变位置
如果总共只有一个结点不需要排序
如果前面只有两个结点 想要改变tmp1---->tmp2---->NULL的指向关系
图解 tmp1---->tmp2---->NULL的指向关系
第一步:tmp1->next=tmp2->next;
第二步:tmp2-next=tmp1;
完成位置交换
如果前面只三以上结点 想要改变tmp----> tmp1---->tmp2---->NULL的指向关系
第一步:tmp1->next = tmp2->next;
第二步:tmp2->next = tmp1;
第三步:tmp->next = tmp2;
即实现了tmp1与tmp2的位置互换
然后进行迭代,进行下一次循环,迭代过程要讨论tmp1与tmp2是否交换来决定迭代方式。
有了上面的基础,就可以通过冒泡法完成排序啦。
void sort_by_name(struct contacts **pp) { int i = 0; int j = 0; //临时联系人结构体指针1 struct contacts *tmp1= *pp; //临时联系人结构体指针2 struct contacts *tmp2; //临时联系人结构体指针存放中转的地址 struct contacts *tmp; if (*pp == NULL) { printf("\n\r\n通讯录暂时没有联系人\n\n\r\n"); } else { //如果当前是最后一个结点不需要排序 if (tmp1->next == NULL) { ; } else { for (i = peopple_num-1; i >0; i--) { //内层循环结束进行初始化 tmp = *pp; tmp1 = *pp; tmp2= (*pp)->next; for (j=0;j<i;j++) { if (strcmp(tmp1->name, tmp2->name)>0) { if (j==0)//第一个结点和第二个结点比较时 { tmp1->next = tmp2->next; tmp2->next = tmp1; *pp = tmp2; //整体后推一个结点 三句话顺序不能颠倒 tmp = tmp2; tmp1 = tmp2->next; tmp2 = tmp1->next; } else if(j>0) { tmp1->next = tmp2->next; tmp2->next = tmp1; tmp->next = tmp2; //整体后推一个结点 tmp = tmp->next; tmp1 = tmp2->next; tmp2 = tmp1->next; } } else//没有交换 正常后推一个结点 { if (j == 0)//第一个结点和第二个结点比较时 { tmp1 = tmp1->next; tmp2 = tmp2->next; } else if (j>0) { tmp = tmp->next; tmp1 = tmp1->next; tmp2 = tmp2->next; } } } } } } }完整代码
#include<stdio.h> #include<string.h> #include<windows.h> #include<stdlib.h> #pragma warning (disable:4996) //记录通讯录人数 int peopple_num = 0; char *Sex[] = { 0 ,"男","女" }; //定义一个联系人结构体 struct contacts { char name[20];//姓名 char address[10];//地址 int sex;//性别 int age;//年龄 char phone[20];//电话 struct contacts* next;//指向下一个结点 }; //1. 添加联系人信息 void add_contacts(struct contacts **pp); //2. 删除指定联系人信息 void delete_contacts(struct contacts **pp); //3. 查找指定联系人信息 void seek_contacts(struct contacts **pp); //4. 修改指定联系人信息 void alter_contacts(struct contacts **pp); //5. 显示所有联系人信息 void show_all(struct contacts **pp); //6. 清空所有联系人 void clear_all(struct contacts **pp); //7. 以名字排序所有联系人 void sort_by_name(struct contacts **pp); //8.打印菜单 void menu(); int main() { int input=0; //定义一个指向联系人链表的指针 struct contacts *con=NULL; //定义一个函数指针数组 void(*p[8])(struct contacts **pp) = { 0,add_contacts ,delete_contacts ,seek_contacts ,alter_contacts ,show_all,clear_all,sort_by_name }; do { menu(); printf("\n请输入你的选择>"); scanf("%d", &input); if (input <= 7 && input >= 1) { (*p[input])(&con); } else if (input != 0) { printf("输入有误!\n"); } } while (input); printf("你已经退出程序\n"); system("pause"); return 0; } void menu() { printf("\n 通讯录 \n"); printf(" 已添加人数:%-4d 请选择\n", peopple_num); printf(" 0.退出 \n"); printf(" 1.添加联系人信息 \n"); printf(" 2.删除指定联系人信息 \n"); printf(" 3.查找指定联系人信息 \n"); printf(" 4.修改指定联系人信息 \n"); printf(" 5.显示所有联系人信息 \n"); printf(" 6.清空所有联系人 \n"); printf(" 7.以名字排序所有联系人 \n"); } //1. 添加联系人信息 void add_contacts(struct contacts **pp) { //临时字符串 char tmp_string[20]; //临时联系人结构体指针 struct contacts *tmp; //临时联系人结构体指针 struct contacts *tmp_end; if (*pp == NULL) { *pp = (struct contacts *)malloc(sizeof(struct contacts)); tmp = *pp; } else { tmp = (struct contacts *)malloc(sizeof(struct contacts)); tmp_end = *pp; while (tmp_end->next )//找到最后一个结点 { tmp_end = tmp_end->next; } tmp_end->next = tmp;//最后一个结点指向新开辟的结点 } printf("输入姓名\n"); getchar();//接收回车键 gets(tmp_string); strcpy(tmp->name, tmp_string); printf("输入地址\n"); gets(tmp_string); strcpy(tmp->address, tmp_string); printf("输入年龄\n"); scanf("%d", &(tmp->age)); printf("输入性别 1代表男 2代表女\n"); scanf("%d",&(tmp->sex)); printf("输入电话\n"); getchar();//接收回车键 gets(tmp_string); strcpy(tmp->phone, tmp_string); tmp->next = NULL; printf("添加成功\n"); peopple_num++; } //2. 删除指定联系人信息 void delete_contacts(struct contacts **pp) { //临时字符串 char tmp_string[20]; //找到的匹配的人数 int count = 0; //定义一个临时联系人结构体变量 struct contacts *tmp = *pp;//指向第一个结点 struct contacts *tmp_delete;//指向第二个结点 if (*pp == NULL) { printf("\n\r\n通讯录暂时没有联系人\n\r\n"); } else { tmp_delete = tmp->next; getchar();//接收回车键 printf("请输入所要删除联系人的姓名\n"); gets(tmp_string); printf("删除结果\n"); if (!strcmp(tmp->name, tmp_string))//如果在第一个结点找到了的话 { if (tmp->next == NULL)//如果只有一个结点 *pp=NULL; else *pp = tmp->next;//让链表本身指向第二个结点 free(tmp);//释放第一个结点的内存 tmp = NULL; tmp_delete = NULL; count++; printf("删除成功!\n"); peopple_num--; } while (tmp_delete!=NULL) { if (!strcmp(tmp_delete->name, tmp_string))//如果找到了的话 { if (tmp_delete->next == NULL)//如果在最后一个结点找到 { tmp->next=NULL; } else { tmp->next = tmp_delete->next; } free(tmp_delete); count++; printf("删除成功!\n"); peopple_num--; break; } tmp = tmp->next; tmp_delete = tmp_delete->next; } if (0 == count) { printf("通讯录里没有此人\n\r\n"); } } } //3. 查找指定联系人信息 void seek_contacts(struct contacts **pp) { //临时字符串 char tmp_string[20]; //找到的匹配的人数 int count = 0; //定义一个临时联系人结构体变量 struct contacts *tmp=*pp; if (*pp == NULL) { printf("\n\r\n通讯录暂时没有联系人\n\r\n"); } else { getchar();//接收回车键 printf("请输入所要查找联系人的姓名\n"); gets(tmp_string); printf("查找结果\n"); while (tmp) { if (!strcmp(tmp->name, tmp_string))//如果找到了的话 { printf("姓名: %-10s 地址:%-10s 年龄:%-10d 性别:%-10s 电话:%-20s \n", tmp->name, tmp->address, tmp->age, Sex[tmp->sex], tmp->phone);//打印所有信息 count++;//找到一人匹配 } tmp = tmp->next; } if (0 == count) { printf("查无此人\n\r\n"); } } } //4. 修改指定联系人信息 void alter_contacts(struct contacts **pp) { //临时字符串 char tmp_string[20]; //定义一个临时联系人结构体变量 struct contacts *tmp = *pp; //找到的匹配的人数 int count = 0; //输入量 int input=0; if (*pp == NULL) { printf("\n\r\n通讯录暂时没有联系人\n\r\n"); } else { getchar();//接收回车键 printf("请输入所要修改联系人的姓名\n"); gets(tmp_string); while (tmp) { if (!strcmp(tmp->name, tmp_string))//如果找到了的话 { do { printf("请选择修改联系人的属性\n"); printf("0.退出\n"); printf("1.姓名\n"); printf("2.年龄\n"); printf("3.性别\n"); printf("4.电话\n"); printf("5.地址\n"); printf("请选择>"); scanf("%d",&input); switch (input) { case 1:getchar(); printf("新名字\n"); scanf("%s", tmp->name); break; case 2:getchar(); printf("新年龄\n"); scanf("%d", &(tmp->age)); break; case 3:getchar(); printf("新性别 1男 2女\n"); scanf("%d", &(tmp->sex)); break; case 4:getchar(); printf("新电话\n"); scanf("%s", tmp->phone); break; case 5:getchar(); printf("新地址\n"); scanf("%s", tmp->address); break; } } while (input); printf("修改结果\n"); printf("姓名: %-10s 地址:%-10s 年龄:%-10d 性别:%-10s 电话:%-20s \n", tmp->name, tmp->address, tmp->age, Sex[tmp->sex], tmp->phone);//打印所有信息 count++;//找到一人匹配 break; } tmp = tmp->next; } if (0 == count) { printf("没有搜索到此人\n\r\n"); } } } //5. 显示所有联系人信息 void show_all(struct contacts **pp) { //定义一个临时联系人结构体变量 struct contacts *tmp; if (*pp == NULL) { printf("\n\r\n通讯录暂时没有联系人\n\r\n"); } else { tmp = *pp; printf("显示所有联系人\n"); while (tmp) { printf("姓名: %-10s 地址:%-10s 年龄:%-10d 性别:%-10s 电话:%-20s \n",tmp->name, tmp->address,tmp->age,Sex[tmp->sex],tmp->phone); tmp = tmp->next; } } } void clear(struct contacts *p) { if (p->next == NULL)//如果当前结点是最后一个结点 { free(p);//释放本结点的内存 p = NULL; } else //如果当前结点不是最后一个结点 { clear(p->next);//递归到下一结点 free(p);//释放本结点内存 p= NULL; } } //6. 清空所有联系人 void clear_all(struct contacts **pp) { //定义一个临时联系人结构体变量 if (*pp == NULL) { printf("\n\r\n通讯录暂时没有联系人\n\n\r\n"); } else { clear(*pp);//反向递归删除链表 *pp = NULL; printf("\n\r\n已清空所有联系人!\n\n\r\n"); peopple_num = 0; } } //7. 以名字排序所有联系人 void sort_by_name(struct contacts **pp) { int i = 0; int j = 0; //临时联系人结构体指针1 struct contacts *tmp1= *pp; //临时联系人结构体指针2 struct contacts *tmp2; //临时联系人结构体指针存放中转的地址 struct contacts *tmp; if (*pp == NULL) { printf("\n\r\n通讯录暂时没有联系人\n\n\r\n"); } else { //如果当前是最后一个结点不需要排序 if (tmp1->next == NULL) { ; } else { for (i = peopple_num-1; i >0; i--) { //内层循环结束进行初始化 tmp = *pp; tmp1 = *pp; tmp2= (*pp)->next; for (j=0;j<i;j++) { if (strcmp(tmp1->name, tmp2->name)>0) { if (j==0)//第一个结点和第二个结点比较时 { tmp1->next = tmp2->next; tmp2->next = tmp1; *pp = tmp2; //整体后推一个结点 三句话顺序不能颠倒 tmp = tmp2; tmp1 = tmp2->next; tmp2 = tmp1->next; } else if(j>0) { tmp1->next = tmp2->next; tmp2->next = tmp1; tmp->next = tmp2; //整体后推一个结点 tmp = tmp->next; tmp1 = tmp2->next; tmp2 = tmp1->next; } } else//没有交换 正常后推一个结点 { if (j == 0)//第一个结点和第二个结点比较时 { tmp1 = tmp1->next; tmp2 = tmp2->next; } else if (j>0) { tmp = tmp->next; tmp1 = tmp1->next; tmp2 = tmp2->next; } } } } } } }