首页 > 其他分享 >通讯录(动态增长版本)——《初学C语言第52天》

通讯录(动态增长版本)——《初学C语言第52天》

时间:2024-01-07 10:31:51浏览次数:36  
标签:count name void C语言 pc 通讯录 printf 52 data

contact.h


////此通讯录为静态的版本(设置多少量就是多少,量的大小无法调整)
////动态版本:需要多少就给多少,不够用了就开辟新空间,多了就自动减少
////文件版本:动、静两种只要退出通讯录,保存的信息就消失了,而文件版本会依旧保存
#define _CRT_SECURE_NO_WARNINGS 1
#define  MAX 100
#define  MAXname 20
#define  MAXsex 10
#define  MAXtre 12
#define  MAXaddr 30
#define  Capacity 3
#define  increase  2
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
//类型声明
//人的信息
typedef struct p
{
    char name[MAXname];
    int age;
    char sex[MAXsex];//性别
    char tele[MAXtre];//电话
    char address[MAXaddr];//地址
}p;//加了typedef,就把结构体类型struct p重命名为了p
//封装一个通讯录(由于data和count都是通讯录的成员,同时变化且变化量相同,所以在头文件中封装,更容易找到)
typedef struct Contact
{
    p *data;//存放100个人的信息
    int count;//记录当前通讯录中人的实时个数,添加+1,删除-1
    int capacity;//当前通讯录的容量
}Contact;
//初始化通讯录
int InitContact(Contact* pc);//由于我们要通过pc指针来改变con的内容,所以不需要+const进行修饰
//增加联系人到通讯录
void AddContact(Contact* pc);
//显示通讯录中的信息
void ShowContact(const Contact* pc);//此处添加const是为了保护con的信息不被改动
//删除指定联系人
void DelContact(const Contact* pc);
//查找指定联系人
void SearchContact(Contact* pc);
//修改指定联系人
void ModifyContact(Contact* pc);
//排序通讯录中的联系人
//按照名字、年龄.......来排序
void SortContact(Contact* pc);
//销毁通讯录
void DestoryContact(Contact* pc);

contzct.c



