可存储版通讯录
Suzhou 15 1

test.c

#define _CRT_SECURE_NO_WARNINGS
#include "contact.h"

void menu()
{
    printf("****************-***************\n");
    printf("****1.add          2.del    ****\n");
    printf("****3.search       4.modify ****\n");
    printf("****5.show         7.save   ****\n");
    printf("****0.exit                  ****\n");
    printf("********************************\n");
}

int main()
{
    int input = 1;
    struct Contact con;  //通讯录con中包含data指针、当前通讯录的容量、当前通讯录中的联系人个数size
    InitContact(&con);  //初始化通讯录,需要把con和size置为0,传址调用
    do
    {
        menu();
        printf("请选择->");
        scanf("%d", &input);
        switch (input)
        {
            //预编译时可以将ADD等改成0...
            //预编译时可以将ADD等改成0...
        case ADD:
            AddContact(&con);  //元素增加后size随之改变,传址调用
            break;
        case DEL:
            DelContact(&con);
            break;
        case SEARCH:
            SearContact(&con);
            break;
        case MODIFY:
            ModContact(&con);
            break;
        case SHOW:
            ShowContact(&con);
            break;
        case SAVE:
            SaveContact(&con);
            break;
        case EXIT:
            //销毁通讯录,即释放malloc开辟的内存空间
            SaveContact(&con);
            DestContact(&con);
            printf("退出通讯录\n");
            break;
        default:
            printf("选择错误\n");
            break;
        }
    } while (input);
    return 0;
}

contact.c

#define _CRT_SECURE_NO_WARNINGS

#include "contact.h"

void InitContact(struct Contact* ps)
{
    //通讯录默认开辟3个联系人的空间
    ps->data = (struct PeoInfo*)malloc(DEFAULT_SZ * sizeof(struct PeoInfo));
    if (ps->data == NULL)
    {
        return;  //开辟不成功不执行操作返回 
    }
    ps->size = 0;
    ps->capacity = DEFAULT_SZ;
    //在每次执行通讯录程序后,初始化开辟好空间后,将通讯录文件中保存的通讯录信息加载到通讯录中
    LoadContact(ps);  //加载通讯录
}
void CheckCapacity(struct Contact* ps);
void LoadContact(struct Contact* ps)
{
    struct PeoInfo tmp = { 0 };
    FILE* LoadContactFile = fopen("contact.dat", "rb");
    if (LoadContactFile == NULL)
    {
        printf("LoadContact::%s\n", strerror(errno));
    }
    //读取文件放在通讯录中
    while (fread(&(tmp), sizeof(struct PeoInfo), 1, LoadContactFile))
    {
        //在fread每次读取一个放在通讯录中的循环操作中,fread的返回值size_t,fread返回的是实际读到的所有元素的个数
        //count设置为每次读取一个,当fread函数返回值为1,则进入循环,检查容量后写入到通讯录中
        CheckCapacity(ps);
        ps->data[ps->size] = tmp;
        ps->size++;
    }
    fclose(LoadContactFile);
    LoadContactFile = NULL;
}

//检查通讯录是否已被填满,已满则扩容,未满则不操作
void CheckCapacity(struct Contact* ps)
{
    if (ps->size == ps->capacity)
    {
        //扩容
        struct PeoInfo* ptr = realloc(ps->data, (ps->capacity + 2) * sizeof(struct PeoInfo));
        if (ptr != NULL)
        {
            ps->data = ptr;
            ps->capacity += 2;
            printf("扩容成功\n");
        }
        else
        {
            printf("扩容失败\n");
        }
    }
}

void AddContact(struct Contact* ps)
{
    //先检查数组中容量是否被填满
    CheckCapacity(ps);
    //增加联系人
    printf("请输入姓名\n");
    scanf("%s", &ps->data[ps->size].name);
    printf("请输入年龄\n");
    scanf("%d", &ps->data[ps->size].age);
    printf("请输入性别\n");
    scanf("%s", &ps->data[ps->size].sex);
    printf("请输入电话\n");
    scanf("%s", &ps->data[ps->size].tel);
    printf("请输入地址\n");
    scanf("%s", &ps->data[ps->size].addr);
    ps->size++;  //数组中成员数量+1
    printf("添加成功\n");

}

void ShowContact(const struct Contact* ps)
{
    if (ps->size == 0)
    {
        printf("通讯录为空\n");
    }
    else
    {
        int i = 0;
        printf("%-10s\t%-3s\t%-5s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");
        for (i = 0; i < ps->size; i++)
        {
            printf("%-10s\t%-3s\t%-5d\t%-12s\t%-20s\n",
                ps->data[i].name,
                ps->data[i].sex,
                ps->data[i].age,
                ps->data[i].tel,
                ps->data[i].addr);
        }
    }
}

//删除、查找、改变都需要查找代码,代码冗余,单独写成函数调用
int FindName(const struct Contact* ps, char name[MAX_NAME])
{
    //跳出for循环的两种情况:
    //1.break跳出,说明数组中找到了要删除的数据
    //2.for循环跳出,说明遍历完成后没有找到查找的数据
    int i = 0;
    for (i = 0; i < ps->size; i++)
    {
        if (strcmp(ps->data[i].name, name) == 0)
        {
            return i;  //找到了返回元素下标
        }
    }
    return -1;  //找不到返回-1
}

void DelContact(struct Contact* ps)
{
    char name[MAX_NAME];
    printf("请输入要删除的人的名字:->");
    scanf("%s", &name);
    //1.查找要删除的信息在数组中的位置(遍历)
    int pos = FindName(ps, name);  //返回位置或-1
    if (pos == -1)  //for循环跳出
    {
        printf("要删除的人不存在\n");
    }
    else  //break跳出,此时的位置是data[i]
    {
        //2.删除信息(保证顺序不变,后面的信息逐个覆盖前面的)
        int j = 0;
        for (j = pos; j < ps->size - 1; j++)
        {
            ps->data[j] = ps->data[j + 1];
        }
        ps->size--;
        printf("删除成功\n");
    }

}

void SearContact(const struct Contact* ps)
{
    char name[MAX_NAME];
    printf("请输入要查找的联系人的名字\n");
    scanf("%s", &name);
    int pos = FindName(ps, name);  //返回位置或-1
    if (pos == -1)
    {
        printf("要查找的人不存在\n");
    }
    else  //找到后打印元素的每一个字段
    {
        printf("%-10s\t%-3s\t%-5s\t%-12s\t%-20s\n",
            "姓名", "性别", "年龄", "电话", "地址");
        printf("%-10s\t%-3s\t%-5d\t%-12s\t%-20s\n",
            ps->data[pos].name,
            ps->data[pos].sex,
            ps->data[pos].age,
            ps->data[pos].tel,
            ps->data[pos].addr);
    }
}

void ModContact(struct Contact* ps)
{
    char name[MAX_NAME];
    printf("请输入要修改的联系人的名字\n");
    scanf("%s", &name);
    int pos = FindName(ps, name);  //返回位置或-1
    if (pos == -1)
    {
        printf("要修改的信息不存在\n");
    }
    else  //找到后打印元素的每一个字段
    {
        printf("请输入姓名\n");
        scanf("%s", &ps->data[pos].name);
        printf("请输入年龄\n");
        scanf("%d", &ps->data[pos].age);
        printf("请输入性别\n");
        scanf("%s", &ps->data[pos].sex);
        printf("请输入电话\n");
        scanf("%s", &ps->data[pos].tel);
        printf("请输入地址\n");
        scanf("%s", &ps->data[pos].addr);
        printf("修改完成\n");
    }
}

void SaveContact(const struct Contact* ps)
{
    FILE* WriteContactFile = fopen("contact.dat", "wb");
    if (WriteContactFile == NULL)
    {
        printf("WriteContactFile::%s\n", strerror(errno));
        return;
    }
    //将通讯录中的数据写入到WriteContactFile
    int i = 0;
    for (i = 0; i < ps->size; i++)
    {
        //通讯录中的数据存放在ps中的date数组内
        fwrite(&(ps->data[i]), sizeof(struct PeoInfo), 1, WriteContactFile);
    }
    fclose(WriteContactFile);
    WriteContactFile = NULL;
}

void DestContact(Contact* ps)
{
    free(ps->data);  //free释放malloc、realloc开辟改变过的内存空间
    ps->data = NULL;
}

contact.h

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

#define MAX_NAME 10
#define MAX_SEX 3
#define MAX_TEL 12
#define MAX_ADDR 20
#define DEFAULT_SZ 3

//使用枚举增加代码可读性
enum Option
{
    EXIT,  //0
    ADD,  //1
    DEL,  //2
    SEARCH,  //3
    MODIFY,  //4
    SHOW,  //5
    SORT,  //6
    SAVE  //7
};

struct PeoInfo  //描述一个人的信息
{
    char name[MAX_NAME];
    int age;
    char sex[MAX_SEX];
    char tel[MAX_TEL];
    char addr[MAX_ADDR];
};


typedef struct Contact  //描述通讯录
{
    struct PeoInfo* data;  //指向一块内存空间
    int size;  //记录当前已有的元素个数
    int capacity;  //记录当前通讯录容量
}Contact;  //struct Contact重命名为Contact


//声明函数:
void InitContact(struct Contact* ps);  //初始化函数,参数为struct Contact的指针    
void AddContact(struct Contact* ps);   //数组内增加元素
void ShowContact(const struct Contact* ps);  //打印数组
void DelContact(struct Contact* ps);  //删除指定信息
void SearContact(const struct Contact* ps);  //查找指定信息
void ModContact(struct Contact* ps);  //更改指定信息
void DestContact(struct Contact* ps);  //销毁通讯录
void SaveContact(const struct Contact* ps);  //保存通讯录中的信息
void LoadContact(struct Contact* ps);  //加载通讯录
评论区

索引目录