咱们手机上面还有教务系统上都可以存储信息,这些都是使用编程语言来实现的,那么今天,咱们今天就用C语言来实现通讯录。
一. 实验名称
通讯录
二. 实验目标
1.数据的储存
2.数据的增加
3.数据的删除
4.数据的修改
5.数据的展示
6.数据的保存
7.数据的排序
三. 实现的方法
首先,咱们需要一个头文件用来包括数据类型的定义,函数声明,以及所需要使用函数的头文件,然后还需要一个.c文件用来存放所有函数的定义,不然使得主函数所在的.c文件过于冗杂。
test.c(即主函数所在的文件)
#include "test.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,//0 ADD,//1 DEL,//2 SEARCH, MODIFY, SHOW, SORT }; int main() { int input = 0; //创建通讯录并将其初始化 Contact con;//创建 Init_Contact(&con);//将通讯录初始化 do { menu(); printf("请输入那要选择的操作:"); scanf("%d", &input); switch (input) { case ADD: Add_Contact(&con); break; case DEL: Del_Contact(&con); break; case SEARCH: Search_Contact(&con); break; case MODIFY: Modify_Contact(&con); break; case SHOW: Show_Contact(&con); break; case SORT: Sort_Contact(&con); break; case EXIT: Save_Contact(&con); Destroy_Contact(&con); printf("退出通讯录!\n"); break; default: printf("输入错误,请重新选择!\n"); break; } } while (input); return 0; }
为什么上面采用了枚举类型(后续博客会讲到的),因为第一个枚举数默认为0,后面每一个元素都是往后加一,这个Contact con是一个结构体类型(后续博客会讲到的)我们会在头文件中定义。
test.h(即对于函数的声明,结构体定义)
#define _CRT_SECURE_NO_WARNINGS 1 #include <string.h> #include <stdlib.h> #include <assert.h> #include <stdio.h> #pragma once #define NAME_MAX 20 #define SEX_MAX 5 #define TELE_MAX 11 #define NUMBER_MAX 8 #define SZ 3 #define ADD_SZ 2 //定义一个结构体类型,存放通讯录人物的基本信息 typedef struct PeoInfo { char name[NAME_MAX]; int age; char sex[SEX_MAX]; char tele[TELE_MAX]; char number[NUMBER_MAX]; }PeoInfo; //定义一个结构体类型,存放通讯录的信息 typedef struct Contact { PeoInfo* data;//结构体类型,用于存储通讯录人物信息 int sz;//当前已经存放的信息的个数 int capacity;//内存空间大小 }Contact; //函数声明(初始化通讯录) void Init_Contact(Contact* pc); //函数声明(增加通讯录信息) void Add_Contact(Contact* pc); //函数声明(删除通讯录信息) void Del_Contact(Contact* pc); //函数声明(查找通讯录信息) void Search_Contact(const Contact* pc); //函数声明(更改通讯录信息) void Modify_Contact(Contact* pc); //函数声明(展示通讯录信息) void Show_Contact(Contact* pc); //函数声明(排序通讯录) void Sort_Contact(Contact* pc); //函数声明(存储通讯录) void Save_Contact(Contact* pc); //函数声明(销毁通讯录) void Destroy_Contact(Contact* pc); //函数声明(加载通讯录) void Load_Contact(Contact* pc);
这里的结构体类型后续博客会详细的讲解。
contact.h(函数定义)
#include "test.h" //信息初始化 void Init_Contact(Contact* pc) { assert(pc); pc->sz = 0; PeoInfo* ptr = (PeoInfo*)calloc(SZ, sizeof(PeoInfo)); if (ptr == NULL) { perror("Init_Contact::calloc"); return; } pc->data = ptr; pc->capacity = SZ; //加载文件到通讯录 Load_Contact(pc); } //检查容量 void Check_Capacity(Contact* pc) { if (pc->capacity == pc->sz)//此时容量与已存入数据相同,这时需要增容 { PeoInfo* ptr = realloc(pc->data, ((pc->capacity) + ADD_SZ) * sizeof(PeoInfo)); if (ptr == NULL) { perror("Check_Capacity;;realloc"); return; } pc->data = ptr; pc->capacity += ADD_SZ; printf("增容成功!\n"); } } //增加信息 void Add_Contact(Contact* pc) { assert(pc); //检查是否容量已满,已满则选择扩容 Check_Capacity(pc); //增加一个新的信息 printf("请输入名字:"); scanf("%s", pc->data[pc->sz].name); printf("请输入年龄:"); scanf("%d", &pc->data[pc->sz].age); printf("请输入性别:"); scanf("%s", pc->data[pc->sz].sex); printf("请输入电话:"); scanf("%s", pc->data[pc->sz].tele); printf("请输入学号:"); scanf("%s", pc->data[pc->sz].number); //信息个数加一 pc->sz++; } //查找删除人姓名 int Find_Name(Contact* pc, char name[]) { assert(pc); int i = 0; for (i = 0; i < pc->sz; i++) { if (strcmp(pc->data[i].name, name[i]) == 0) { return i; } } return -1; } //删除信息 void Del_Contact(Contact* pc) { assert(pc); char name[NAME_MAX] = { 0 }; if (pc->sz == 0) { printf("通讯录为空,无法删除!\n"); return; } //删除 printf("请输入你要删除人的姓名:"); scanf("%s", name); int ret = Find_Name(pc,name); if (-1 == ret) { printf("你要删除的人不存在!\n"); return; } int i = 0; for (i = ret; i < pc->sz-1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--; printf("删除成功!\n"); } //查找信息 void Search_Contact(const Contact* pc) { assert(pc); char name[NAME_MAX] = { 0 }; printf("请输入你查找人的姓名:"); scanf("%s",name); int tmp = Find_Name(pc,name); if (-1 == tmp) { printf("你要查找的人不存在!\n"); return; } printf("%-20s\t%-4s\t%-5s\t%-11s\t%-8s\n", "名字", "年龄", "性别", "电话", "学号"); printf("%-20s\t%-4d\t%-5s\t%-11s\t%-8s\n", pc->data [tmp].name , pc->data[tmp].age, pc->data[tmp].sex, pc->data[tmp].tele, pc->data[tmp].number); } //更改信息 void Modify_Contact(Contact* pc) { assert(pc); char name[NAME_MAX] = { 0 }; printf("请输入你更改人的姓名:"); scanf("%s", name); int pos = Find_Name(pc, name); if (-1 == pos) { printf("你要更改的人不存在!\n"); return; } //更改 printf("请输入更改的名字:"); scanf("%s", pc->data[pos].name); printf("请输入更改的年龄:"); scanf("%d", &pc->data[pos].age); printf("请输入更改的性别:"); scanf("%s", pc->data[pos].sex); printf("请输入更改的电话:"); scanf("%s", pc->data[pos].tele); printf("请输入更改的学号:"); scanf("%s", pc->data[pos].number); printf("修改完成!\n"); } //展示信息 void Show_Contact(Contact* pc) { assert(pc); int i = 0; printf("%-20s\t%-4s\t%-5s\t%-11s\t%-8s\n", "名字", "年龄", "性别", "电话", "学号"); printf("%-20s\t%-4d\t%-5s\t%-11s\t%-8s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].number); } //比较名字大小 int cmp_name(const void* n1, const void* n2) { return (strcmp(((PeoInfo*)n1)->name, ((PeoInfo*)n2)->name)); } //排序通讯录 void Sort_Contact(Contact* pc) { assert(pc); qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_name); printf("排序完成!\n"); } //储存数据 void Save_Contact(Contact* pc) { FILE* pf = fopen("contact.txt", "wb"); if (NULL == pf) { perror("Save_Contact"); } else { int i = 0; for (i = 0; i < pc->sz; i++) { fwrite(pc->data + i, sizeof(PeoInfo), 1, pf); } } fclose(pf); pf = NULL; printf("保存成功!\n"); } // void Load_Contact(Contact* pc) { FILE* pf = fopen("contact.txt", "rb"); if (pf == NULL) { perror("Load_Contact"); } else { PeoInfo tmp = { 0 }; int i = 0; while (fread(&tmp, sizeof(PeoInfo), 1, pf)) { Check_Capacity(pc); pc->data[i] = tmp; pc->sz++; i++; } fclose(pf); pf = NULL; } } //销毁信息 void Destroy_Contact(Contact* pc) { free(pc->data); pc->data = NULL; pc->sz = 0; pc->capacity = 0; pc = NULL; }
这段代码很长,接下来我们将一一介绍:
assert函数,就是断言,用于判断传入指针是否为空指针,
calloc函数,为创建空间的函数,并会初始化,与melloc还是有略微差异的,
perror函数,查看函数错误的原因并打印出错误信息,
realloc函数,在原有空间上增加空间,
FILE文档类型,
fopen,以某种方式打开文档,
fclose,关闭文档,并且需要将其置位空指针,
free,释放空间函数创建的空间,也需要将其置位空,
这些就是我们所使用的数组,下面就要介绍我们是如何实现的了。
根据主函数我们所需要的功能有增加,删除,展示,排序,查找,展示,保存退出,首先我们需要一个通讯录,一个通讯录需要数据(data),容量(capacity)还有大小(size),并且需要将其初始化,当容量满了之后就需要扩容,增加就只需要让数据的容量内存都变大一个相应的值,非常容易实现,删除,更改和查找都需要先找到所需要元素的名字,找到直接删除,更改即可,展示通讯录使用遍历即可,排序我们则采用qsort快排来实现,最后存储文件我们在后续博客中会讲到,这就是通讯录的全部思路。