C语言之通讯录的实现篇

简介: C语言之通讯录的实现篇

今天实现同通讯录的功能。在学习了结构体和其他的自定义的类型之后,我们就可以实现一个的通讯录。


实现一个通讯录:


  1. 可以保存100个人的信息
  2. 增加人的信息
  3. 删除指定联系人的信息
  4. 查找指定联系人的信息
  5. 修改指定联系人的信息
  6. 显示所有联系人的信息
  7. 排序通讯录的信息

一个人的信息包括:名字+年龄+性别+电话+住址

那接下来我们将从test.c 测试代码  contact.h 声明  contact.c 实现 去实现

test.c

主菜单menu

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void menu()
{
  printf("************************************");
  printf("********1.add      2.del************");
  printf("********3.search   4.modify*********");
  printf("********5.show     6.sort***********");
  printf("********0.exit           ***********");
  printf("************************************");
}
enum Option
{
  EXIT,//0
  ADD,//1
  DEL,//2
  SEARCH,//3
  MODIFY,//4
  SHOW,//5
  SORT,//6  
};
int main()
{
  int input = 0;
  Contact con;//创建通讯录con
  do
  {
    menu();
    printf("请输入你的选择:>\n");
    scanf("%d", &input);
    switch (input)//这里为了代码更加清晰用枚举常量
    {
    case ADD:
      break;
    case DEL:
      break;
    case SEARCH:
      break;
    case MODIFY:
      break;
    case SHOW:
      break;
    case SORT:
      break;
    case EXIT:
      printf("退出通讯录\n");
      break;
    default:
      printf("选择错误,请重新选择:>\n");
      break;
    }
  } while (input);
  return 0;
}
  • 菜单是根据用户需求而设计
  • 使用枚举常量 为了让程序员写代码 更加清晰

创建通讯录con

Contact con;//创建通讯录con


初始化通讯录InitContact

InitContact(&con);

这里需要特别注意的是,结构体传参到底是传值还是传地址??🆗忘了小朋友戳一戳

增加个人信息AddContact

AddContact(&con);

展示个人信息ShowContact

ShowContact(&con);//即使这里不需要& 但是出于效率考虑还是需要

删除个人信息DelContact

DelContact(&con);

查找个人信息SearchContact

SearchContact(&con);

修改个人信息ModifyContact

ModifyContact(&con);

test.c总代码

#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");
}
enum Option
{
  EXIT,//0
  ADD,//1
  DEL,//2
  SEARCH,//3
  MODIFY,//4
  SHOW,//5
  SORT,//6  
};
int main()
{
  int input = 0;
  //创建通讯录
  Contact con;
  //初始化通讯录
  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);
      break;
    case SORT:
      //SortContact(&con);
      break;
    case EXIT:
      printf("退出通讯录\n");
      break;
    default:
      printf("选择错误,请重新选择:>\n");
      break;
    }
  } while (input);
  return 0;
}

contact.h

contact.h文件主要是头文件的包含

头文件包含

在我们写代码的过程中,会调用库函数,需要包含头文件,和声明函数。


所以我们将所有函数声明和头文件放到我们.h 文件中。


当然,在其他.c文件需要使用时,我们只需要包含 我们创造的 头文件"contact.h" 即可。


自己创建的头文件用" " 双引号,库函数的头文件用< >

#pragma once
#include<stdio.h>
#include<string.h>
#include<assert.h>

PeoInfo_个人信息的设置声明

我们怎样去设置一个人的全部信息呢?姓名+年龄+性别+电话+住址 都是需要不同类型的变量去设置,所以我们把它们都放到【结构体】里面。

#define NAME_MAX 20
#define SEX_MAX 20
#define TELE_MAX 20
#define ADDR_MAX 20
typedef struct PeoInfo
{
  char name[NAME_MAX];
  int age;
  char sex[SEX_MAX];
  char tele[TELE_MAX];
  char addr[ADDR_MAX];
}PeoInfo;
  • typedef是定义结构体类型由struct PeoInfo---> PeoInfo (这样后面使用定义变量时类型就直接写PeoInfo就可以了)
  • 数组【】里面如果是常量 那就后期想修改是非常不方便的,所以我们自己定义NAME_MAX等,后期修改起来更加方便。

Contact_存放个人信息声明

如果我想存放100个人的信息,那我们怎样去存放100个人的信息呢?用结构体数组(所谓就是存放结构体类型变量的数组)

Contact_存放个人信息声明
如果我想存放100个人的信息,那我们怎样去存放100个人的信息呢?用结构体数组(所谓就是存放结构体类型变量的数组)
#defi
  • typedef是定义结构体类型由struct Contact---> Contact (这样后面使用定义变量时类型就直接写Contact就可以了)
  • 数组【】里面如果是常量 那就后期想修改是非常不方便的,所以我们自己定义MAX等,后期修改起来更加方便。
  • 可以通俗理解为:一个结构体类型的数组data里面存放一个一个的结构体数据。一个结构体类型的数据就是PeoInfo

