抽丝剥茧C语言(高阶)静态通讯录(上)

简介: 抽丝剥茧C语言(高阶)静态通讯录

通讯录目录

用C语言模拟出来一个通讯录,首先要分头文件和源文件的,我这里分了一个头文件和两个源文件:

test.c这里用于存放主函数和调用其他函数,contacts.c用于存放通讯录的各种功能函数,contacts.h用于存放引用头文件的代码和自定义函数的声明和预处理指令。

首先,我们写的通讯录鸭油7个功能:

添加联系人,删除联系人,修改联系人的信息,查找联系人,展示通讯录联系人,排序通讯录中的联系人,退出通讯录。

test.c

#include "contacts.h"
enum list
{
  exit,//默认值为0
  add,
  del,
  modify,
  find,
  show,
  sort
};
void catalogue()
{
  printf("*********************************\n");
  printf("***   1.add        2.del      ***\n");
  printf("***   3.modify     4.find     ***\n");
  printf("***   5.show       6.sort     ***\n");
  printf("***   0.exit                  ***\n");
  printf("*********************************\n");
}
int main()
{
  int n = 0;
  do
  {
    catalogue();//通讯录菜单
    printf("请选择>");
    scanf("%d", &n);//选择要做什么
    switch (n)
    {
    case exit://退出程序
      printf("退出通讯录");
      break;
    case add://添加联系人
      break;
    case del://删除联系人
      break;
    case find://查找联系人
      break;
    case modify://修改联系人信息
      break;
    case show://展示联系人
      break;
    case sort://排序通讯录
      break;
    default:
      printf("输入错误请重新输入\n");
    }
  } while (n);
  return 0;
}

Contacts.c

#include "contacts.h"

Contacts.h

#include <stdio.h>

运行起来看一下效果:

下面我们就着手安排剩下的功能。

初始化通讯录

首先我们要想一下,通讯录里面的联系人个人信息都有什么,我自己定义的有,名字,年龄,性别,电话,住址。

因为通讯录里面要储存一些联系人,联系人又分这些信息,那么我们用构造体来定义一个联系人再合适不过。

Contacts.h

//定义的结构体
typedef struct person
{
  char name[20];//名字
  int age;//年龄
  char sex[20];//性别
  char phone[20];//电话
  char location[20];//住址
}person;

这是联系人的类型,那么一个通讯录我们假设能储存一百个人,那么还需要有一个变量来计算一下通讯录当前有多少人才行。

Contacts.h

typedef struct contacts
{
  person data[100];//存放人信息的位置
  int count;//记录通讯录的人数
}contacts;

这里因为data和count是维护整个通讯录的关键变量,count是根据date里面的元素数量变化而变化,放在一个结构体里面更方便用。

然后整个程序就是这样子的:

Contacts.h

#include <stdio.h>
#include <string.h>
//定义的结构体
typedef struct person
{
  char name[20];//名字
  int age;//年龄
  char sex[20];//性别
  char phone[20];//电话
  char location[20];//住址
}person;
typedef struct contacts
{
  person data[100];//存放人信息的位置
  int count;//记录通讯录的人数
}contacts;
//函数声明区
void initialize(contacts* pc);//初始化通讯录

Contacts.c

#include "contacts.h"
void initialize(contacts* pc)
{
  pc->count = 0;//将计数的变量初始化为0
  memset(pc->data, 0, sizeof(pc->data));//将数组里面的内容都初始化为0
}

test.c

#include "contacts.h"
enum list
{
  exit,//默认值为0
  add,
  del,
  modify,
  find,
  show,
  sort
};
void catalogue()
{
  printf("*********************************\n");
  printf("***   1.add        2.del      ***\n");
  printf("***   3.modify     4.find     ***\n");
  printf("***   5.show       6.sort     ***\n");
  printf("***   0.exit                  ***\n");
  printf("*********************************\n");
}
int main()
{
  int n = 0;
  contacts con;//通讯录
  initialize(&con);//初始换通讯录
  do
  {
    catalogue();//通讯录菜单
    printf("请选择>");
    scanf("%d", &n);//选择要做什么
    switch (n)
    {
    case exit://退出程序
      printf("退出通讯录");
      break;
    case add://添加联系人
      break;
    case del://删除联系人
      break;
    case find://查找联系人
      break;
    case modify://修改联系人信息
      break;
    case show://展示联系人
      break;
    case sort://排序通讯录
      break;
    default:
      printf("输入错误请重新输入\n");
    }
  } while (n);
  return 0;
}