#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
int InitContact(Contact* pc)
{
    assert(pc);
    pc->count = 0;
    pc->data = (p*)calloc(Capacity, sizeof(p));
    if (pc->data == NULL)
    {
        printf("InitContact::%s\n",strerror(errno));
        return 1;//出错打印错误,并返回1
    }
    pc->capacity = Capacity;//容量得记录下来,由于容量会随时更改,所以我们用#define设置一个符号
    return 0;
}//可以返回真假,或者使用void,直接返回
void CheckCapacity(Contact*pc)
{
    if (pc->count == pc->capacity)
    {
        p* m = (p*)realloc(pc->data, (pc->capacity + increase) * sizeof(p));//(原总容量+新增长得空间的个数)*单个元素的大小=现总容量
        if (m == NULL)
        {
            printf("AddContact::%s\n", strerror(errno));
            return;
        }
        else
        {
            pc->data = m;
            pc->capacity += increase;
            printf("增容成功!!!\n");
        }
    }
}
//增添
void AddContact(Contact* pc)
{
    assert(pc);
    //增容
    CheckCapacity(pc);
    printf("请输入名字:");
    scanf("%s", pc->data[pc->count].name);//scanf中,需要将数据输入到地址中,而name为数组,本身就是地址,所以不需要&
    printf("请输入年龄:");
    scanf("%d", &(pc->data[pc->count].age));//而age为变量,因此想要更改其值就要使用其地址,即&age
    printf("请输入性别:");
    scanf("%s", pc->data[pc->count].sex);
    printf("请输入电话:");
    scanf("%s", pc->data[pc->count].tele);
    printf("请输入地址:");
    scanf("%s", pc->data[pc->count].address);
    pc->count++;//此联系人添加完,就轮到下一个人
    printf("增加成功");
}
//显示
void ShowContact(const Contact* pc)
{
    assert(pc);
    int i = 0;
    printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");//由于1个汉字占2个字符
    //左对齐让占位符前面的数字为负数即可
    for (i = 0; i < pc->count; i++)
    {
        printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name
            , pc->data[i].age
            , pc->data[i].sex
            , pc->data[i].tele
            , pc->data[i].address);//\t:水平制表符,让其空开
    }
}
//此程序所有的信息只存于内存中,不能长时间保存,要长时间保存需要放在数据库中!!!!
static int Findbyname(Contact* pc, char name[])//此处添加static会让此函数声明仅能在contact.c文件中看到。
//该函数未在头文件声明是为了不想让别人看到。并且后续功能的实现还需要此函数
{
    assert(pc);
    int i = 0;
    for (i = 0; i < pc->count; i++)
    {
        if (0 == strcmp(pc->data[i].name, name))
        {
            return i;//找到了,返回其下标
        }
    }
    //由于函数返回类型为int,所以就不再设置else,返回-1了,直接作为函数返回值
    return -1;
}
//删除
void DelContact(Contact* pc)
{
    char name[MAXname] = { 0 };
    int i = 0;
    assert(pc);
    if (pc->count == 0)
    {
        printf("通讯录为空,没有信息可删除:");
        return;
    }
    printf("q请输入要删除人的名字:");
    scanf("%s", name);
    //删除之前,要先查找,再删除
    //1.查找
    int n = Findbyname(pc, name);//找不到返回-1,即n就相当于下标
    if (n == -1)
    {
        printf("要删除的人不存在:");
        return;//退出该函数
    }
    //2.删除(要将此位置为空的地方,存放后续添加的联系人)
    for (i = n; i < pc->count - 1; i++)
    {
        //加入现在有100个人的信息,即count=100,i=99,+1=100,而下标最大为99(就已经是最后一个元素,再大就越界了)
        //所以for语句中pc->count要-1,避免越界,也刚好满足条件
        pc->data[i] = pc->data[i + 1];
    }//若删除最后一个元素,就相当于最后一个元素的后面的一个元素进行覆盖,相当于没覆盖,最后一个元素覆不覆盖无所谓
    pc->count--;//但是通过pc->count--,假设100个元素,删除最后一个元素的话,只需要count--,我们最后一个元素不覆盖也可以,
    //count--为99,最后一个元素我们也访问不到,因为我们是拿count来访问我们的数据的
    printf("删除成功!!!");
}
//查找
void SearchContact(Contact* pc)
{
    assert(pc);
    char name[MAXname] = { 0 };
    printf("请输入要要查找人的名字:");
    scanf("%s", name);
    //1.查找
    int n = Findbyname(pc, name);
    if (n == -1)
    {
        printf("要查找的人不存在!!!");
        return;//找不到就返回
    }
    else//(找到了,打印出来)
    {
        printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");//由于1个汉字占2个字符
        //左对齐让占位符前面的数字为负数即可
        printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n", pc->data[n].name
            , pc->data[n].age
            , pc->data[n].sex
            , pc->data[n].tele
            , pc->data[n].address);
    }
}
//修改
void ModifyContact(Contact* pc)
{
    assert(pc);
    char name[MAXname] = { 0 };
    printf("请输入要修改人的名字:");
    scanf("%s", name);
    //1.查找
    int n = Findbyname(pc, name);
    if (n == -1)
    {
        printf("要修改的人不存在!!!");
        return;//找不到就返回
    }
    printf("要修改的联系人已经查找到,请您进行修改:");
    //修改,并重新录入
    printf("请输入名字:");
    scanf("%s", pc->data[n].name);    //此时下标为n
    printf("请输入年龄:");
    scanf("%d", &(pc->data[n].age));
    printf("请输入性别:");
    scanf("%s", pc->data[n].sex);
    printf("请输入电话:");
    scanf("%s", pc->data[n].tele);
    printf("请输入地址:");
    scanf("%s", pc->data[n].address);
    printf("修改成功!!!");
}
//排序
int cmp_peo_by_name(const void* e1, const void* e2)
{
    return strcmp(((p*)e1)->name, ((p*)e2)->name);
}
//按照名字来排序
void SortContact(Contact* pc)
{
    assert(pc);
    qsort(pc->data, pc->count, sizeof(p), cmp_peo_by_name);// sizeof(p)可替换为 sizeof(pc->data[0]),p只是元素pc->data的类型,拿下标为0的元素来计算也可以
    printf("排序成功!!!");
}
//销毁
void DestoryContact(Contact* pc)
{
    assert(pc);
    free(pc->data);//释放
    pc->data = NULL;//回收
}
//qsort:比较函数(可以排序任意类型的数据),头文件<stdlib.h>,<search.h>
//其参数为:void qsort(void* base, size_t num, size_t width,int(*cmp)(const void* e1,const void* e2))
//void* base:指的是我们要排序的数据的起始位置
// size_t num:待排序的数据元素的个数
// size_t width:待排序的数据元素的大小(占几个字节)
//int(*cmp)(const void* e1,const void* e2):函数指针,需声明新的函数,并使用strcmp去比较所想比较的内容

////循环结束标志
//return: 从当前的方法中退出,返回到该调用的方法的语句处,继续执行。
//continue: 终止当前的一次循环过程,其 不 跳出循环,而是继续往下判断循环条件执行语句。
//          只能结束循环中的一次过程, 但不能终止循环继续进行。
//break: 直接跳出 当前 的循环,从当前循环外面开始执行,忽略循环体中任何其他语句和循环条件测试。
//       它只能跳出一层循环,如果你的循环是嵌套循环,那么你需要按照你嵌套的层次,逐步使用break来跳出。


test.c



//////实现一个通讯录
////人的信息:
//名字
//年龄
//性别
//电话
//地址

////实现功能:
// 存放100个人的信息
// 1.增添联系人
// 2.删除联系人
// 3.查找联系人
// 4.修改联系人
// 5.显示联系人
// 6.联系人排序

////文件构成:
//test6.8.c        测试功能
//contact.c     通讯录相关功能的实现
//contact.h     通讯录相关的声明