InitContact_初始化个人信息声明

初步创建完成我们的通讯录,那我们调试发现通讯录里面全是随机值,所以我们需要封装一个函数去初始化个人信息。

void InitContact(Contact* pc);

AddContact_增加个人信息

void AddContact(Contact* pc);

ShowContact_展示个人信息

void ShowContact(Contact* pc);

DelContact_删除个人信息

void DelContact(Contact *pc);

SearchContact_查找个人信息

void SearchContact(Contact* pc);

ModifyContact_修改个人信息

void ModifyContact(Contact* pc);

contact.h总代码

#pragma once
#include<stdio.h>
#include<string.h>
#include<assert.h>
#define NAME_MAX 20
#define SEX_MAX 20
#define TELE_MAX 20
#define ADDR_MAX 30
#define MAX 100
typedef struct PeoInfo
{
  char name[NAME_MAX];
  int age;
  char sex[SEX_MAX];
  char tele[TELE_MAX];
  char addr[ADDR_MAX];
}PeoInfo;
typedef struct Contact
{
  PeoInfo data[MAX];//存放数据
  int sz;//记录当前通讯录中存放的人的信息个数
}Contact;
//初始化通讯录
void InitContact(Contact* pc);
//增加个人信息
void AddContact(Contact* pc);
//展示个人信息
void ShowContact(Contact* pc);
//删除个人信息
void DelContact(Contact *pc);
//查找个人信息
void SearchContact(Contact* pc);
//修改个人信息
void ModifyContact(Contact* pc);
//排序
//void SortContact(Contact* pc);

contact.c

InitContact_初始化个人信息

void InitContact(Contact* pc)
{
    assert(pc);
  pc->sz = 0;
  memset(pc->data, 0, sizeof(pc->data));
}
  • 传地址的结构体访问两种方式:->    *( ).
  • 关于memset内存函数的复习,戳一戳:C语言之内存函数篇(3)_唐唐思的博客-CSDN博客
  • data是数组名 访问数组名即访问数组的第一个元素,单独放在sizeof里面,整个数组的大小
  • 不要遗忘assert去断言,这里要修改pc指向的空间修改,所以不需要const修饰。

完成了我们的通讯录的初始化,感觉要长脑子了。 接下来一步一步实现它的功能。

AddContact_增加个人信息

首先,这幅图想说明: data的下标和sz的数值是对应的

void AddContact(Contact* pc)
{
    assert(pc);
  printf("请输入名字\n");
  scanf("%s", pc->data[pc->sz].name);//name是数组名,不用&
  printf("请输入年龄\n");
  scanf("%d", &(pc->data[pc->sz].age));//
  printf("请输入性别\n");
  scanf("%s", pc->data[pc->sz].sex);
  printf("请输入电话\n");
  scanf("%s", pc->data[pc->sz].tele);
  printf("请输入地址\n");
  scanf("%s", pc->data[pc->sz].addr);
  //
  pc->sz++;
  printf("增加成功\n");
}
  • scanf输入 %d %s
  • scanf输入&
  • 结构体访问成员

ShowContact_展示个人信息

我们改动了通讯录之后,我们都需要去观察一下通讯录,这个时候需要封装函数去实现这个功能