这里我们初始化完成了。

这里要说一下,我们传结构体就要传结构体的地址,因为能节省内存。

(这里忘记添加assert函数来断言了,下面补上了)。

添加联系人和展示通讯录的联系人

添加联系人首先要先判断通讯录是不是人数已经满了,然后在contacts结构体中的person data[100]存放联系人的信息,从data[0]开始,那么count就是计算有多少个联系人,一开始也是0,多一个就++,那么count也对应了data数组的下标存放位置。

存放进去之后我们顺便也写一下打印函数,打印就很简单了,定义一个变量来当数组下标,小于count就可以了。

contacts.h

//函数声明区
void initialize(contacts* pc);//初始化通讯录
void addcontact(contacts* pc);//输入联系人信息
void showcontact(const contacts* pc);//打印通讯录,因为打印不需要修改里面的数值,所以用const修饰一下更安全

contacts.c

void addcontact(contacts* pc)
{
  assert(pc != NULL);//断言pc指向的位置不是空指针
  if (pc->count == MAX)
  {
    printf("通讯录已满\n");
    return 0;
  }
  printf("姓名:");
  scanf("%s", pc->data[pc->count].name);//这里注意一下,数组名是首元素地址,所以不用取地址了
  printf("年龄:");
  scanf("%d", &(pc->data[pc->count].age));
  printf("性别:");
  scanf("%s", pc->data[pc->count].sex);
  printf("电话号:");
  scanf("%s", pc->data[pc->count].phone);
  printf("家庭住址:");
  scanf("%s", pc->data[pc->count].location);
  pc->count++;
  printf("增加成功\n");
}
void showcontact(const contacts* pc)
{
  assert(pc != NULL);
  int i = 0;
  printf("%-20s\t%-20s\t%-20s\t%-20s\t%-20\t\n", "姓名", "年龄","性别","电话号","家庭住址");
  for (i = 0; i < pc->count; i++)
  {
    printf("%-20s\t%-20d\t%-20s\t%-20s\t%-20\t\n", 
      pc->data[i].name, 
      pc->data[i].age, 
      pc->data[i].sex, 
      pc->data[i].phone, 
      pc->data[i].location);
  }
}

test.c

int main()
{
  int n = 0;
  contacts con;//通讯录
  initialize(&con);//初始换通讯录
  do
  {
    catalogue();//通讯录菜单
    printf("请选择>");
    scanf("%d", &n);//选择要做什么
    switch (n)
    {
    case exit://退出程序
      printf("退出通讯录");
      break;
    case add://添加联系人
      addcontact(&con);
      break;
    case del://删除联系人
      break;
    case find://查找联系人
      break;
    case modify://修改联系人信息
      break;
    case show://展示联系人
      showcontact(&con);
      break;
    case sort://排序通讯录
      break;
    default:
      printf("输入错误请重新输入\n");
    }
  } while (n);
  return 0;
}

来看一下效果:

删除联系人,修改联系人,查找联系人

这三个放在一起写比较方便,因为修改和删除需要先查找有没有这个联系人才可以操作,查找功能更不用说。

首先要写一个查找联系人的函数,用strcmp函数来查找你输入的名字在通讯录里有无。

删除联系人的函数:

contacts.c

int find_out(char* p1 , contacts* p2)
{
  assert(p1 != NULL);
  assert(p2 != NULL);
  int i = 0;
  for (i = 0; i < p2->count; i++)
  {
    if (!strcmp(p1, p2->data[i].name))//如果相等就返回0,前面加了!操作符,所以非零条件不成立
      return i;
  }
  return -1;
}
int delcontact(contacts* pc)
{
  assert(pc != NULL);
  char name[20] = { 0 };
  printf("输入此人姓名\n");
  scanf("%s", name);
  int i = find_out(name, pc);
  if (i == -1)
  {
    printf("无此人信息\n");
    return 1;
  }
  pc->count = pc->count - 1;
  while (i < pc->count)
  {
    pc->data[i] = pc->data[i + 1];//删除的过程
    i++;
  }
  printf("删除成功");
}

其实删除人的过程很简单,你选定的元素是data[i],然后被data[i+1]覆盖,data[i+1]被data[i+2]覆盖以此循环。

