ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

简易通讯录的实现

2021-09-30 21:02:47  阅读:146  来源: 互联网

标签:struct pc 实现 联系人 简易 通讯录 printf data name


 要求

实现一个通讯录

可容纳一定人数的相关信息,如名字,性别,电话号码,地址等,并可在程序退出前将添加的信息写入到指定文件,当然也可在下一次运行程序时加载上一次保存的文件

具有以下功能:

1.增加联系人

2.删除联系人

3.查找联系人

4.修改联系人

5.显示当前联系人

6.以姓氏排序

 思路

联系人信息存储----结构体变量

各个功能----定义函数

加载和写入文件----文件指针

tips:若要储存1000个人的信息,应动态开辟内存,提高内存利用率.比如,默认开辟3个联系人信息所需空间,后面添加人数自动增加容量就行.内存随开随用,用完就free,是个好习惯

三个文件

| contact.c | 各个功能函数定义 |
| :-------- | ---------------- |
| contact.h | 各个功能函数声明 |
| test.c    | 通讯录的测试     |

用结构体变量描述联系人信息

```c
//联系人信息
struct PeoInfo
{
    char name[NAME_MAX];//名字
    char sex[SEX_MAX];//性别
    char tele[TELE_MAX];//电话号码
    char addr[ADDR_MAX];//地址
};


//可动态调节
struct Contact
{
    struct PeoInfo* data;//为了可动态调节内存空间大小,应该定义一个结构体指针data
    int sz;//通讯录中当前有效元素的个数
    int capacity;//通讯录的当前最大容量
};
```

先简单介绍两个与动态内存函数

```
//头文件<stdlib.h>
void *malloc( size_t size );
//开辟一定字节的内存空间,并返回指向该空间的指针
```

```
//头文件<stdlib.h>
void *realloc( void *memblock, size_t size );
//更改由malloc()函数开辟的内存空间大小//可用于扩大内存空间

```

主要函数的代码展示

因为我们用的是动态内存开辟,默认先用malloc()只开辟了3个联系人的空间,在添加第4个联系人之前,应该对容量进行判断

```c
//检查容量
void CheckCapacity(struct Contact* pc)
{
    if (pc->sz == pc->capacity)
    {
        //增加容量,每次增加两个容量(每增容一次,就开辟两个人的内存空间)
        struct PeoInfo* ptr = (struct PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo));
        if (ptr != NULL)
        {
            pc->data = ptr;
            pc->capacity += 2;

            printf("增容成功\n");
        }
        else
        {
            perror("增容失败");
            exit(1);//明确终止一个程序时可用exit()
        }
    }
}
```

增加联系人

```c

void AddContact(struct Contact* pc)
{
//增加联系人之前应该检查容量
    CheckCapacity(pc);
    //录入新增联系人的信息
    printf("请输入名字:>");
    scanf("%s", pc->data[pc->sz].name);
    printf("请输入性别:>");
    scanf("%s", pc->data[pc->sz].sex);
    printf("请输入电话:>");
    scanf("%s", pc->data[pc->sz].tele);
    printf("请输入地址:>");
    scanf("%s", pc->data[pc->sz].addr);
    pc->sz++;//指向下一个位置,为增加下一个联系人作准备
    printf("增加成功\n");
}
```

删除联系人

与增加联系人之前要考虑容量够不够一样,在删除联系人之前,应该先查找当前通讯录是否存在该联系人

```c
//通过名字查找
int FindContactByName(const struct Contact* pc, const char* name)//因为只是查找相关信息,不需要对结构体内容进行修改,所以加const修饰指针更安全
{
    int i = 0;
    for (i = 0; i < pc->sz; i++)
    {
        if (strcmp(pc->data[i].name, name) == 0)
        {
            return i;//找到就返回对应下标
        }
    }
    //找不到了
    return -1;
}
```

```c
//删除联系人
void DelContact(struct Contact* pc)
{
    if (pc->sz == 0)
    {
        printf("通讯录为空,无法删除\n");
        return;
    }
    char name[NAME_MAX] = { 0 };
    printf("请输入要删除人的名字:>");
    scanf("%s", name);
    //查找需删除的联系人
    int pos = FindContactByName(pc, name);
    if (pos == -1)
    {
        printf("指定的联系人不存在\n");
    }
    else
    {
        //删除
        int j = 0;//删除的实质是从当前位置开始,将后面联系人的信息依次前移
        for (j = pos; j < pc->sz - 1; j++)
        {
            pc->data[j] = pc->data[j + 1];
        }
        pc->sz--;
        printf("删除成功\n");
    }
}

```

