【【C语言康复训练-5】】

C语言康复训练-5

head.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define DEFAULT_SZ 3
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30


//枚举之后的顺序是按照次序
//安排0 1 2 3 4 5 6 7 
enum option
{
    EXIT,//枚举 0
    ADD,// 1
    DEL,//2 
    SEARCH,//3
    MODIFY,//4
    SHOW,//5
    SORT,//6
    SAVE//7
};


typedef struct peoinfo
{
    char name[MAX_NAME];//20
    int age;
    char sex[MAX_SEX];//5
    char tele[MAX_TELE];//12
    char addr[MAX_ADDR];//30
}peoinfo;



typedef struct contact//定义一个通讯录类型
{
    struct peoinfo* data;
    //之前这里是一块固定大小的空间 现在我们改成可变空间
    //用指针的方式修改
    // size是给出用来记录放了多少个信息的
    // 那么我们还需要一个数字来表示内部的容量
    //不然我怎么知道满不满 所以再增加一个变量
    int capacity;//当前通讯录的最大容量 

    int size;//记录当前已经有的元素个数
}contact;


void menu();
//声明函数 initcontact(&con)
void initcontact(contact* ps);
void addcontact(contact* ps);
void showcontact(const struct contact* ps);
void delcontact(contact* ps);
void searchcontact(const struct contact* ps);
void modifycontact(contact* ps);
void sortcontact(contact* p);
void destroycontact(contact* ps);
void savecontact(contact* ps);
void loadcontact(contact* ps);
void checkcapacity(struct contact* ps);

head.c

#define _CRT_SECURE_NO_WARNINGS  1
#include"head.h"
//通讯录设计因为是在C语言康复训练,简单学习学习

int main()
{
	int input = 0;
	contact con;
	//其实本来想写struct contact  
   // 但是typedef   contact
	initcontact(&con);
	do
	{
		menu();
		printf("请选择->\n");
		scanf("%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);//虽然只是简单的show 并不会来改变值,但是结构体传参
            //不要再复制临变量了,所以我们直接传递&con
            break;

        case SORT:
            sortcontact(&con);
            break;

        case SAVE:
            savecontact(&con);
            break;

        case EXIT:
            savecontact(&con);
            //销毁通讯录 释放动态开辟内存
            destroycontact(&con);
            printf("退出通讯录\n");
            break;

        default:
            printf("输入非法请重试\n");
            break;

        }
        //这里的case 1 2 3 4 5 6 0 对我们来说并不是很好的去观察 
        //所以既然如此我们运用枚举的方法提前在头文件里面这样的话写case会更容易一点
	} while (input);
    return 0;
}


void destroycontact(struct contact* ps)
{
    free(ps->data);
    ps->data = NULL;


}

project.c

#define _CRT_SECURE_NO_WARNINGS  1
#include"head.h"

//EXIT,//枚举 0
//ADD,// 1
//DEL,//2 
//SEARCH,//3
//MODIFY,//4
//SHOW,//5
//SORT,//6
//SAVE//7
void menu()
{
	printf("*************************\n");
	printf("*************************\n");
	printf("*********0.退出**********\n");
	printf("*********1.增加**********\n");
	printf("*********2.删除**********\n");
	printf("*********3.寻找**********\n");
	printf("*********4.修改**********\n");
	printf("*********5.显示**********\n");
	printf("*********6.排序**********\n");
	printf("*********7.保存**********\n");
	printf("*************************\n");
	printf("*************************\n");
}