因为通过一个查找的逻辑找到了此人,所以通讯录的人就会少一人,那么count就会减一,这样让i<count就不会有问题了,如果count不减少,i=99,count=100,就会造成数组的越界访问,这样不好处理,所以我们直接让count- -,这样i最多也就是98,i+1=99;至于data[99]这个位置的元素怎么办,不用理会,上面的添加联系人和展示通讯录都是count进行很重要的操作,新添加的联系人会覆盖掉原来末尾中没有被位移的联系人信息;如果没有添加展示联系人的话根本不会打印出来末尾的那个联系人。

修改联系人就更容易了,直接将原来联系人的信息覆盖掉就可以了,等于无循环版本添加联系人函数。

修改联系人的函数:

contacts.c

int find_out(char* p1 , contacts* p2)
{
  assert(p1 != NULL);
  assert(p2 != NULL);
  int i = 0;
  for (i = 0; i < p2->count; i++)
  {
    if (!strcmp(p1, p2->data[i].name))//如果相等就返回0,前面加了!操作符,所以非零条件不成立
      return i;
  }
  return -1;
}
int modifycontact(contacts* pc)
{
  assert(pc != NULL);
  printf("输入此人姓名\n");
  char name[20] = { 0 };
  scanf("%s", name);
  int i = find_out(name, pc);
  if (i == -1)
  {
    printf("无此人信息\n");
    return 1;
  }
  printf("请输入要修改的信息\n");
  printf("姓名:");
  scanf("%s", pc->data[i].name);
  printf("年龄:");
  scanf("%d", &(pc->data[i].age));
  printf("性别:");
  scanf("%s", pc->data[i].sex);
  printf("电话号:");
  scanf("%s", pc->data[i].phone);
  printf("家庭住址:");
  scanf("%s", pc->data[i].location);
  printf("修改成功\n");
}

查找联系人的函数就是展示通讯录函数的无循环版本。

这是查找联系人的函数:

contacts.c

int find_out(char* p1 , contacts* p2)
{
  assert(p1 != NULL);
  assert(p2 != NULL);
  int i = 0;
  for (i = 0; i < p2->count; i++)
  {
    if (!strcmp(p1, p2->data[i].name))//如果相等就返回0,前面加了!操作符,所以非零条件不成立
      return i;
  }
  return -1;
}
int findcontact(contacts* pc)
{
  assert(pc != NULL);
  printf("输入此人姓名\n");
  char name[20] = { 0 };
  scanf("%s", name);
  int i = find_out(name, pc);
  if (i == -1)
  {
    printf("无此人信息\n");
    return 1;
  }
  printf("%-20s\t%-20s\t%-20s\t%-20s\t%-20\t\n", "姓名", "年龄", "性别", "电话号", "家庭住址");
  printf("%-20s\t%-20d\t%-20s\t%-20s\t%-20\t\n",
      pc->data[i].name,
      pc->data[i].age,
      pc->data[i].sex,
      pc->data[i].phone,
      pc->data[i].location);
}

这是代码运行的效果(写一点调试一点,这样就会让代码的bug容易修复):

相关文章
|
3月前
|
存储 C语言
探索C语言数据结构:利用顺序表完成通讯录的实现
本文介绍了如何使用C语言中的顺序表数据结构实现一个简单的通讯录,包括初始化、添加、删除、查找和保存联系人信息的操作,以及自定义结构体用于存储联系人详细信息。
51 2
|
3月前
|
存储 C语言
手把手教你用C语言实现通讯录管理系统
手把手教你用C语言实现通讯录管理系统
|
5月前
|
存储 搜索推荐 算法
【C语言】C语言—通讯录管理系统(源码)【独一无二】
【C语言】C语言—通讯录管理系统(源码)【独一无二】
102 2
|
5月前
|
存储 数据可视化 C语言
【C语言】C语言 手机通讯录系统的设计 (源码+数据+论文)【独一无二】
【C语言】C语言 手机通讯录系统的设计 (源码+数据+论文)【独一无二】
|
7月前
|
机器学习/深度学习 搜索推荐 程序员
C语言实现个人通讯录(功能优化)-2
C语言实现个人通讯录(功能优化)
|
7月前
|
存储 C语言 索引
C语言实现个人通讯录(功能优化)-1
C语言实现个人通讯录(功能优化)
C语言实现个人通讯录(功能优化)-1
|
7月前
|
存储 人机交互 C语言
【C语言项目实战】使用单链表实现通讯录
【C语言项目实战】使用单链表实现通讯录
|
16天前
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
52 23
|
16天前
|
算法 C语言
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
46 15
|
16天前
|
C语言
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
54 24

热门文章

最新文章