定义结构体
我们要做一个通讯录,里面的信息有一个人的名字,年龄,性别,地址和电话号
对于姓名,年龄等字符串,为了日后方便调整其长度,需要预定义一下它们的长度
#define MAX 100 #define NAME_MAX 20 #define SEX_MAX 5 #define ADDR_MAX 30 #define TELE_MAX 12 #define DEFAULT_SIZE 3 #define INC_SIZE 2
接着定义这个结构体
typedef struct Peo { char name[NAME_MAX]; int age; char sex[SEX_MAX]; char addr[ADDR_MAX]; char tele[TELE_MAX]; }Peo;
既然我们要写出一个通讯录,这个通讯录中就必须可以容纳许多人的信息,所以需要定义一个Peo类型的数组
//定义一个长度为100的Peo类型的数组 Peo contact[MAX] ={0};
然后我们发现,我们还需要有一个变量记录当前通讯录中有多少人的数据,所以定义一个int size= 0
可是接下来的各个操作函数中,我们则需要传这个数组和记录长度的这个变量,仿佛它们2个一直都是“捆绑”在一起的
所以我们可以再定义一个结构体,将记录信息的数组和size写到这个结构体中
typedef struct Contact { //静态版本 Peo data[MAX]; int size; }Contact;
接下来我们发现,这样写只能存放一定数量的信息,如果想存放更多的信息,就需要不断的更改预处理中MAX的值,如果给MAX的值赋给一个很大很大的数,则大多时候大部分的空间都是空闲着的,都被浪费了
所以我们定义一个可以动态开辟空间的一个结构体,需要多少,开辟多少
typedef struct Contact { //动态版本 Peo* data;//指向存放人的信息 int size;//当前已经存放信息的个数 int capacity;//当前通讯录最大容量 }Contact;
基础操作部分
我们可以先写一个目录
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"); }
接着再写一个函数,用来定义一个通讯录和选择各种操作
在switch语句中,为了方便知道每个case都是什么操作,我们可以定义一个枚举
enum Choose1 { EXIT1, ADD, DEL, SEARCH, MODIFY, SHOW, SORT };
void contact() { Contact con; int input = 0; do { menu(); printf("请输入你的选择\n"); scanf("%d", &input); switch (input) { case ADD: break; case DEL: break; case SEARCH: break; case MODIFY: break; case SHOW: break; case SORT: break; case EXIT1: printf("退出程序\n"); exit(0); default: printf("选择错误\n"); break; } } while (input); }
初始化
我们定义了一个通讯录后,需要进行初始化,可以开辟一个默认大小的空间,这个默认大小是我们在预处理时定义的
void InitContact(Contact* con) { assert(con); con->size = 0; Peo* ptr = (Peo*)calloc(DEFAULT_SIZE,sizeof(Peo)); if (ptr == NULL) { perror("InitContact::calloc"); return; } con->data = ptr; con->capacity = DEFAULT_SIZE; }
增加操作
因为这个是动态版本的通讯录,所以我们每次增加数据都需查看当前存放数据的空间是否是满的
所以我们可以单独定义一个增容函数
void check_capacity(Contact* con) { assert(con); if (con->capacity == con->size) { //增容 Peo* ptr = (Peo*)realloc(con->data, (INC_SIZE + con->capacity) * sizeof(Peo)); if (ptr == NULL) { perror("check_capacity:realloc"); return; } con->data = ptr; con->capacity += INC_SIZE; } }
void AddContact(Contact* con) { assert(con); check_capacity(con); if (con->size == MAX) { printf("已满,无法添加"); return; } printf("请输入姓名\n"); scanf("%s", con->data[con->size].name); printf("请输入性别\n"); scanf("%s", con->data[con->size].sex); printf("请输入年龄\n"); scanf("%d", &con->data[con->size].age); printf("请输入地址\n"); scanf("%s", con->data[con->size].addr); printf("请输入电话\n"); scanf("%s", con->data[con->size].tele); con->size++; printf("\n"); }
展现操作,这个函数是打印当前通讯录中所有的数据
v
oid ShowContact(Contact* con) { assert(con); if (con->size == 0) { printf("现在0人,无法显示信息\n"); return; } printf("%-10s\t%-5s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话"); for (int i = 0; i < con->size; i++) { printf("%-10s\t%-5d\t%-5s\t%-20s\t%-12s\n", con->data[i].name, con->data[i].age, con->data[i].sex, con->data[i].addr, con->data[i].tele); } printf("\n"); }
16
在后续的查找函数和删除函数,都是通过姓名查找到对应的信息,再进行其余操作,所以我们可以单独定义一个通过姓名查找函数
通过姓名查找,如果查找到了返回下标,否则返回-1
int FindByName(const Contact* con,char* find_name) { assert(con); for (int i = 0; i < con->size; i++) { if (strcmp(find_name, con->data[i].name) == 0) { return i; } } return -1; }
删除操作
先通过前面的FindByName函数找到要删除的人的信息,再进行删除操作
void DelByName(Contact* con) { assert(con); if (con->size==0) { printf("目前人数为0,无法进行删除操做\n"); return; } printf("输入你想要删除的人的名字"); char del_name[NAME_MAX]; scanf("%s", del_name); int pos = FindByName(con, del_name); if (pos == -1) { printf("找不到此人\n"); return; } for (int i = pos; i < con->size - 1; i++) { con->data[i] = con->data[i + 1]; } con->size--; printf("删除成功\n"); }
查询操作
void SearchByName(const Contact* con) { assert(con); if (con->size == 0) { printf("目前0人,无法查询\n"); return; } printf("输入你想要找的人的名字"); char find_name[NAME_MAX]; scanf("%s", find_name); int ret = FindByName(con, find_name); if (ret == -1) { printf("找不到此人\n"); return; } else { printf("找到了!\n"); printf("他\\她的信息如下:\n"); //打印信息 printf("姓名:%s\t年龄:%d\t性别:%s\t地址:%s\t电话:%s\n", con->data[ret].name, con->data[ret].age, con->data[ret].sex, con->data[ret].addr, con->data[ret].tele); } printf("\n"); }
修改操作
通过FindByName函数找到要修改信息的下标,之后进行修改函数
void ModifyContact(Contact* con) { assert(con); if (con->size == 0) { printf("目前0人,无法修改\n"); return; } printf("输入你想要修改人的名字"); char modify_name[NAME_MAX]; scanf("%s", modify_name); int pos = FindByName(con, modify_name); if (pos == -1) { printf("找不到此人\n"); return; } else { printf("请输入新的姓名\n"); scanf("%s", con->data[pos].name); printf("请输入新的性别\n"); scanf("%s", con->data[pos].sex); printf("请输入新的年龄\n"); scanf("%d", &con->data[pos].age); printf("请输入新的地址\n"); scanf("%s", con->data[pos].addr); printf("请输入新的电话\n"); scanf("%s", con->data[pos].tele); } }
排序操作
这里的排序是通过C语言自带的qsort函数进行的排序,不做过多介绍
int CmpName(const void* e1, const void* e2) { return strcmp(((Peo*)e1)->name, ((Peo*)e2)->name); } int CmpAge(const void* e1, const void* e2) { return ((Peo*)e1)->age - ((Peo*)e2)->age; } void SortByAge(Contact* con) { assert(con); qsort(con->data, con->size, sizeof(con->data[0]), CmpAge); printf("按年龄排序:\n"); ShowContact(con); } void SortByName(Contact* con) { assert(con); qsort(con->data, con->size, sizeof(con->data[0]), CmpName); printf("按姓名排序:\n"); ShowContact(con); }
9
销毁操作
因为这个通讯录中存放数据的空间是动态开辟到堆区的,所以需要我们通过free函数将动态开辟的空间销毁归还给操作系统
void DestroyContact(Contact* con) { assert(con); free(con->data); con->data = NULL; con->size = 0; con->capacity = 0; con = NULL; }
文件操作部分
每次运行依次程序,最后都要将程序中的数据存放到文件中
因为结构体中有许多不同的类型,所以这里选择用二进制文件存放数据
void SaveContact(Contact* con) { assert(con); FILE* pf = fopen("contact.txt", "wb"); if (pf == NULL) { perror("SaveContact"); return; } else { int i = 0; for (i = 0; i < con->size; i++) { fwrite(con->data + i, sizeof(Peo), 1, pf); } fclose(pf); pf = NULL; printf("保存成功\n"); } }
每次运行程序,都需要将文件中的数据读取出来到程序中,便于对这些信息进行一系列操作
void LoadContact(Contact* con) { //读数据 //1,打开文件 FILE* pf = fopen("contact.txt", "rb"); if (pf == NULL) { perror("LoadContact"); return; } else { //2.读数据 Peo tmp = { 0 }; int i = 0; while (fread(&tmp, sizeof(Peo), 1, pf)) { //增容 check_capacity(con); con->data[i] = tmp; con->size++; i++; } fclose(pf); pf = NULL; } }
全部代码:
头文件Contact.h #define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include <stdio.h> #include <string.h> #include <assert.h> #include <stdlib.h> #include <errno.h> #define MAX 100 #define NAME_MAX 20 #define SEX_MAX 5 #define ADDR_MAX 30 #define TELE_MAX 12 #define DEFAULT_SIZE 3 #define INC_SIZE 2 typedef struct Peo { char name[NAME_MAX]; int age; char sex[SEX_MAX]; char addr[ADDR_MAX]; char tele[TELE_MAX]; }Peo; typedef struct Contact { //静态版本 /*Peo data[MAX]; int size;*/ //动态版本 Peo* data;//指向存放人的信息 int size;//当前已经存放信息的个数 int capacity;//当前通讯录最大容量 }Contact; void InitContact(Contact* con); void AddContact(Contact* con); void ShowContact(Contact* con); void DelByName(Contact* con); int FindByName(const Contact* con, char* find_name); void SearchByName(const Contact* con); void ModifyContact(Contact* con); int CmpName(const void* e1, const void* e2); int CmpAge(const void* e1, const void* e2); void SortByAge(const Contact* con); void SortByName(const Contact* con); void ClearAllContact(Contact* con); void DestroyContact(Contact* con); void SaveContact(Contact* con); void LoadContact(Contact* con); 1
2
3
4
ContactList.c #define _CRT_SECURE_NO_WARNINGS 1 #include "ContactList.h" //静态版本 //void InitContact(Contact* con) //{ // assert(con); // con->size = 0; // memset(con->data, 0, sizeof(con->data)); //} //动态版本 void InitContact(Contact* con) { assert(con); con->size = 0; Peo* ptr = (Peo*)calloc(DEFAULT_SIZE,sizeof(Peo)); if (ptr == NULL) { perror("InitContact::calloc"); return; } con->data = ptr; con->capacity = DEFAULT_SIZE; //加载文件信息到通讯录 LoadContact(con); } //静态版本 //void AddContact(Contact* con) //{ // assert(con); // if (con->size == MAX) // { // printf("已满,无法添加"); // return; // } // // // printf("请输入姓名\n"); // scanf("%s", con->data[con->size].name); // printf("请输入性别\n"); // scanf("%s", con->data[con->size].sex); // printf("请输入年龄\n"); // scanf("%d", &con->data[con->size].age); // printf("请输入地址\n"); // scanf("%s", con->data[con->size].addr); // printf("请输入电话\n"); // scanf("%s", con->data[con->size].tele); // con->size++; // printf("\n"); //} //动态版本 void check_capacity(Contact* con) { assert(con); if (con->capacity == con->size) { //增容 Peo* ptr = (Peo*)realloc(con->data, (INC_SIZE + con->capacity) * sizeof(Peo)); if (ptr == NULL) { perror("check_capacity:realloc"); return; } con->data = ptr; con->capacity += INC_SIZE; } } void AddContact(Contact* con) { assert(con); check_capacity(con); if (con->size == MAX) { printf("已满,无法添加"); return; } printf("请输入姓名\n"); scanf("%s", con->data[con->size].name); printf("请输入性别\n"); scanf("%s", con->data[con->size].sex); printf("请输入年龄\n"); scanf("%d", &con->data[con->size].age); printf("请输入地址\n"); scanf("%s", con->data[con->size].addr); printf("请输入电话\n"); scanf("%s", con->data[con->size].tele); con->size++; printf("\n"); } void ShowContact(Contact* con) { assert(con); if (con->size == 0) { printf("现在0人,无法显示信息\n"); return; } printf("%-10s\t%-5s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话"); for (int i = 0; i < con->size; i++) { printf("%-10s\t%-5d\t%-5s\t%-20s\t%-12s\n", con->data[i].name, con->data[i].age, con->data[i].sex, con->data[i].addr, con->data[i].tele); } printf("\n"); } int FindByName(const Contact* con,char* find_name) { assert(con); for (int i = 0; i < con->size; i++) { if (strcmp(find_name, con->data[i].name) == 0) { return i; } } return -1; } void DelByName(Contact* con) { assert(con); if (con->size==0) { printf("目前人数为0,无法进行删除操做\n"); return; } printf("输入你想要删除的人的名字"); char del_name[NAME_MAX]; scanf("%s", del_name); int pos = FindByName(con, del_name); if (pos == -1) { printf("找不到此人\n"); return; } for (int i = pos; i < con->size - 1; i++) { con->data[i] = con->data[i + 1]; } con->size--; printf("删除成功\n"); } void SearchByName(const Contact* con) { assert(con); if (con->size == 0) { printf("目前0人,无法查询\n"); return; } printf("输入你想要找的人的名字"); char find_name[NAME_MAX]; scanf("%s", find_name); int ret = FindByName(con, find_name); if (ret == -1) { printf("找不到此人\n"); return; } else { printf("找到了!\n"); printf("他\\她的信息如下:\n"); //打印信息 printf("姓名:%s\t年龄:%d\t性别:%s\t地址:%s\t电话:%s\n", con->data[ret].name, con->data[ret].age, con->data[ret].sex, con->data[ret].addr, con->data[ret].tele); } printf("\n"); } void ModifyContact(Contact* con) { assert(con); if (con->size == 0) { printf("目前0人,无法修改\n"); return; } printf("输入你想要修改人的名字"); char modify_name[NAME_MAX]; scanf("%s", modify_name); int pos = FindByName(con, modify_name); if (pos == -1) { printf("找不到此人\n"); return; } else { printf("请输入新的姓名\n"); scanf("%s", con->data[pos].name); printf("请输入新的性别\n"); scanf("%s", con->data[pos].sex); printf("请输入新的年龄\n"); scanf("%d", &con->data[pos].age); printf("请输入新的地址\n"); scanf("%s", con->data[pos].addr); printf("请输入新的电话\n"); scanf("%s", con->data[pos].tele); } } int CmpName(const void* e1, const void* e2) { return strcmp(((Peo*)e1)->name, ((Peo*)e2)->name); } int CmpAge(const void* e1, const void* e2) { return ((Peo*)e1)->age - ((Peo*)e2)->age; } void SortByAge(Contact* con) { assert(con); qsort(con->data, con->size, sizeof(con->data[0]), CmpAge); printf("按年龄排序:\n"); ShowContact(con); } void SortByName(Contact* con) { assert(con); qsort(con->data, con->size, sizeof(con->data[0]), CmpName); printf("按姓名排序:\n"); ShowContact(con); } void ClearAllContact(Contact* con) { assert(con); memset(con->data, 0, sizeof(con->data)); con->size = 0; } void DestroyContact(Contact* con) { assert(con); free(con->data); con->data = NULL; con->size = 0; con->capacity = 0; con = NULL; } void SaveContact(Contact* con) { assert(con); FILE* pf = fopen("contact.txt", "wb"); if (pf == NULL) { perror("SaveContact"); return; } else { int i = 0; for (i = 0; i < con->size; i++) { fwrite(con->data + i, sizeof(Peo), 1, pf); } fclose(pf); pf = NULL; printf("保存成功\n"); } } void LoadContact(Contact* con) { //读数据 //1,打开文件 FILE* pf = fopen("contact.txt", "rb"); if (pf == NULL) { perror("LoadContact"); return; } else { //2.读数据 Peo tmp = { 0 }; int i = 0; while (fread(&tmp, sizeof(Peo), 1, pf)) { //增容 check_capacity(con); con->data[i] = tmp; con->size++; i++; } fclose(pf); pf = NULL; } }
tset.c #define _CRT_SECURE_NO_WARNINGS 1 #include "ContactList.h" #include <stdio.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 Choose1 { EXIT1, ADD, DEL, SEARCH, MODIFY, SHOW, SORT }; enum Choose2 { EXIT2, SHORTBYNAME, SHORTBYAGE }; void Sort(Contact* con) { assert(con); printf("请选择排序方式:\n"); printf("1.按姓名排序(升序)\n"); printf("2.按年龄排序(升序)\n"); printf("0.退出排序\n"); printf("\n"); int choose = 0; do { printf("请输入你的选择\n"); scanf("%d", &choose); switch (choose) { case SHORTBYNAME: SortByName(con); break; case SHORTBYAGE: SortByAge(con); break; case EXIT2: printf("退出排序\n"); break; default: printf("输入错误,请重新输入\n"); break; } } while (choose); } void contact() { Contact con; InitContact(&con); int input = 0; do { menu(); printf("请输入你的选择\n"); scanf("%d", &input); switch (input) { case ADD: AddContact(&con); break; case DEL: DelByName(&con); break; case SEARCH: SearchByName(&con); break; case MODIFY: ModifyContact(&con); break; case SHOW: ShowContact(&con); break; case SORT: Sort(&con); break; case EXIT1: SaveContact(&con); DestroyContact(&con); printf("退出程序\n"); exit(0); default: printf("选择错误\n"); break; } } while (input); } int main() { contact(); return 0; }