void initcontact(struct contact* ps)
{
    ps->data = (struct peoinfo*)malloc(DEFAULT_SZ * sizeof(struct peoinfo));
    //对于初始化的形式 我们malloc就是一个控制内存空间的函数
    //我们先确定了大体的方向 大概是能预存3个数字 这样来说就不会太占整个内存
    //并且存入之后支持可擦去

    if (ps->data == NULL)
    {
        return;
    }
    ps->size = 0;
    ps->capacity = DEFAULT_SZ;
    loadcontact(ps);// 存!!!!
}
//声明函数
void loadcontact(contact* ps)
{
    peoinfo tmp = { 0 };
    FILE* pfread = fopen("contact.dat", "rb");
    if (pfread == NULL)
    {
        printf("loadcontact::%s\n", strerror(errno));
        return;
    }
    //读取文件放到通讯里
    while (fread(&tmp, sizeof(peoinfo), 1, pfread))
    {
        checkcapacity(ps);
        ps->data[ps->size] = tmp;
        ps->size++;
    }
    //这里需要解决的问题是读一个再一个我们究竟什么时候停下
    //并且也会涉及到扩充的问题
    //
    fclose(pfread);
    pfread = NULL;
}
//对于初始化来说,我们希望一开始data里面能放3个元素

void checkcapacity(struct contact* ps)
{
    if (ps->size == ps->capacity)
    {
        //增容
        struct peoinfo* ptr = realloc(ps->data, (ps->capacity) * sizeof(struct peoinfo));
        if (ptr != NULL)
        {
            ps->data = ptr;
            ps->capacity += 2;
            printf("增容成功\n");
        }
    }
}
void addcontact(struct contact* ps)
{
    //对于增删查改我们所需要做的是先check
    //我们用来检测通讯录的容量如果满了就增加空间
    //如果不满,啥事不干



    checkcapacity(ps);
    //增加数据
    printf("请输入名字:->");
    scanf("%s", ps->data[ps->size].name);
    printf("请输入年龄:->");
    scanf("%d", &(ps->data[ps->size].age));
    printf("请输入性别:->");
    scanf("%s", ps->data[ps->size].sex);
    printf("请输入电话:->");
    scanf("%s", ps->data[ps->size].tele);
    printf("请输入地址:->");
    scanf("%s", ps->data[ps->size].addr);
    ps->size++;
    printf("添加成功\n");

}





//    // 我们执行加操作时,首先判断内部是不是满的情况
//    if (ps->size == MAX)
//    {
//        printf("通讯录已满,无法增加\n");
//    }
//    else
//    {
//        printf("请输入名字:->");
//        scanf("%s", ps->data[ps->size].name);
//        //首先我们知道con数组内部有两个部分一个是data 还有一个个数size
//        //指针ps->先指向了data,意在表示我需要的内容是整个data的东西
//        //然后为什么data里面的数据是ps->size呢,因为size的内容主要指代的是个数
//        //你这么想 size和data深度绑定 不然我为什么要自己另外设置一个size出来
//        //这样的话才能确定是第几个,然后我再确定是这几个大组里面的name成分
//        printf("请输入年龄:->");
//        scanf("%d", &(ps->data[ps->size].age));
//        //name是一个数组不需要取地址 但是age是int型的 所以age位需要取地址
//        printf("请输入性别:->");
//        scanf("%s", ps->data[ps->size].sex);
//        printf("请输入电话:->");
//        scanf("%s", ps->data[ps->size].tele);
//        printf("请输入地址:->");
//        scanf("%s", ps->data[ps->size].addr);
//        ps->size++;
//        printf("添加成功\n");
//    }
//}
void showcontact(const struct contact* ps)
{
    if (ps->size == 0)
    {
        printf("通讯录为空\n");
    }
    else
    {
        int i = 0;
        for (i = 0;i < (ps->size);i++)
        {
            printf("%20s\t%4s\t%5s\t%12s\t%20s\n", "名字", "年龄", "性别", "电话", "地址");
            //%20s表示20个字符 \t表示空出四字节
            printf("%20s\t%4d\t%5s\t%12s\t%20s\n",
                ps->data[i].name,
                ps->data[i].age,
                ps->data[i].sex,
                ps->data[i].tele,
                ps->data[i].addr);

        }

    }
}
//怎么个打印法 我们希望
//名字 电话  性别    住址   年龄
//张三  123    男    西安     23
//

