c语言实现通讯录

通讯录的常见功能:

  1. 存放一百个人的信息

  1. 打印每个人的信息

  1. 增加联系人

  1. 删除指定联系人

  1. 查找联系人

  1. 修改联系人

  1. 排序


我们这里需要用分块思想

首先创建一个头文件contact.h把需要引用的头文件和申明等放在这个头文件里,这样其他文件就只需要引用这个头文件就行了

#pragma once
#include
#include
#include

#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30

typedef struct pepoinfo {
    char name[MAX_NAME];//姓名
    int age;//年龄
    char sex[MAX_SEX];//性别
    char tele[MAX_TELE];//电话号码
    char addr[MAX_ADDR];//地址
}pepoinfo;

typedef struct contact {
    pepoinfo data[MAX];//存放数据
    int sz;//存放的联系人个数
}contact,*pcontact;

//对要用的函数进行声明
void Initcontact(contact* pc);
void Addcontact(contact* pc);
void Showcontact(const contact* pc);
void Delcontact(pcontact pc);
void Searchcontact(const contact* pc);
void Modifycontact(contact* pc);
void Sortcontact(contact* pc);

接下来是测试部分

测试部分主体:


#include "contact.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,
    ADD,
    DEL,
    SEARCH,
    MODIFY,
    SHOW,
    SORT
};

int main() {
    int input = 0;
    contact con;
    Initcontact(&con);
    do {
        menu();
        scanf_s("%d", &input);
        switch (input) {
        case ADD:
            Addcontact(&con);
            break;
        case DEL:
            Delcontact(&con);
            break;
        case SEARCH:
            Searchcontact(&con);
            break;
        case MODIFY:
            Modifycontact(&con);
            break;
        case SHOW:
            Showcontact(&con);
            break;
        case SORT:
            Sortcontact(&con);
            break;
        case EXIT:
            printf("退出通讯录\n");
            break;
        default:
            printf("选择错误\n");
            break;
        }

    } while (input);
}

如果是case1:这种形式还需要使用者去找哪一个数字对应哪一个操作

但是使用枚举之后exit自动赋值0,add自动赋值1等等,就增加了代码的可读性


再建一个contact.c文件实现通讯录

首先是能够初始化通讯录和增加联系人的函数

void Initcontact(contact* pc) {
    pc->sz = 0;
    memset(pc->data, 0, sizeof(pc->data));
}

这里不能直接写成pc->data={0},因为data是数组名,是首元素地址,是个常量的值;

要改一片空间,所以memset比较方便

sizeof(pc->data)求数组占多少字节

void Addcontact(contact* pc) {
    if (pc->sz == MAX) {
        printf("通讯录已满,不能再添加了\n");
        return;
    }
    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].addr);
    pc->sz++;
    printf("添加成功\n");
}

为什么pc->data[pc->sz].name不用取地址,而 &(pc->data[pc->sz].age)需要呢?

因为name是数组名,本身就是数组首元素地址,sex等同理


打印通讯录

void Showcontact(const contact* pc) {
    int i = 0;
    printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
    for (i = 0; i < pc->sz; i++) {
        //打印数据
        printf("%-10s %-4d %-5s %-12s %-30s\n",
            pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].tele,pc->data[i].addr);
    }
}

这里%-10s是为了左对齐打印输出


查找,删除,修改联系人的函数

static int findcontact(contact* pc, char name[]) {
    int i = 0;
    for (i = 0; i < pc->sz; i++) {
        if (0 == (strcmp(pc->data[i].name, name))) {//比较字符串用strcmp
            return i;
        }
    }
    return -1;
}
void Delcontact(pcontact pc) {
    if (pc->sz == 0) {
        printf("通讯录里没有可以删除的联系人\n");
        return;
    }
    char name[MAX_NAME] = { 0 };
    printf("请输入要删除的联系人\n");
    scanf("%s", name);//为什么这里不需要取地址呢?因为name本来就是一个地址
    int pos = findcontact(pc, name);
    if (pos == -1) {
        printf("要删除的人不存在\n");
        return;
    }
    int i = 0;
    for (i = pos; i < pc->sz - 1; i++) {
        //这里i不是从零开始而是从pos开始改变之后的元素
        pc->data[i] = pc->data[i + 1];
    }
    pc->sz--;
    printf("删除成功\n");
}
void Searchcontact(const contact* pc) {
    int i = 0;
    if (pc->sz == 0) {
        printf("通讯录里没有联系人\n");
    }
    char name[MAX_NAME] = { 0 };
    printf("请输入要寻找的联系人\n");
    scanf("%s", name);
    int pos =findcontact(pc, name);
    if (pos == -1) {
        printf("要寻找的人不存在\n");
        return;
    }
    printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
    //打印数据
    printf("%-10s %-4d %-5s %-12s %-30s\n",
        pc->data[pos].name,
        pc->data[pos].age,
        pc->data[pos].sex,
        pc->data[pos].tele,
        pc->data[pos].addr);
}
void Modifycontact(contact* pc) {
    if (pc->sz == 0) {
        printf("通讯录里没有联系人\n");
    }
    char name[MAX_NAME];
    printf("请输入要修改的联系人\n");
    scanf("%s", name);
    int pos = -1;
    pos = findcontact(pc, name);
    if (pos == -1) {
        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].addr);

    printf("修改成功\n");
}