void ShowContact(const Contact* pc)
{
  assert(pc);
  if (pc->sz == 0)
  {
    printf("通讯录为空,无需打印\n");
    return 0;
  }
  int i = 0;
  //名字 年龄 性别 电话 地址
  //-左对齐
  //20是需要20字符的位置来放名字 
  printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
  for (i = 0; i < pc->sz; i++)
  {
    printf("%-20s%-5d%-5s%-12s%-30s\n",
      pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
  }
  • const 和 assert
  • 结构体的访问
  • 一定要判断一下通讯录里的是否有数据
  • 格式美观:%-20s 是左对齐20个字符的空间大小
  • %s %d


FindByName查找函数

关于查找个人信息函数,我们在删除,查找,修改里面都会用的。

static int FindByName(const Contact* pc, char name[])
{
  assert(pc);
  int i = 0;
  for (i = 0; i < pc->sz; i++)
  {
    if (strcmp(pc->data[i].name, name) == 0)//遍历一边看是否有相同的名字
    {
      return i;
    }
  }
  return -1;
}
  • const修饰的指针,assert判断
  • 使用strcmp函数去判断两个字符串是否相等,大小关系
  • 查找就是把通讯录遍历一遍,找到了就返回下标,找不到就返回-1


DelContact_删除个人信息

删除联系人,我们首先需要找到联系人,我们就去封装一个查找的函数【FindByname】:把通讯录遍历一遍,找到了就返回下标,找不到就返回-1。其实我们发现后面 查找 修改 删除的功能都需要用这个函数。

void DelContact(Contact* pc)//删除
{
  char name[NAME_MAX];//
  assert(pc);
  if (pc->sz == 0)
  {
    printf("通讯录为空,无法删除\n");
    return;
  }
  printf("输入要删除的名字:>");
  scanf("%s", name);
  int ret = FindByName(pc, name);
  if (ret == -1)
  {
    printf("要删除的人不存在\n");
    return;
  }
  //存在返回这个人的所在data的下标放入ret
  int i = 0;
  for (i = ret; i < pc -> sz - 1; i++)//注意不要数组越界
  {
    pc->data[i] = pc->data[i + 1];
  }
  pc->sz--;
  printf("删除成功\n");
}
  • 返回的下标被ret接收,要使用起来,从把下标为ret删除(方法:后面依次覆盖和移动往前
  • 注意不要数组越界访问,函数内部 i 值还要+1 可能会造成越界。
  • 如果要删除最后一个数据,直接sz--即可。

SearchContact_查找个人信息

void SearchContact(Contact* pc)
{
  char name[NAME_MAX];
  assert(pc);
  //查找
  printf("输入要查找的名字:>");
  scanf("%s", name);
  int ret = FindByName(pc, name);
  if (ret == -1)
  {
    printf("要查找的人不存在\n");
    return;
  }
  //显示
  printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
  printf("%-20s%-5d%-5s%-12s%-30s\n",
                        pc->data[ret].name, pc->data[ret].age, 
                        pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}//打印的是下标为ret里的元素数据
  • 打印的是下标为ret里的元素数据

ModifyContact_修改个人信息

void ModifyContact(Contact* pc)
{
  char name[NAME_MAX];
  assert(pc);
  //查找
  printf("输入要修改的名字:>");
  scanf("%s", name);
  int ret = FindByName(pc, name);
  if (ret == -1)
  {
    printf("要修改的人不存在\n");
    return;
  }
  //修改
  assert(pc);
  printf("请输入名字\n");
  scanf("%s", pc->data[ret].name);//name是数组名,不用&
  printf("请输入年龄\n");
  scanf("%s", &(pc->data[ret].age));
  printf("请输入性别\n");
  scanf("%s", pc->data[ret].sex);
  printf("请输入电话\n");
  scanf("%s", pc->data[ret].tele);
  printf("请输入地址\n");
  scanf("%s", pc->data[ret].addr);
  printf("修改成功\n");
}//下标是ret的数组元素内的数据被修改
  • 下标是ret的数组元素内的数据被修改

contact.c总代码

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
//初始化
void InitContact(Contact* pc)
{
  assert(pc);
  pc->sz = 0;
  memset(pc->data, 0, sizeof(pc->data));
}
//增加
void AddContact(Contact* pc)
{
  assert(pc);
  printf("请输入名字\n");
  scanf("%s", pc->data[pc->sz].name);//name是数组名,不用&
  printf("请输入年龄\n");
  scanf("%d", &(pc->data[pc->sz].age));//
  printf("请输入性别\n");
  scanf("%s", pc->data[pc->sz].sex);
  printf("请输入电话\n");
  scanf("%s", pc->data[pc->sz].tele);
  printf("请输入地址\n");
  scanf("%s", pc->data[pc->sz].addr);
  pc->sz++;
  printf("增加成功\n");
}
//展示
void ShowContact(const Contact* pc)
{
  assert(pc);
  if (pc->sz == 0)
  {
    printf("通讯录为空,无需打印\n");
    return 0;
  }
  int i = 0;
  //名字 年龄 性别 电话 地址
  //-左对齐
  //20是需要20字符的位置来放名字 
  printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
  for (i = 0; i < pc->sz; i++)
  {
    printf("%-20s%-5d%-5s%-12s%-30s\n",
      pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
  }
}
//删除,查找,修改都需要使用
int FindByName(const Contact* pc, char name[])
{
  assert(pc);
  int i = 0;
  for (i = 0; i < pc->sz; i++)
  {
    if (strcmp(pc->data[i].name, name) == 0)
    {
      return i;
    }
  }
  return -1;
}
//删除
void DelContact(Contact* pc)
{
  char name[NAME_MAX];
  assert(pc);
  if (pc->sz == 0)
  {
    printf("通讯录为空,无法删除\n");
    return;
  }
  printf("输入要删除的名字:>");
  scanf("%s", name);
  int ret = FindByName(pc, name);
  if (ret == -1)
  {
    printf("要删除的人不存在\n");
    return;
  }
  //存在返回这个人的所在data的下标放入ret
  int i = 0;
  for (i = ret; i < pc -> sz - 1; i++)
  {
    pc->data[i] = pc->data[i + 1];
  }
  pc->sz--;
  printf("删除成功\n");
}
//查找
void SearchContact(Contact* pc)
{
  char name[NAME_MAX];
  assert(pc);
  if (pc->sz == 0)
  {
    printf("通讯录为空,无法查找\n");
    return;
  }
  //查找
  printf("输入要查找的名字:>");
  scanf("%s", name);
  int ret = FindByName(pc, name);
  if (ret == -1)
  {
    printf("要查找的人不存在\n");
    return;
  }
  //返回下标显示这个的信息🆗
  printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
  printf("%-20s%-5d%-5s%-12s%-30s\n",
      pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}
//修改
void ModifyContact(Contact* pc)
{
  char name[NAME_MAX];
  assert(pc);
  if (pc->sz == 0)
  {
    printf("通讯录为空,无法修改\n");
    return;
  }
  //查找
  printf("输入要修改的名字:>");
  scanf("%s", name);
  int ret = FindByName(pc, name);
  if (ret == -1)
  {
    printf("要修改的人不存在\n");
    return;
  }
  //修改
  assert(pc);
  printf("请输入名字\n");
  scanf("%s", pc->data[ret].name);//name是数组名,不用&
  printf("请输入年龄\n");
  scanf("%d", &(pc->data[ret].age));//
  printf("请输入性别\n");
  scanf("%s", pc->data[ret].sex);
  printf("请输入电话\n");
  scanf("%s", pc->data[ret].tele);
  printf("请输入地址\n");
  scanf("%s", pc->data[ret].addr);
  printf("修改成功\n");
}


信息太多,空间小了;信息太少,空间大了。怎么解决呢?动态内存管理!录入的个人信息,等程序结束之后,就不在了。因为数据是存放在内存中的,只要程序退出,掉电,都会丢失。怎么解决?文件存储,数据库。


  • 排序功能(名字和年龄排序两个方面)
  • 动态内存函数优化通讯录
  • C语言文件操作优化通讯录

这个等到我们学习完动态内存和文件操作再去讲解。 ✔✔✔✔✔最后,感谢大家的阅读,若有错误和不足,欢迎指正!希望大家都有好好学习,好好敲代码。好好生活哦。🆗

代码------→【gitee:唐棣棣 (TSQXG) - Gitee.com

联系------→【邮箱:2784139418@qq.com】

目录
相关文章
|
C语言
C语言——通讯录系统—基于 VS2022
C语言——通讯录系统—基于 VS2022
|
11月前
|
存储 C语言
探索C语言数据结构:利用顺序表完成通讯录的实现
本文介绍了如何使用C语言中的顺序表数据结构实现一个简单的通讯录,包括初始化、添加、删除、查找和保存联系人信息的操作,以及自定义结构体用于存储联系人详细信息。
137 2
|
11月前
|
存储 C语言
手把手教你用C语言实现通讯录管理系统
手把手教你用C语言实现通讯录管理系统
|
机器学习/深度学习 搜索推荐 程序员
C语言实现个人通讯录(功能优化)-2
C语言实现个人通讯录(功能优化)
113 0
C语言实现个人通讯录(功能优化)-2
|
存储 C语言 索引
C语言实现个人通讯录(功能优化)-1
C语言实现个人通讯录(功能优化)
125 0
C语言实现个人通讯录(功能优化)-1
|
C语言
C语言学习记录——通讯录(静态内存)
C语言学习记录——通讯录(静态内存)
74 2
|
存储 C语言
C语言实现通讯录
C语言实现通讯录
81 2
|
存储 C语言
C语言实验-动态顺序表实现简易通讯录(二)
在这个C语言实验中,你将实现一个简单的通讯录,它使用动态顺序表来存储联系人信息。
128 2
|
存储 C语言
C语言实验-动态顺序表实现简易通讯录(一)
本文介绍了使用C语言模拟实现通讯录的步骤,包括使用动态顺序表存储联系人信息,每个联系人包含姓名、性别、电话和住址。功能包括新增、查找、删除、修改和查看联系人信息,以及按关键词排序。代码示例展示了如何定义联系人结构体、通讯录顺序表,以及主函数中的菜单选择和输入处理。文章还强调了在读取用户输入时避免出现死循环的问题,并提供了初始化和销毁通讯录的函数,以及如何判断和增加通讯录容量的方法。
148 1
|
C语言
c语言小课设--通讯录(动态内存管理+可持久化数据)
c语言小课设--通讯录(动态内存管理+可持久化数据)