#define _CRT_SECURE_NO_WARNINGS 1
#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");
}
int main()
{
    int input = 0;
    Contact con;//通讯录
    //创建一个函数,初始化通讯录
    //为什么不直接初始化,而是借助函数进行初始化。
    //1.我们尽量把代码分装成模块的形式,写一个函数来完成此项工作(模块化工作)
    //2.如果我们想对通讯录的数据初始化的内容不能通过{}来初始化,我们想用另一种方法初始化或初始化成我们指定的内容,即此时用{}初始化不方便
    InitContact(&con);//传参为地址是因为,后续还要对con进行更改,并且结构体传参尽量传地址,这样效率更高(传con,无法对其进行更改)
    do
    {
        menu();//菜单
        printf("请选择:");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
            AddContact(&con);//结构体传参传地址效率更高
            break;
        case 2:
            DelContact(&con);
            break;
        case 3:
            SearchContact(&con);
            break;
        case 4:
            ModifyContact(&con);
            break;
        case 5:
            ShowContact(&con);
            break;
        case 6:
            SortContact(&con);
            break;
        case 0:
            printf("退出通讯录:\n");
            break;
        default://退出程序时要回收空间,所以在退出之前回收
            DestoryContact(&con);
            printf("选择错误:\n");
            break;
        }
    } while (input);//输入0,为假,就跳出代码
    return 0;
}

标签:count,name,void,C语言,pc,通讯录,printf,52,data
From: https://blog.51cto.com/KKhahaha/9132414

相关文章

  • 动态内存管理:malloc free——《初学C语言第50天》
    //////——————1.动态内存管理(内存空间)////共四个函数:malloc free calloc realloc////1.为什么存在动态内存分配////我们已经掌握的内存开辟方式有:////intval=20;//在栈空间上开辟四个字节////chararr[10]={0};//在栈空间上开辟10个字节的连续空间////......
  • 联合union——《初学C语言第49天》
    //////————联合:union////1.联合的定义////联合也是一种特殊的自定义类型//#include<stdio.h>//unionUn//Un为联合标签//{// inta;// charc;//};//structSt//{// inta;// intb;//};//intmain()//{// unionUnu;// printf("%d\n",sizeof(u));//4// printf("%p\n",&am......
  • qt c语言双三次线性插值
    用chatgpt生成的测试了比较卡for(inty=0;y<enlargedHeight;y++){for(intx=0;x<enlargedWidth;x++){//计算原始图像中对应的浮点坐标floatoriginalX=(float)x/(float)enlar......
  • C语言学习随笔-05 变量
    变量:其值在其作用域内可以改变的量交变量,变量在使用前必须定义,每一个变量都有地址。1、变量的命名    ● 变量名由大小写字母、数字和下划线组成,必须以大小写字母或下划线开头,不能以数字开头。    ● C中也允许定义各种其它类型的变量,如枚举、指针、数组、结构体......
  • C语言学习随笔-04 数据类型
    C中的数据类型:在C语言中,数据类型指的是用于声明不同类型的变量或函数的一个广泛的系统。变量的类型决定了变量存储占用的空间,以及如何解释存储的位模式。常用的四中基本数据类型:int、char、float、double    ▶基本类型:它们是算术类型,如int、char、float、double。 ......
  • C语言逆波兰式算法
    1#include<stdio.h>23//数字模式识别4#defineIS_NUM(c)(((c)>='0')&&((c)<='9')||((c)=='.'))5//符号字符识别6#defineIS_OPERATOR(c)(((c)=='+')||((c)=='-')||((c)==&......
  • C语言学习随笔-03 基本语法
    c语言程序由函数构成,每个函数可以实现一个或多个功能。 一个正规程序可以有多个函数,但是有且只有一个主函数。 函数只有在被调用的时候才执行,主函数由系统调用执行。 函数的格式必须按照规范书写。 C语言程序文件的后缀为.c1、C的令牌(Token):C程序由各种令牌组成,令牌可......
  • 枚举——《初学C语言第48天》
    ////三.枚举////枚举:就是一一列举,把可能的取值一一列举。////比如生活中:////1.一周的星期一到星期日是有限的7天,可以一一列举。////2.性别有:男、女、保密,也可以一一列举。////2.月份有12个月,也可以一一列举////这就可以使用枚举了。////————1.枚举类型的定义//enum......
  • 基于STC89C52RC的温湿度显示与按键可调的时钟显示
    大学时候的课程设计项目,本人只负责软件设计。课题摘要摘要温湿度参数的检测已经成为人们日常生产生活中的一个重要的参数指标。温度和湿度是两个最基本的环境参数,人们生活与温湿度息息相关。在工农业生产、环保、科研、化工业、制药业等地方,都经常需要对环境温度和湿度进行测量。......
  • macOS Sonoma 14 beta 3 (23A5286i) ISO、IPSW、PKG 下载,公共测试版现已推出
    macOSSonoma14beta3(23A5286i)ISO、IPSW、PKG下载,公共测试版现已推出本站下载的macOS软件包,既可以拖拽到Applications(应用程序)下直接安装,也可以制作启动U盘安装,或者在虚拟机中启动安装。另外也支持在Windows和Linux中创建可引导介质。作者主页:sysin.orgmacOSSonom......