本篇文章主要是实现一个简易的通讯录:
功能如下:
- 添加用户
- 修改用户
- 删除用户
- 查找用户(可重名)
- 按名字或年龄排序
- 显示用户
- 保存通讯录
- 日志追加
有如下知识点:
- 动态数组
- 结构体
- 枚举
- 自定义标识符和宏
- 文件打开与存储
- 函数
- 指针
- 循环
- 排序
简述特点:
- 将人员信息放在一个PeoInf的结构体中,再创建一个结构体List,用于存放peoinf这个结构体的指针,和容量与目前通讯录人员数量。
- 再用realloc动态开辟以结构体peoinf为大小的内存,用于实现动态内存开辟。
- 程序运行后,初始化这段空间,并查询是否有"contact.txt"的文件存在,如果存在,则读取文件里的内容,并放到peoinf的结构体"数组"中,并实时监控是否需要扩容。如果不存在就创建文件。
- 随后就可以添加、修改、查找、删除用户,每一次增删改查都会被记录到一个"contact_log.txt"的文件里,这里使用了时间戳。
- 用qsort进行名字或年龄进行排序
- 程序会知道本次是否进行修改,如果修改后就退出会提示是否需要保存,当然也可以自己手动保存。
- 程序以"rb"和"wb"进行文件的读写。
- 程序实现了重名查找,在有重名的情况下会进行选择。
- (代码可直接运行,复制到编译器vs2019即可)
代码部分
contact.h
cpp
#pragma once
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <time.h>
#include <sys/stat.h>
#define MAX_10 10
#define MAX_20 20
//#define LOG_PRINT(x) fprintf(pf, "In %s %s ,user %s name calling %s\n",__DATE__,__TIME__,(x),(list->pl+num)->name)
typedef struct PeoInf
{
char name[MAX_20];
int age;
char sex[5];
char tel[12];
char addr[30];
}PeoInf;
//定义通讯录结构体,嵌套PeoInf
typedef struct List
{
//动态内存分配
PeoInf* pl;
int count;
int capacity;//容量
}List;
//定义一个枚举变量,用于存储菜单所有选择
enum select_all
{
EXIT,//0
ADD,
DEL,
SELECT,
MODIFY,
SORT,
SHOW,
SAVE
};
//菜单函数
void menu();
//定义初始化list函数
void initialise_list(List* list);
//定义添加信息函数
void add_peoinf(List* list);
//定义显示函数
void show_list(List* list);
//定义删除函数
void del_peoinf(List* list);
//定义通过找名字查找人的函数(已实现重名查找)
int find_byname(const List* list);
//定义查找人
void sele_peoinf(const List* list);
//定义修改人信息函数
void modify_peoinf(List* list);
//定义删除和修改已找到下标的信息函数
void del_havefond(List* list, int position);
void modify_havefond(List* list, int position);
//定义排序函数
void sort_peoinf(List* list);
//定义文件保存函数
void file_save(List* list);
//定义扩容函数
void expand_list(List* list);
actualize.c
cpp
#include "contact.h"
//实现菜单函数
void menu(){
printf("----------------------------------------\n");
printf("--------1. add 2. del--------------\n");
printf("--------3. select 4. modify-----------\n");
printf("--------5. sort 6. show-------------\n");
printf("--------------7. save-------------------\n");
printf("--------------0. exit-------------------\n");
printf("----------------------------------------\n");
}
//实现初始化list函数
void initialise_list(List* list){
PeoInf* ptr = (PeoInf*)calloc(3, sizeof(PeoInf));//默认开辟三个人的存储空间
if (ptr == NULL) {
printf("%s", strerror(errno));
return ;
}
list->pl = ptr;
list->count = 0;
list->capacity = 3;
FILE* pf = NULL;
struct stat buffer;//判断文件是否存在
if (stat("contact.txt", &buffer) != 0) {//不存在就创建文件
pf = fopen("contact.txt", "wb");
fclose(pf);
pf = NULL;
return;
}
pf = fopen("contact.txt", "rb");
if (pf != NULL) {
for (int i = 0; fread(list->pl + i, sizeof(PeoInf), 1, pf) != 0; i++) {
if (list->count == list->capacity - 1) {
expand_list(list);
}
list->count++;
}
fclose(pf);
}
pf = NULL;
}
//扩容函数
void expand_list(List* list) {
PeoInf* ptr =(PeoInf*) realloc(list->pl, (list->capacity + 2)*sizeof(PeoInf));//每次增加两个
if (ptr == NULL) {
printf("%s", strerror(errno));
return;
}
list->pl = ptr;
list->capacity += 2;
}
//实现添加日志功能
/*
* return 0 失败
* return 1 成功
*/
int add_log(List* list,char* moving,int num) {
//打开文件
FILE* pf=NULL;
//判断写入模式是否要追加
if (list->count == 0) {
pf = fopen("contact_log.txt", "w");
}
else {
pf = fopen("contact_log.txt", "a");
}
//如果打开失败,报错
if (pf == NULL) {
perror("fopen:");
return 0;
}
//获取时间戳
time_t rawtime;
struct tm* timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
fprintf(pf, "In %s \tuser %s name calling %s.\n", asctime(timeinfo), moving, (list->pl + num)->name);
fclose(pf);
pf = NULL;
return 1;
}
//实现添加信息功能
void add_peoinf(List* list) {
assert(list);//断言
//判断是否需要扩容
if (list->count == list->capacity) {
expand_list(list);//内部函数,不必去头文件里定义
printf("Automatic capacity expansion is successful,\n and the current address book capacity is %d\n", list->capacity);
}
printf("Please enter the name\n->");
scanf("%s", (list->pl+list->count)->name);
printf("Please enter age\n->");
scanf("%d", &(list->pl + list->count)->age);
printf("Please enter sex\n->");
scanf("%s", (list->pl + list->count)->sex);
printf("Please enter the telephone\n->");
scanf("%s", (list->pl + list->count)->tel);
printf("Please enter the address\n->");
scanf("%s", (list->pl + list->count)->addr);
//添加日志log功能
if (!add_log(list,"add",list->count)) {
printf("log fail,please find excause.\n");
}
list->count++;
printf("succeed!\n");
}
//实现显示函数
void show_list(List* list) {
assert(list);
printf("name\tage\tsex\ttelephone\taddr\n");
for (int i = 0; i < (list->count); i++) {
printf("%s\t%d\t%s\t%s\t\t%s\n", (list->pl + i)->name,
(list->pl + i)->age, (list->pl + i)->sex, (list->pl + i)->tel, (list->pl + i)->addr);
}
}
//实现通过寻找名字,找到这个人
//重名默认存放数组为10,如需变大可改为动态扩容实现
int find_byname(const List* list) {
char s_name[MAX_20] = { 0 };
int count = 0;
int find_result[MAX_10] = { 0 };
printf("Please enter the name that you want \n->");
scanf("%s", s_name);
for (int i = 0; i < list->count; i++) {
if (strcmp((list->pl + i)->name, s_name)==0) {
//找到了
if (count == 0) {
printf("Find the information, please confirm\n");
printf("number\tname\tage\tsex\ttelephone\taddr\n");
}
printf("%d\t%s\t%d\t%s\t%s\t\t%s\n", count+1,(list->pl + i)->name,
(list->pl + i)->age, (list->pl + i)->sex, (list->pl + i)->tel, (list->pl + i)->addr);
find_result[count] = i;//将找到的坐标存入数组中
count++;//判断是否有重复
}
}
if (count == 0) {
//找不到
printf("Check no such person, please confirm after the input!\n");
return -1;
}
else if (count == 1) {
return find_result[0];
}
else {//两个以上
int select_num = 0;
while (1) {
printf("Please select the object serial number that you want to operate on\n->");
scanf("%d", &select_num);
if (select_num >= 1 && select_num <= count) {//输入正确序号,方可返回
return find_result[select_num - 1];
}
else {
printf("error,please reenter\n");
}
}
}
}
//实现删除函数
void del_peoinf(List* list) {
assert(list);
int del_num = find_byname(list);
if (del_num < 0) return;//查找失败
for (int i = 0; i < list->count - del_num - 1; i++) {
*(list->pl + del_num + i) = *(list->pl + del_num + 1 + i);
}
list->count--;
printf("delet successfully\n");
if (!add_log(list, "delet", del_num)) {
printf("log fail,please find excause.\n");
}
}
void del_havefond(List* list,int position) {
assert(list);
for (int i = 0; i < list->count - position - 1; i++) {
*(list->pl + position + i) = *(list->pl + position + 1 + i);
}
list->count--;
printf("delet successfully\n");
if (!add_log(list, "delet", position)) {
printf("log fail,please find excause.\n");
}
}
//实现查找信息功能
void sele_peoinf(const List* list) {
assert(list);
int find_num = find_byname(list);
if (find_num < 0) return;//查找失败
printf("The information is as follows\n");
printf("name\tage\tsex\ttelephone\taddr\n");
printf("%s\t%d\t%s\t%s\t\t%s\n", (list->pl + find_num)->name,
(list->pl + find_num)->age, (list->pl + find_num)->sex, (list->pl + find_num)->tel, (list->pl + find_num)->addr);
int input_find = 0;
do {
printf("--------------------------------\n");
printf("--------------------------------\n");
printf("-----1. del-------2. modif------\n");
printf("------------0. exit-------------\n");
printf("--------------------------------\n");
printf("--------------------------------\n");
printf("please enter what you want\n->");
scanf("%d", &input_find);
if (input_find == 1) {
del_havefond(list, find_num);
return;
}
else if (input_find == 2) {
modify_havefond(list, find_num);
return;
}
else if (input_find != 0) {
printf("Input is wrong, please reagain\n");
}
} while (input_find);
}
void modify_havefond(List* list,int position) {
assert(list);
printf("Please enter the new name\n->");
scanf("%s", (list->pl + position)->name);
printf("Please enter new age\n->");
scanf("%d", &(list->pl + position)->age);
printf("Please enter new sex\n->");
scanf("%s", (list->pl + position)->sex);
printf("Please enter the new telephone\n->");
scanf("%s", (list->pl + position)->tel);
printf("Please enter the new address\n->");
scanf("%s", (list->pl + position)->addr);
printf("Modified successfully\n");
if (!add_log(list, "modify", position)) {
printf("log fail,please find excause.\n");
}
}
//实现修改信息
void modify_peoinf(List* list) {
assert(list);
int mod_num = find_byname(list);
if (mod_num < 0) return;//查找失败
printf("Please enter the new name\n->");
scanf("%s", (list->pl + mod_num)->name);
printf("Please enter new age\n->");
scanf("%d", &(list->pl + mod_num)->age);
printf("Please enter new sex\n->");
scanf("%s", (list->pl + mod_num)->sex);
printf("Please enter the new telephone\n->");
scanf("%s", (list->pl + mod_num)->tel);
printf("Please enter the new address\n->");
scanf("%s", (list->pl + mod_num)->addr);
printf("Modified successfully\n");
if (!add_log(list, "modify",mod_num)) {
printf("log fail,please find excause.\n");
}
}
//qsort的比较函数
int compare_name(const void* e1,const void* e2) {
return strcmp(((PeoInf*)e1)->name, ((PeoInf*)e2)->name);
}
int compare_age(const void* e1, const void* e2) {
return ((PeoInf*)e1)->age - ((PeoInf*)e2)->age;
}
//实现排序函数
void sort_peoinf(List* list) {
int sort_input = 0;
do {
printf("--------------------------------\n");
printf("--------------------------------\n");
printf("-----1. name-------2. age------\n");
printf("------------0. exit-------------\n");
printf("--------------------------------\n");
printf("--------------------------------\n");
printf("please enter you want sort by\n->");
scanf("%d", &sort_input);
if (sort_input == 1) {
qsort(list->pl, list->count, sizeof(PeoInf), compare_name);
printf("sort by name successfully\n");
return;
}
else if (sort_input == 2) {
qsort(list->pl, list->count, sizeof(PeoInf), compare_age);
printf("sort by age successfully\n");
return;
}
} while (sort_input);
}
void file_save(List *list) {
FILE* pf = fopen("contact.txt", "wb");//二进制写入
if (pf == NULL) {
perror("fopen:");
return;
}
//写数据
for (int i = 0; i < list->count; i++) {
fwrite(list->pl+i, sizeof(PeoInf), 1, pf);
}
fclose(pf);
pf = NULL;
}
test.c
cpp
#include "contact.h"
int main()
{
int input = 0;
List list;
initialise_list(&list);//动态内存开辟,记得用完销毁
int modify_num = 0;//修改数量记录
do{
menu();
printf("Please choose!\n->");
scanf("%d", &input);
switch (input)
{
case ADD:
{
add_peoinf(&list);
modify_num++;
}break;
case DEL:
{
del_peoinf(&list);
modify_num++;
}break;
case SELECT:
{
sele_peoinf(&list);
}break;
case MODIFY:
{
modify_peoinf(&list);
modify_num++;
}break;
case SORT:
{
sort_peoinf(&list);
}break;
case SHOW:
{
show_list(&list);
}break;
case SAVE:
{
file_save(&list);
printf("save in file sucessfully\n");
modify_num = 0;
}break;
case EXIT:
{
if (modify_num != 0) {
int save_select = 0;
printf("=========1.save 2.no=============\n");
printf("The modified data is not saved, whether it needs to be saved\n->");
scanf("%d", &save_select);
if (save_select == 1) {
file_save(&list);
printf("save in file sucessfully\n");
}
}
printf("Ok,have a nice day! Bye~");
}break;
default:
printf("Input is wrong,please reagain!\n");
break;
}
} while (input);
//销毁动态内存
free(list.pl);
list.pl = NULL;
}
希望对大家有帮助!