static int findbyname(const struct contact* ps, char name[MAX_NAME])
//static 修饰局部变量 表示这个find只能在内部使用
{
    int i = 0;
    for (i = 0;i < ps->size;i++)
    {
        if (0 == strcmp(ps->data[i].name, name))
        {
            return i;
        }
    }
    return -1;
}
void delcontact(struct contact* ps)
{
    char name[MAX_NAME];
    //删除首先需要告诉出名字
    printf("请输入要删除人的名字:>");
    scanf("%s", name);
    //删除的方法有2种一种是1234567 比如要删除4 那么就剩下123567 后面的往前面覆盖就行
    //另一种做法是把最后一种元素放到4上
    //我们选择往前覆盖法
    //1,查找要删除的名字 2 .删除覆盖
//用一整个模块来代替他
    //查找删除的人在什么位置,找到了返回名字所在元素的下标 找不到返回-1
    int pos = findbyname(ps, name);
    if (pos == -1)
    {
        printf("需要删除的名字不存在\n");
    }
    else//删除数据 开始覆盖
    {
        int j = 0;
        for (j = pos;j < (ps->size - 1);j++)
        {
            ps->data[j] = ps->data[j + 1];
        }
        ps->size--;
        printf("删除成功\n");
    }
}
void searchcontact(const struct contact* ps)
{
    char name[MAX_NAME];
    printf("请输入要查找人的名字\n");
    scanf("%s", name);
    //我们发现这个遍历的功能在我们这里也需要 重复写
    //我们为什么不用一个模块替代他的功能
    int pos = findbyname(ps, name);
    if (pos == -1)
    {
        printf("要查找的人不存在\n");
    }
    else
    {
        printf("%20s\t%4s\t%5s\t%12s\t%20s\n", "名字", "年龄", "性别", "电话", "地址");
        //%20s表示20个字符 \t表示空出四字节
        printf("%20s\t%4d\t%5s\t%12s\t%20s\n",
            ps->data[pos].name,
            ps->data[pos].age,
            ps->data[pos].sex,
            ps->data[pos].tele,
            ps->data[pos].addr);
    }
}
void modifycontact(struct contact* ps)
{
    char name[MAX_NAME];
    printf("请输入要修改人的名字:>");
    scanf("%s", name);
    int pos = findbyname(ps, name);
    if (pos == -1)
    {
        printf("要修改的人不存在\n");
    }
    else
    {
        printf("请输入名字:->");
        scanf("%s", ps->data[pos].name);
        printf("请输入年龄:->");
        scanf("%d", &(ps->data[pos].age));
        printf("请输入性别:->");
        scanf("%s", ps->data[pos].sex);
        printf("请输入电话:->");
        scanf("%s", ps->data[pos].tele);
        printf("请输入地址:->");
        scanf("%s", ps->data[pos].addr);
        printf("修改成功\n");
    }
}

void sortcontact(struct contact* p)
{
    if (p->size == 0)
    {
        printf("通讯录为空\n");
    }
    int i = 0;
    int j = 0;
    for (i = 0; i < p->size - 1; i++)
    {
        for (j = 0; j < p->size - i - 1; j++)
        {
            if (strcmp(p->data[j].name, (p->data[j + 1]).name) > 0)
            {
                struct peoinfo tmp;
                tmp = p->data[j];
                p->data[j] = p->data[j + 1];
                p->data[j + 1] = tmp;
            }
        }
        printf("排序成功!\n");
    }
}

void savecontact(struct contact* ps)
{
    FILE* pfwrite = fopen("contact.dat", "wb");
    if (pfwrite == NULL)
    {
        printf("savecontact::%s\n", strerror(errno));
        return;
    }
    int i = 0;
    for (i = 0;i < ps->size;i++)
    {
        fwrite(&(ps->data[i]), sizeof(peoinfo), 1, pfwrite);
    }
    fclose(pfwrite);
    pfwrite = NULL;
    printf("保存成功!\n");
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值