这里把查找功能抽离成一个函数,大大减少代码冗余

那么findcontact函数为什么要用static修饰呢?

因为这个函数是为了辅助查找删除这些函数而实现的

我们不希望别人看到,不需要在头文件中申明,加上static只能在自己所在的.c文件内部中被看到

其他源文件用不上它,命名也不会发生冲突


排序

int cmp_by_age(const void* p1, const void* p2) {
    return ((pepoinfo*)p1)->age - ((pepoinfo*)p2)->age;
    //这里需要先将指针强制转换再通过指针找到年龄
}
void Sortcontact(contact* pc) {
    qsort(pc->data,pc->sz,sizeof(pepoinfo),cmp_by_age);
    //为什么可以直接写成pc->data而不是pc->data[0].age呢?
    //为什么是求pepoinfode大小呢?,因为每个联系人的元素类型是pepoinfo
    printf("排序成功\n");
}

总的contact.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "contact.h"

void Initcontact(contact* pc) {
    pc->sz = 0;
    memset(pc->data, 0, sizeof(pc->data));
}
void Addcontact(contact* pc) {
    if (pc->sz == MAX) {
        printf("通讯录已满,不能再添加了\n");
        return;
    }
    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].addr);
    pc->sz++;
    printf("添加成功\n");
}
void Showcontact(const contact* pc) {
    int i = 0;
    printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
    for (i = 0; i < pc->sz; i++) {
        //打印数据
        printf("%-10s %-4d %-5s %-12s %-30s\n",
            pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].tele,pc->data[i].addr);
    }
}
static int findcontact(contact* pc, char name[]) {
    int i = 0;
    for (i = 0; i < pc->sz; i++) {
        if (0 == (strcmp(pc->data[i].name, name))) {
            return i;
        }
    }
    return -1;
}
void Delcontact(pcontact pc) {
    if (pc->sz == 0) {
        printf("通讯录里没有可以删除的联系人\n");
        return;
    }
    char name[MAX_NAME] = { 0 };
    printf("请输入要删除的联系人\n");
    scanf("%s", name);//为什么这里不需要取地址呢?因为name本来就是一个地址
    int pos = findcontact(pc, name);
    if (pos == -1) {
        printf("要删除的人不存在\n");
        return;
    }
    int i = 0;
    for (i = pos; i < pc->sz - 1; i++) {
        //这里i不是从零开始而是从pos开始改变之后的元素
        pc->data[i] = pc->data[i + 1];
    }
    pc->sz--;
    printf("删除成功\n");
}
void Searchcontact(const contact* pc) {
    int i = 0;
    if (pc->sz == 0) {
        printf("通讯录里没有联系人\n");
    }
    char name[MAX_NAME] = { 0 };
    printf("请输入要寻找的联系人\n");
    scanf("%s", name);
    int pos =findcontact(pc, name);
    if (pos == -1) {
        printf("要寻找的人不存在\n");
        return;
    }
    printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
    //打印数据
    printf("%-10s %-4d %-5s %-12s %-30s\n",
        pc->data[pos].name,
        pc->data[pos].age,
        pc->data[pos].sex,
        pc->data[pos].tele,
        pc->data[pos].addr);
}
void Modifycontact(contact* pc) {
    if (pc->sz == 0) {
        printf("通讯录里没有联系人\n");
    }
    char name[MAX_NAME];
    printf("请输入要修改的联系人\n");
    scanf("%s", name);
    int pos = -1;
    pos = findcontact(pc, name);
    if (pos == -1) {
        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].addr);

    printf("修改成功\n");
}

int cmp_by_age(const void* p1, const void* p2) {
    return ((pepoinfo*)p1)->age - ((pepoinfo*)p2)->age;
    //这里需要先将指针强制转换再通过指针找到年龄
}
void Sortcontact(contact* pc) {
    qsort(pc->data,pc->sz,sizeof(pepoinfo),cmp_by_age);
    //为什么可以直接写成pc->data而不是pc->data[0].age呢?
    //为什么是求pepoinfode大小呢?,因为每个联系人的元素类型是pepoinfo
    printf("排序成功\n");
}

c语言实现通讯录_第1张图片
c语言实现通讯录_第2张图片
c语言实现通讯录_第3张图片

你可能感兴趣的:(c语言,c++,开发语言)