搜索联系人

直接调用FindContactByName()函数即可

```c
//搜索联系人
void SearchContact(const struct Contact* pc)
{
    char name[NAME_MAX] = { 0 };
    printf("输入要查找人的名字:>");
    scanf("%s", name);
    int pos = FindContactByName(pc, name);
    if (-1 == pos)
    {
        printf("未找到该联系人\n");
    }
    else
    {
        printf("%15s\t%8s\t%15s\t%30s\n\n",
            "name", "sex", "tele", "addr");
        printf("%15s\t%8s\t%15s\t%30s\n",
            pc->data[pos].name,
            pc->data[pos].sex,
            pc->data[pos].tele,
            pc->data[pos].addr);
    }
}

```

修改联系人信息

```c
//修改联系人信息
void ModifyContact(struct Contact* pc)
{
    char name[NAME_MAX] = { 0 };
    printf("输入要修改人的名字:>");
    scanf("%s", name);
    //老规矩,修改之前也查找下是否存在
    int pos = FindContactByName(pc, name);
    if (-1 == pos)
    {
        printf("要修改的成员不存在\n");
    }
    else
    {
        printf("请输入新成员的名字:>");
        scanf("%s", pc->data[pos].name);
        printf("请输入新成员的性别:>");
        scanf("%s", pc->data[pos].sex);
        printf("请输入新成员的电话:>");
        scanf("%s", pc->data[pos].tele);
        printf("请输入新成员的地址:>");
        scanf("%s", pc->data[pos].addr);
    }
}

```

排序联系人

用冒泡排序,因为普通的冒泡排序在排序大量数据时效率低下,应考虑其它快速排序,这里给出的是稍加优化的冒泡排序,用flag表示当前是否需要排序.

```c
//以姓氏排序
void SortContact(struct Contact* pc)
{
    int i = 0;
    int j = 0;
    int flag = 0;
    struct PeoInfo tmp;
    for (i = 0; i < pc->sz; i++)
    {
        for (j = 0; j < pc->sz - 1 - i; j++)
        {
            if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0)
            {
                 tmp = pc->data[j];
                pc->data[j] = pc->data[j + 1];
                pc->data[j + 1] =  tmp;
                flag = 1;//加入标记
            }
            if(falg == 0)
            {
               return;
            }
        }
    }
    printf("已排序\n");
}

```

下面是文件操作

温馨提示:写入到指定文件后,我们想打开看时,若用平常的方式打开,会乱码;应该以二进制方式打开

```
//将指定文件中的信息写入到内存空间中
void LoadContact(struct Contact* pc)
{
    //打开文件
    FILE* pf = fopen("contact.txt", "rb");//权限为"只读"
    if (pf == NULL)
    {
        perror("LoadContact::fopen");
        return;
    }
    //读文件
    struct PeoInfo tmp = { 0 };
    while (fread(&tmp, sizeof(struct PeoInfo), 1, pf))//fread返回值是?
    {
        //检查容量,若不够就增容
        CheckCapacity(pc);
        pc->data[pc->sz] = tmp;
        pc->sz++;
    }
    //关闭文件
    fclose(pf);
    pf = NULL;
}
//保存联系人信息到指定文件
void SaveContact(struct Contact* pc)
{
    //打开文件
    FILE* pf = fopen("contact.txt", "wb");//权限为"读写"
    if (pf == NULL)
    {
        perror("SaveContact::fopen");
        return;
    }
        //写入数据
        int i = 0;
        for (i = 0; i < pc->sz; i++)
        {
            //fwrite(&(pc->data[i]), sizeof(struct PeoInfo), 1, pf);
            fwrite(pc->data + i, sizeof(struct PeoInfo), 1, pf);
        }

     //关闭文件
            fclose(pf);
            pf = NULL;
}
//销毁通讯录(实质是释放内存)
void DestroyContact(struct Contact* pc)
{
    free(pc->data);//内存用完是个好习惯
    pc->data = NULL;//手动置空
    pc->capacity = 0;
    pc->sz = 0;
}
```

完整代码展示

contact.c

```

```

标签:struct,pc,实现,联系人,简易,通讯录,printf,data,name
来源: https://blog.csdn.net/HandsomeDog_L/article/details/120572294

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有