前言:
经过了结构体原理的具体学习之后,我们需要一个系统的功能程序来对结构体进行相关的复习与应用,更好的促进吸收与理解。
这时候我们以通讯录为例子,加深理解。
实现一个通讯录:
1.可以存放100个人的信息
2.每个人的信息:
- 1.名字 char name[MAX_NAME]
- 2.性别 char sex[MAX_SEX]
- 3.年龄 int age
- 4.电话 char tele[MAX_TELE]
- 5.地址 char addr[MAX_ADDR]
3.增加联系人
4.删除指定联系人
5.查找指定联系人
6.修改指定联系人
7.显示联系人信息
8.排序联系人(按照年龄/名字)
要充分运用结构体的基础知识,那就静态的通讯录入手,实现代码的编写。
一.静态通讯录的实现
各模块的分工和作用:
1.关于通讯录的前期准备
(1)菜单的打印
关于通讯录,建立菜单是非常重要的,因为菜单能够实现和用户的交互。
菜单的选择:
1.增加联系人 2.删除联系人
3.查找联系人 4.修改联系人信息
5.展示所有联系人信息 6.排序联系人信息
0.退出通讯录
代码:
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"); }
打印:
(2)建立一个联系人的信息
可以看到这个PeoInfo是不同类型元素的集合
typedef struct PeoInfo { int age; char name[MAX_NAME]; char sex[MAX_SEX]; char tele[MAX_TELE]; char addr[MAX_ADDR]; }PeoInfo;
(3)通讯录整体
data数组是可以放100个PeoInfo的信息,但不一定放100个,sz的作用是记录通讯录的有效信息个数
typedef struct Contact { PeoInfo data[MAX];//存放数据 int sz;//记录通讯录的有效信息个数 }Contact,*pContact;
这里pContact的数据类型为struct Contact*类型
(4)宏定义常量
万一以后会改到
char name[];
char sex[];
char tele[];
char addr[];
PeoInfo data[];
等大小,那么这时候使用宏定义是必要的,因为这样方便修改修改数组/结构体大小
//只要这里一改,那么数组大小都会改变,就不用一行代码一行代码找了 #define MAX 100 #define MAX_NAME 20 #define MAX_SEX 5 #define MAX_TELE 12 #define MAX_ADDR 30
(5)主函数菜单选项的功能
enum Option { EXIT, ADD, DEL, SEARCH, MODIFY, SHOW, SORT }; int main() { int input = 0; Contact con;//通讯录 InitContact(&con); //初始化通讯录 //加载文件的信息到通讯录中 do { menu(); printf("请选择:>"); scanf("%d", &input); switch (input) { case ADD: AddContact(&con); break; case DEL: DelContact(&con); break; case SEARCH: SearchContact(&con); break; case MODIFY: ModifyContact(&con); break; case SHOW: ShowContact(&con); break; case SORT: SortContact(&con); break; case EXIT: printf("退出通讯录\n"); break; default: printf("选择错误\n"); break; } } while (input); return 0; }
case 1:
AddContact(&con);
break;
case 2:
DelContact(&con);
break;
case 3:
SearchContact(&con);
break;
为什么要定义成枚举?
如果这写选项的写成1,2,3...如果忘记选项是选什么功能的时候,还得去上面菜单里面看选项含义,这样的代码可读性是不高的
而枚举的是递增1往下走,正好对应了0,1,2,3,4...,只要在前面定义上一个EXIT把它赋值成0,其它功能刚好就能对应上了1,2,3,4...增强了可读性
2.通讯录的功能实现
关于一个结构体对象con的理解:
头文件引用:
#include<stdio.h>
#include<string.h>
(1)初始化通讯录
如果不初始化数组,那么里面的值全是随机值
void InitContact(Contact* pc);
void InitContact(Contact* pc) { pc->sz = 0; memset(pc->data, 0, sizeof(pc->data));//sizeof(pc->data)求的是整个数组的大小, //把每个字节改成0,也就是通通改成0了 }
初始化:
pc->data=0 , 错误,数组名是地址,是一个常量的值,假设值为0x0012ff40,那data的值就为0x0012ff40,把0赋值给一个常量是错误的
其实本意应该为:
pc所指向通讯录的data数组的所有内容改成0,也就是改一片空间,用memset
搜一下它的功能:
(2)增加指定联系人
void AddContact(Contact* pc);
void AddContact(Contact* pc) { if (pc->sz == MAX) { printf("通讯录已满,无法增加\n"); return; } printf("请输入名字:>"); scanf("%s", pc->data[pc->sz].name); printf("请输入年龄:>"); scanf("%d", &(pc->data[pc->sz].age));//注意年龄在这里是一个int类型 printf("请输入性别:>"); scanf("%s", pc->data[pc->sz].sex); printf("请输入电话:>"); scanf("%s", pc->data[pc->sz].tele); printf("请输入地址:>"); scanf("%s", pc->data[pc->sz].addr); pc->sz++;//? printf("添加成功\n"); }
注意:
因为除了age其它均为数组名,所以不用取地址操作,只有年龄要
演示效果: