通讯录(c语言版本)

前言


我们用手机打电话,发信息时候总是会用到通讯录那么通讯录是干什么的呢?

显而易见,用于存储一个人的信息(姓名,电话,地址)等等.我们可以进行查询,删除,增加等相关信息.

而博主写这篇博客的目的就是 把我们最近学习的C语言知识用来制作简易版本的 通讯录.


通讯录(c语言版本)

①明确项目目的


此前看过博主的博客小伙伴可能知道博主的博客风格.博主写任何一个小项目之前都是先去梳理 目的,然后去搭建逻辑结构,再去分别实现模块化.此次仍然不例外.


目的:

  • 可以存储个人信息(姓名,性别,年龄,电话,地址), 说明少不了结构体.
  • 存储人数不限. (说明需要动态内存)
  • 有提醒菜单提示相关命令.
  • 命令有(0退出,1添加信息,2删除信息,3查询信息,4修改信息,5显示所有信息,6排序信息)

②项目结构搭建

明确目的后就可以搭建逻辑结构了,我们知道人的信息要用结构体存.并且按相关命令就进入相关模块,那么

一定少不了do-whileswitch-case

#include <stdio.h>
struct information //个人信息表
{
	char name[20];//姓名
	char sex[10]; //性别
	int age;//年龄
	char tele[15];//电话
	char address[40];//地址
};

struct contact  //通讯录
{
	struct information* info; //因为不限人数量,所以开辟动态空间,存储多个信息表.
	long long size;  //真实信息人数数量
	long long capacity; //通讯录容量
};



int main()
{
    struct contact con = {};  //创建通讯录

    Initcon(&con); //初始化通讯录

    int input = 0;
    printf("请输入你想要操作的命令:\n");
    do
    {
        remind(); //菜单提示
        scanf("%d", &input);
        switch (input)
        {
        case Exit:
            save_con(&con);     //把通讯录保存到文件夹
            free_con(&con); 	//一定要记得释放动态空间.
            printf("已经成功退出系统!\n");
            break;
        case add:
            add_con(&con);
            printf("信息存储完毕!\n等待您的下一步命令:\n");
            break;
        case del:
            del_con(&con);
            printf("该人信息删除完毕!\n等待您的下一步命令:\n");
            break;
        case search:
            search_con(&con);
            printf("查找成功,等待您的下一步命令:\n");
            break;
        case modify:
            modify_con(&con);
            printf("修改完毕\n等待您的下一步命令:\n");
            break;
        case show:
            printf("所有人的详细信息如下,请查看:\n");
            show_con(&con);
            printf("展示完毕,等待您的下一步命令:\n");
            break;
        case sort:
            sort_con(&con);
            printf("排序成功\n等待您的下一步命令:\n");
            break;
        default:
            printf("你的命令不在菜单栏中,请重新选择:\n");
            break;
        }
    } while (input);

    return 0;
}

在这,逻辑结构就已经搭建好了,但是能不能再修改下呢?比如switch-case语句中的0-6,我们可不可以用更加表明意思的句子代替?

怎么弄呢?这就是 枚举 的好处


修改的内容如下:

#include <stdio.h>
struct information //个人信息表
{
	char name[20];//姓名
	char sex[10]; //性别
	int age;//年龄
	char tele[15];//电话
	char address[40];//地址
};

struct contact  //通讯录
{
	struct information* info; //因为不限人数量,所以开辟动态空间,存储多个信息表.
	long long size;  //真实信息人数数量
	long long capacity; //通讯录容量
};

enum command   //增加了枚举常量
{
	Exit,
	add,
	del,
	search,
	modify,
	show,
	sort
};


int main()
{
    struct contact con = {};  //创建通讯录
    Initcon(&con); //初始化通讯录
    int input = 0;
    printf("请输入你想要操作的命令:\n");
    do
    {
        remind(); //菜单提示
        scanf("%d",&input);
        switch(input)
        {
            case Exit:
                save_con(&con);     //把通讯录保存到文件夹
                free_con(&con); 	//一定要记得释放动态空间.
                printf("已经成功退出系统!\n");
                break;
            case add:
                add_con(&con);
                printf("信息存储完毕!\n等待您的下一步命令:\n");
                break;
            case del:
                del_con(&con);
                printf("该人信息删除完毕!\n等待您的下一步命令:\n");
                break;
            case search:
                search_con(&con);
                printf("查找成功,等待您的下一步命令:\n");
                break;
            case modify:
                modify_con(&con);
                printf("修改完毕\n等待您的下一步命令:\n");
                break;
            case show:
                printf("所有人的详细信息如下,请查看:\n");
                show_con(&con);
               	printf("展示完毕,等待您的下一步命令:\n");
                break;
            case sort:
                sort_con(&con);
                printf("排序成功\n等待您的下一步命令:\n");
                break;
            default:
                printf("你的命令不在菜单栏中,请重新选择:\n");
                break;
        }
    }while(input);
    
    return 0;
}

③各模块的具体实现

1.Initcon初始化通讯录实现

在搭建结构时候,我们只创建了通讯录,但是通讯录实际是没有任何东西的.我们需要给它赋上初值.

#include <stdlib.h>
void Initcon(struct contact* con)
{
    con->info = (struct information*)malloc(sizeof(struct information) * 4); //开辟个人信息空间
    if (con->info == NULL)
    {
        printf("系统容量不足,无法增加通讯录容量\n");
        return;
    }

    con->size = 0; //当前有0个存储信息
    con->capacity = 4; //当前通讯录剩余4个存储空间
}

2.remind菜单制作

菜单制作其实就是把相关的信息打印出来就行.

void remind()
{
    printf(
        "******************************************************************\n"
        "******************************************************************\n"
        "*********************    0   退出通讯录    ***********************\n"
        "*********************    1  存储相关信息   ***********************\n"
        "*********************    2  删除相关信息   ***********************\n"
        "*********************    3  查找某人信息   ***********************\n"
        "*********************    4  修改某人信息   ***********************\n"
        "*********************    5   显示通讯录    ***********************\n"
        "*********************    6    信息排序     ***********************\n"
        "******************************************************************\n"
        "******************************************************************\n"
    );
}

3.add_con存储信息的实现

存储信息就是把一个人的 姓名,性别,年龄,电话,地址写进去,也就是说我们需要更新结构体 struct information.

同时我们知道,一旦增加了一个信息,那么通讯录struct contact中的实际容量size就会增加1.剩余容量capacity就会减去1.

最重要的是, 在我们存储信息之前一定不能忘记检查size是否已经等于capacity了,如果等于我们就需要增容.

void add_con(struct contact* con)
{

    check_capacity(con); //这一步必不可少

    printf("请输入所需存储姓名:\n");
    scanf("%s", con->info[con->size].name);
    printf("请输入其性别:\n");
    scanf("%s", con->info[con->size].sex);
    printf("请输入其年龄:\n");
    scanf("%s", con->info[con->size].age);
    printf("请输入其电话:\n");
    scanf("%s", con->info[con->size].tele);
    printf("请输入其居住地址:\n");
    scanf("%s",con->info[con->size].address);

    con->size++; //存储人数加1
}

1.check_capacity增容函数的实现

我们在存储信息时候,需要检查是否必要扩容,check_capacity的作用就是这个.

void check_capacity(struct contact* con)
{
    if (con->size == con->capacity)
    {
        struct information* p = (struct information*)realloc(con->info, sizeof(struct information) * (con->capacity + 4));
        //每次多开辟4个容量.
        if (p == NULL)
        {
            printf("系统容量不足以支撑继续存储信息\n");
            return;
        }

        con->info = p;
        con->capacity += 4;
    }
}

4.del_con删除信息的实现

要删除一个人的信息,很简单,只要知道那个人的名字就行.但是我们用代码怎么来实现删除呢?

因为我们采用的动态内存数组.删除一个人信息后,就会空缺一个位置,而那个位置大概率是在中间.

那删除以后把后面的数据依次往前挪动吗? 可行,但是比较麻烦.

那怎么办? 采取覆盖方法,直接依次往前挪动数据,然后size减去1就行.这样最后面那个即使还存在,但是我们后面

即使增加它也会被覆盖.

void del_con(struct contact* con)
{
    printf("你想要删除的人名字是:\n");
    char na[20] = "";
    int index = 0,i = 0;
    scanf("%s", na);

    for (i = 0; i < con->size - 1; i++)  //找此人的位置在哪,如果就在最后面,就只需要size - 1
    {
        if (!strcmp(con->info[i].name, na))
        {
            index = i;
            break;
        }
    }

    if ((i == con->size) && (strcmp(con->info[con->size - 1].name, na) != 0))
    {
        printf("此人不存在!\n");
        return;
    }


    for (i = index; i < con->size-1; i++)  //依次覆盖
    {
        con->info[i] = con->info[i + 1];
    }

    con->size -= 1; //不要忘记减1哦~~

}

5.search查询模块

查询,即根据名字去查询就行.需要的代码和del_con中部分相似.

void search_con(struct contact* con)
{
    printf("你想要查找的人的姓名是:\n");
    char na[20] = "";
    scanf("%s",na);
    int i = 0;
    for(i = 0;i<con->size;i++)
    {
        if (!strcmp(con->info[i].name, na))
        {
            printf("信息如下:\n"
                "%4s\t%4s\t%4s\t%4s\t%4s\n ",
                "姓名","性别","年龄","电话","地址");

            printf("%s\t%s\t%s\t%s\t%s\n",
                con->info[i].name,con->info[i].sex,con->info[i].age,con->info[i].tele, con->info[i].address);
            
            break;
        }
    }

    if (i == con->size)
    {
        printf("此人不存在\n");
    }
}

6.modify_con信息修改实现

信息修改,顾名思义就是去修改某一项信息.直接搜索名字,然后修改相关信息.

void modify_con(struct contact* con)
{
    printf("你想要修改谁的信息:\n");
    char na[20] = "";
    scanf("%s", na);
    for (int i = 0; i < con->size; i++)
    {
        if (!strcmp(con->info[i].name, na))
        {
            printf("名字需要修改为: ");
            scanf("%s",con->info[i].name);
            printf("\n性别修改为:");
            scanf("%s", con->info[i].sex);
            printf("\n年龄修改为:");
            scanf("%s", con->info[i].age);
            printf("\n电话修改为:");
            scanf("%s", con->info[i].tele);
            printf("\n地址修改为:");
            scanf("%s", con->info[i].address);
            printf("\n");
            break;
        }
    }
}

7.show 展示所有人信息

void show_con(struct contact* con)
{
    printf("信息如下:\n"
        "%4s\t%4s\t%4s\t%4s\t%4s\n",
        "姓名", "性别", "年龄", "电话", "地址");

    for (int i = 0; i < con->size; i++)
    {
        printf("%s\t%s\t%s\t%s\t%s\n",
            con->info[i].name, con->info[i].sex, con->info[i].age, con->info[i].tele, con->info[i].address);
    }
}

8.sort_con信息排序

这里留下一个小思考,不准调研排序库函数,大家可以怎么排序?

博主用的选择排序:

void swap(struct information* a, struct information* b)
{
    struct information p = {0};
    p = *a;
    *a = *b;
    *b = p;
}
void sort_con(struct contact* con)
{
    printf("你想要按照什么排序:\n"
        "姓名 性别 年龄 电话 地址?\n:");
    char na[20] = "";
    scanf("%s", na);
    int i = 0, j = 0;
    for (i = 0; i < con->size - 1; i++)
    {
        int dex = i;

        if (!strcmp(na, "姓名"))
        {
            for (j = i + 1; j < con->size; j++)
            {
                if (strcmp(con->info[dex].name, con->info[j].name) > 0)
                {
                    dex = j;
                }
            }
            swap(&con->info[dex], &con->info[i]);
        }
        else if (!strcmp(na, "性别"))
        {
            for (j = i + 1; j < con->size; j++)
            {
                if (strcmp(con->info[dex].sex, con->info[j].sex) > 0)
                {
                    dex = j;
                }
            }
            swap(&con->info[dex], &con->info[i]);
        }
        else if (!strcmp(na, "年龄"))
        {
            for (j = i + 1; j < con->size; j++)
            {
                if (strcmp(con->info[dex].age, con->info[j].age) > 0)
                {
                    dex = j;
                }
            }
            swap(&con->info[dex], &con->info[i]);
        }
        else if (!strcmp(na,"电话"))
        {
            for (j = i + 1; j < con->size; j++)
            {
                if (strcmp(con->info[dex].tele, con->info[j].tele) > 0)
                {
                    dex = j;
                }
            }
            swap(&con->info[dex], &con->info[i]);
        }
        else if (!strcmp(na, "地址"))
        {
            for (j = i + 1; j < con->size; j++)
            {
                if (strcmp(con->info[dex].address, con->info[j].address) > 0)
                {
                    dex = j;
                }
            }
            swap(&con->info[dex], &con->info[i]);
        }
    }
}

9.save_con保存通讯录信息.

void save_con(struct contact* con)
{
    FILE* write = fopen("pp.txt","wb");
    if (!write)
    {
        printf("系统容量不足,无法保存\n");
        return;
    }

    fwrite(con->info,sizeof(struct information),con->size,write);
    fclose(write);
    write = NULL;
}

10.free_con释放内存

void free_con(struct contact* con)
{
    free(con->info);
    con->info = NULL;
}

告终

到此,整个通讯录就写完毕了.

???

真的完毕了吗???大家仔细想想,还有哪一步出问题了.

没错那就是 我们虽然保存了文件,但是下次运行程序时候,我们上次的保存内容读取出来了吗?并没有…

所以我们在初始化出了问题,初始化的时候忘记 读取文件内容

修改:

void save_con(struct contact* con)
{
    FILE* write = fopen("pp.txt","wb");
    if (!write)
    {
        printf("系统容量不足,无法保存\n");
        return;
    }

    fwrite(con->info,sizeof(struct information),con->size,write);
    fclose(write);
    write = NULL;
}


void Initcon(struct contact* con)
{
    con->info = (struct information*)malloc(sizeof(struct information) * 4);
    if (con->info == NULL)
    {
        printf("系统容量不足,无法增加通讯录容量\n");
        return;
    }
    con->size = 0; //当前有0个存储信息
    con->capacity = 4; //当前通讯录剩余4个存储空间

    read_con(con);
}

完结

完整代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct information //个人信息表
{
    char name[20];//姓名
    char sex[10]; //性别
    char age[10];//年龄
    char tele[15];//电话
    char address[40];//地址
};

struct contact  //通讯录
{
    struct information* info; //因为不限人数量,所以开辟动态空间,存储多个信息表.
    long long size;  //真实信息人数数量
    long long capacity; //通讯录剩余容量
};

enum command   //增加了枚举常量
{
    Exit,
    add,
    del,
    search,
    modify,
    show,
    sort
};

void save_con(struct contact* con)
{
    FILE* write = fopen("pp.txt","wb");
    if (!write)
    {
        printf("系统容量不足,无法保存\n");
        return;
    }

    fwrite(con->info,sizeof(struct information),con->size,write);
    fclose(write);
    write = NULL;
}
void free_con(struct contact* con)
{
    free(con->info);
    con->info = NULL;
}
void check_capacity(struct contact* con)
{
    if (con->size == con->capacity)
    {
        struct information* p = (struct information*)realloc(con->info, sizeof(struct information) * (con->capacity + 4));
        //每次多开辟4个容量.
        if (p == NULL)
        {
            printf("系统容量不足以支撑继续存储信息\n");
            return;
        }

        con->info = p;
        con->capacity += 4;
    }
}

void read_con(struct contact* con)
{
    FILE* read = fopen("pp.txt","rb");
    if (read == NULL)
    {
        return;
    }
    int i = 0;
    while (fread(&(con->info[i++]), sizeof(struct information), 1, read))
    {
        check_capacity(con);  //一定不要忘记检查增容.
        con->size++;
    }
}

void Initcon(struct contact* con)
{
    con->info = (struct information*)malloc(sizeof(struct information) * 4);
    if (con->info == NULL)
    {
        printf("系统容量不足,无法增加通讯录容量\n");
        return;
    }
    con->size = 0; //当前有0个存储信息
    con->capacity = 4; //当前通讯录剩余4个存储空间

    read_con(con);
}

void remind()
{
    printf(
        "******************************************************************\n"
        "******************************************************************\n"
        "*********************    0   退出通讯录    ***********************\n"
        "*********************    1  存储相关信息   ***********************\n"
        "*********************    2  删除相关信息   ***********************\n"
        "*********************    3  查找某人信息   ***********************\n"
        "*********************    4  修改某人信息   ***********************\n"
        "*********************    5   显示通讯录    ***********************\n"
        "*********************    6    信息排序     ***********************\n"
        "******************************************************************\n"
        "******************************************************************\n"
    );
}


void add_con(struct contact* con)
{

    check_capacity(con); //这一步必不可少

    printf("请输入所需存储姓名:\n");
    scanf("%s", con->info[con->size].name);
    printf("请输入其性别:\n");
    scanf("%s", con->info[con->size].sex);
    printf("请输入其年龄:\n");
    scanf("%s", con->info[con->size].age);
    printf("请输入其电话:\n");
    scanf("%s", con->info[con->size].tele);
    printf("请输入其居住地址:\n");
    scanf("%s",con->info[con->size].address);

    con->size++; //存储人数加1
}

void del_con(struct contact* con)
{
    printf("你想要删除的人名字是:\n");
    char na[20] = "";
    int index = 0,i = 0;
    scanf("%s", na);

    for (i = 0; i < con->size - 1; i++)  //找此人的位置在哪,如果就在最后面,就只需要size - 1
    {
        if (!strcmp(con->info[i].name, na))
        {
            index = i;
            break;
        }
    }

    if ((i == con->size) && (strcmp(con->info[con->size - 1].name, na) != 0))
    {
        printf("此人不存在!\n");
        return;
    }


    for (i = index; i < con->size-1; i++)  //依次覆盖
    {
        con->info[i] = con->info[i + 1];
    }

    con->size -= 1; //不要忘记减1哦~~

}

void search_con(struct contact* con)
{
    printf("你想要查找的人的姓名是:\n");
    char na[20] = "";
    scanf("%s",na);
    int i = 0;
    for(i = 0;i<con->size;i++)
    {
        if (!strcmp(con->info[i].name, na))
        {
            printf("信息如下:\n"
                "%4s\t%4s\t%4s\t%4s\t%4s\n ",
                "姓名","性别","年龄","电话","地址");

            printf("%s\t%s\t%s\t%s\t%s\n",
                con->info[i].name,con->info[i].sex,con->info[i].age,con->info[i].tele, con->info[i].address);
            
            break;
        }
    }

    if (i == con->size)
    {
        printf("此人不存在\n");
    }
}

void modify_con(struct contact* con)
{
    printf("你想要修改谁的信息:\n");
    char na[20] = "";
    scanf("%s", na);
    for (int i = 0; i < con->size; i++)
    {
        if (!strcmp(con->info[i].name, na))
        {
            printf("名字需要修改为: ");
            scanf("%s",con->info[i].name);
            printf("\n性别修改为:");
            scanf("%s", con->info[i].sex);
            printf("\n年龄修改为:");
            scanf("%s", con->info[i].age);
            printf("\n电话修改为:");
            scanf("%s", con->info[i].tele);
            printf("\n地址修改为:");
            scanf("%s", con->info[i].address);
            printf("\n");
            break;
        }
    }
}

void show_con(struct contact* con)
{
    printf("信息如下:\n"
        "%4s\t%4s\t%4s\t%4s\t%4s\n",
        "姓名", "性别", "年龄", "电话", "地址");

    for (int i = 0; i < con->size; i++)
    {

        printf("%s\t%s\t%s\t%s\t%s\n",
            con->info[i].name, con->info[i].sex, con->info[i].age, con->info[i].tele, con->info[i].address);
    }
}

void swap(struct information* a, struct information* b)
{
    struct information p = {0};
    p = *a;
    *a = *b;
    *b = p;
}

void sort_con(struct contact* con)
{
    printf("你想要按照什么排序:\n"
        "姓名 性别 年龄 电话 地址?\n:");
    char na[20] = "";
    scanf("%s", na);
    int i = 0, j = 0;
    for (i = 0; i < con->size - 1; i++)
    {
        int dex = i;

        if (!strcmp(na, "姓名"))
        {
            for (j = i + 1; j < con->size; j++)
            {
                if (strcmp(con->info[dex].name, con->info[j].name) > 0)
                {
                    dex = j;
                }
            }
            swap(&con->info[dex], &con->info[i]);
        }
        else if (!strcmp(na, "性别"))
        {
            for (j = i + 1; j < con->size; j++)
            {
                if (strcmp(con->info[dex].sex, con->info[j].sex) > 0)
                {
                    dex = j;
                }
            }
            swap(&con->info[dex], &con->info[i]);
        }
        else if (!strcmp(na, "年龄"))
        {
            for (j = i + 1; j < con->size; j++)
            {
                if (strcmp(con->info[dex].age, con->info[j].age) > 0)
                {
                    dex = j;
                }
            }
            swap(&con->info[dex], &con->info[i]);
        }
        else if (!strcmp(na,"电话"))
        {
            for (j = i + 1; j < con->size; j++)
            {
                if (strcmp(con->info[dex].tele, con->info[j].tele) > 0)
                {
                    dex = j;
                }
            }
            swap(&con->info[dex], &con->info[i]);
        }
        else if (!strcmp(na, "地址"))
        {
            for (j = i + 1; j < con->size; j++)
            {
                if (strcmp(con->info[dex].address, con->info[j].address) > 0)
                {
                    dex = j;
                }
            }
            swap(&con->info[dex], &con->info[i]);
        }
    }
}
int main()
{
    struct contact con = {0};  //创建通讯录

    Initcon(&con); //初始化通讯录

    int input = 0;
    printf("请输入你想要操作的命令:\n");
    do
    {
        remind(); //菜单提示

        scanf("%d", &input);

        switch (input)
        {
        case Exit:
            save_con(&con);     //把通讯录保存到文件夹
            free_con(&con); 	//一定要记得释放动态空间.
            printf("已经成功退出系统!\n");
            break;
        case add:
            add_con(&con);
            printf("信息存储完毕!\n等待您的下一步命令:\n");
            break;
        case del:
            del_con(&con);
            printf("该人信息删除完毕!\n等待您的下一步命令:\n");
            break;
        case search:
            printf("此人信息如下:\n");
            search_con(&con);
            printf("查找成功,等待您的下一步命令:\n");
            break;
        case modify:
            modify_con(&con);
            printf("修改完毕\n等待您的下一步命令:\n");
            break;
        case show:
            printf("所存储人的详细信息如下,请查看:\n");
            show_con(&con);
            printf("展示完毕,等待您的下一步命令:\n");
            break;
        case sort:
            sort_con(&con);
            printf("排序成功\n等待您的下一步命令:\n");
            break;
        default:
            printf("你的命令不在菜单栏中,请重新选择:\n");
            break;
        }
    } while (input);

    return 0;
}
上一篇:C++stack与queue模拟实现


下一篇:jQuery jQuery鼠标混轮滚动事件