动态版通讯录

简介: 动态版通讯录

一.通讯录的准备工作


首先我们要想一想开辟一个通讯录我们需要做哪些工作。要存放一些人的基本信息(名字+性别+年龄+电话+住址),增加联系人,删除联系人,修改联系人,查找联系人,最后要存入文档以便找不到。

这里我们建立了三个文件,第一个头文件是"contact.h"用于函数的声明,全局变量的定义;第二个是“contact.c"用于实现头文件所声明函数的功能;第三个是"test.c"用于测试函数。

下面我们将一个个与大家一起探讨学习:

二.通讯录的实现步骤


  • 创建主菜单
  • 在“test.c"中定义menu()函数创建主菜单,然后用户进行选择,用do..while进行循环,定义变量input进行输入数据,再用switch函数进行操作这里运用了枚举让其更加清晰。代码如下:
void menu()
{
  printf("******************************\n");
  printf("****  1. add     2. del  *****\n");
  printf("****  3. search  4. modify****\n");
  printf("****  5. show    0. exit   ***\n");
  printf("******************************\n");
}
enum Option {
  EXIT,
  ADD,
  DEL,
  SEARCH,
  MODIFY,
  SHOW
};
int main()
{
  int input = 0;
  do {
    menu();
    printf("请输入您的选择:");
    scanf("%d", &input);
    switch (input) {
    case ADD:
      break;
    case DEL:
      break;
    case SEARCH:
      break;
    case MODIFY:
      break;
    case SHOW:
      break;
    case EXIT:
      printf("退出通讯录\n");
      break;
    default:
      printf("选择错误\n");
      break;
    }
  } while (input);
  return 0;
}

image.png

  • 存放个人信息(静态)

我们假设先存放1000人的信息,信息包括:名字+性别+年龄+电话+住址;

在"contact.h"中,代码如下:

/描述个人的信息
struct PeoInfo {
  char name[30];
  int age;
  char sex[5];
  char tele[12];
  char addr[30];
};
//通讯录
struct Contact {
  struct PeoInfo data[1000];//1000个人的数据存放在data数组中;
  int sz;//记录当前通讯录有效信息的个数;
};

但是你会发现这样如果需要修改名字或者地址数组的大小会很麻烦,这时我们引用define预处理命令,进行宏定义,代码如下:

#define NAME_MAX 30
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30
#define MAX 1000
//描述个人的信息
struct PeoInfo {
  char name[NAME_MAX];
  int age;
  char sex[SEX_MAX];
  char tele[TELE_MAX];
  char addr[ADDR_MAX];
};
//通讯录
struct Contact {
  struct PeoInfo data[MAX];//1000个人的数据存放在data数组中;
  int sz;//记录当前通讯录有效信息的个数;
};

接下来需要进行初始化,将sz和data都初始化为0,默认没有信息。在"contact.c"中,代码如下:

void InitContact(struct Contact* pc)
{
  pc->sz = 0;//默认没有信息
  memset(pc->data, 0, sizeof(pc->data));//将data数组中的数据都初始化为0
}

这样修改过后明显会方便很多,但是还有不妥,这里我们定义data数组可以存放1000个人的数据,假设我们仅存放3个人的信息,这样将会浪费很多空间,有人说我们可以改成4,但是每次我们都要去根据存放的个数去实时的修改data数组存放的数据这样很麻烦,于是我们就想到了开辟一个动态空间,首先我们先给data数组3个存放空间,当空间不够时在运用realloc函数进行每2个2个空间的开辟,这样就不会造成空间浪费,而且操作起来也很方便。

  • 存放个人信息(动态)

修改后代码如下:

#define DEFAULT_SZ 3
#define NAME_MAX 30
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30
//#define MAX 1000
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//描述个人的信息
struct PeoInfo {
  char name[NAME_MAX];
  int age;
  char sex[SEX_MAX];
  char tele[TELE_MAX];
  char addr[ADDR_MAX];
};
//通讯录
struct Contact {
  struct PeoInfo* data;//1000个人的数据存放在data数组中;
  int sz;//记录当前通讯录有效信息的个数;
  int capcity;//当前通讯录的最大容量;
};

初始化:

void InitContact(struct Contact* pc)
{
  /*pc->sz = 0;
  memset(pc->data, 0, sizeof(pc->data));*/
  pc->data = (struct PeoInfo*)malloc(DEFAULT_SZ * sizeof(struct PeoInfo));
  pc->sz = 0;
  pc->capcity = DEFAULT_SZ;
}
  • 增加联系人(静态)

增加联系人首先判断存储空间是否满了,如果没满继续操作输入新人的名字+年龄+性别+电话+地址;在”contact.c"中代码如下:

void AddContact(struct Contact* pc) {
  if (pc->sz == MAX) {
    printf("通讯录满了\n");
  }
  else {
    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);
    printf("添加成功\n");
    pc->sz++;
  }
}
  • 增加联系人(动态)

需要新创建个CheckCapacity()来检测当前通讯录的容量,如果满了,就增加空间,如果不满,啥事也不做。

void CheckCapacity(struct Contact* pc) {
  if (pc->sz == pc->capacity) {
    //增容
    struct PeoInfo* ptr = realloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo));
    if (ptr != NULL) {
      pc->data = ptr;
      pc->capacity += 2;
      printf("增容成功\n");
    }
    else {
      printf("增容失败\n");
    }
  }
}
void AddContact(struct Contact* pc)
{
 //检测当前通讯录的容量
  //1.如果满了,就增加空间
  //2.如果不满,啥事不干
      CheckCapacity(pc);
        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);
    printf("添加成功\n");
    pc->sz++;
}
  • 显示联系人

代码如下:

void ShowContact(struct Contact* pc)
{
  int i = 0;
  //标题
  printf("%15s\t%5s\t%8s\t%15s\t%30s\n\n", "name", "age", "sex", "tele", "addr");
  for (i = 0; i < pc->sz; i++)
  {
    //打印每一个数据
    printf("%15s\t%5d\t%8s\t%15s\t%30s\n",
      pc->data[i].name,
      pc->data[i].age,
      pc->data[i].sex,
      pc->data[i].tele,
      pc->data[i].addr);
  }
}

我们接下来对上面编译的内容进行测试:

image.png

删除指定的联系人

通过分析会发现删除,查找,修改联系人都需要把输入的名字与通讯录存入的名字一一对比看是否有相同,为了方便起见我们这里统一定义一个FindName()函数使代码更简单。删除联系人我们只需要把后面的数据一一覆盖前一个数据直到指定的联系人,用for循环即可完成。

代码如下:

int FindName(struct Contact* pc, char name[NAME_MAX])
{
  int i = 0;
  for (i = 0; i < pc->sz; i++) {
    if (strcmp(pc->data[i].name, name) == 0) {
      return i;
    }
  }
  return -1;
}
void DelContact(struct Contact* pc)
{
  char name[NAME_MAX];
  int pos = 0;
  printf("请输入要删除人的名字:>");
  scanf("%s", &name);
  pos = FindName(pc, name);
  if (pos == -1) {
    printf("删除的人不存在\n");
  }
  else {
    int j = 0;
    for (j = pos; j < pc->sz - 1; j++) {
      pc->data[j] = pc->data[j + 1];
    }
    pc->sz--;
    printf("删除成功\n");
  }
}

image.png

  • 查找指定联系人
void SearchContact(struct Contact* pc) {
  char name[NAME_MAX];
  int pos = 0;
  printf("请输入要查找人的名字:>");
  scanf("%s", name);
   pos = FindName(pc, name);
  if (pos == -1) {
    printf("要查找的人不存在\n");
  }
  else {
    printf("%15s\t%5s\t%8s\t%15s\t%30s\n\n", "name", "age", "sex", "tele", "addr");
      //打印每一个数据
      printf("%15s\t%5d\t%8s\t%15s\t%30s\n",
        pc->data[pos].name,
        pc->data[pos].age,
        pc->data[pos].sex,
        pc->data[pos].tele,
        pc->data[pos].addr);
  }
}

image.png

  • 修改指定的联系人
void ModifyContact(struct Contact* pc)
{
  char name[NAME_MAX];
  int pos = 0;
  printf("请输入要修改人的名字\n");
  scanf("%s", name);
  pos = FindName(pc, name);
  if (pos == -1) {
    printf("要修改人的信息不存在\n");
  }
  else {
    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");
  }
}

image.png

静态的通讯录到这基本也就结束了,而动态通讯录则需要进行对空间的销毁。

  • 销毁通讯录(动态)
void DestroyContact(struct Contact* pc)
{
  free(pc->data);
  pc->data = NULL;
}

三.源代码(动态)


contact.h

#pragma once
#define DEFAULT_SZ 3
#define NAME_MAX 30
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//描述个人的信息
struct PeoInfo {
  char name[NAME_MAX];
  int age;
  char sex[SEX_MAX];
  char tele[TELE_MAX];
  char addr[ADDR_MAX];
};
//通讯录
struct Contact {
  struct PeoInfo* data;//1000个人的数据存放在data数组中;
  int sz;//记录当前通讯录有效信息的个数;
  int capcity;//当前通讯录的最大容量;
};
//初始化通讯录
void InitContact(struct Contact* pc);
//增加联系人
void AddContact(struct Contact* pc);
//显示所有的联系人
void ShowContact(struct Contact* pc);
//删除指定联系人
void DelContact(struct Contact* pc);
//查找指定的联系人
void SearchContact(struct Contact* pc);
//修改指定的联系人
void ModifyContact(struct Contact* pc);
//销毁
void DestroyContact(struct Contact* pc);

contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void InitContact(struct Contact* pc)
{
  pc->data = (struct PeoInfo*)malloc(DEFAULT_SZ * sizeof(struct PeoInfo));
  if (pc->data == NULL) {
    return 0;
  }
  pc->sz = 0;
  pc->capcity = DEFAULT_SZ;
}
void CheckCapacity(struct Contact* pc) {
  if (pc->sz == pc->capcity) {
    struct PeoInfo* ptr = realloc(pc->data, (pc->capcity + 2)*sizeof(struct PeoInfo));
    if (ptr != NULL) {
      pc->data = ptr;
      pc->capcity += 2;
      printf("增容成功\n");
    }
    else {
      printf("增容失败\n");
    }
  }
}
void AddContact(struct Contact* pc) {
  CheckCapacity(pc);
  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);
  printf("添加成功\n");
  pc->sz++;
}
void ShowContact(struct Contact* pc)
{
  int i = 0;
  //标题
  printf("%15s\t%5s\t%8s\t%15s\t%30s\n\n", "name", "age", "sex", "tele", "addr");
  for (i = 0; i < pc->sz; i++)
  {
    //打印每一个数据
    printf("%15s\t%5d\t%8s\t%15s\t%30s\n",
      pc->data[i].name,
      pc->data[i].age,
      pc->data[i].sex,
      pc->data[i].tele,
      pc->data[i].addr);
  }
}
int FindName(struct Contact* pc, char name[NAME_MAX])
{
  int i = 0;
  for (i = 0; i < pc->sz; i++) {
    if (strcmp(pc->data[i].name, name) == 0) {
      return i;
    }
  }
  return -1;
}
void DelContact(struct Contact* pc)
{
  char name[NAME_MAX];
  int pos = 0;
  printf("请输入要删除人的名字:>");
  scanf("%s", &name);
  pos = FindName(pc, name);
  if (pos == -1) {
    printf("删除的人不存在\n");
  }
  else {
    int j = 0;
    for (j = pos; j < pc->sz - 1; j++) {
      pc->data[j] = pc->data[j + 1];
    }
    pc->sz--;
    printf("删除成功\n");
  }
}
void SearchContact(struct Contact* pc) {
  char name[NAME_MAX];
  int pos = 0;
  printf("请输入要查找人的名字:>");
  scanf("%s", name);
  pos = FindName(pc, name);
  if (pos == -1) {
    printf("要查找的人不存在\n");
  }
  else {
    printf("%15s\t%5s\t%8s\t%15s\t%30s\n\n", "name", "age", "sex", "tele", "addr");
    //打印每一个数据
    printf("%15s\t%5d\t%8s\t%15s\t%30s\n",
      pc->data[pos].name,
      pc->data[pos].age,
      pc->data[pos].sex,
      pc->data[pos].tele,
      pc->data[pos].addr);
  }
}
void ModifyContact(struct Contact* pc)
{
  char name[NAME_MAX];
  int pos = 0;
  printf("请输入要修改人的名字\n");
  scanf("%s", name);
  pos = FindName(pc, name);
  if (pos == -1) {
    printf("要修改人的信息不存在\n");
  }
  else {
    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");
  }
}
void DestroyContact(struct Contact* pc)
{
  free(pc->data);
  pc->data = NULL;
}

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    0. exit   ***\n");
  printf("******************************\n");
}
enum Option {
  EXIT,
  ADD,
  DEL,
  SEARCH,
  MODIFY,
  SHOW
};
int main()
{
  int input = 0;
  //创建通讯录
  struct Contact con;
  //初始化通讯录
  InitContact(&con);
  do {
    menu();
    printf("请输入您的选择:");
    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 EXIT:
      //销毁通讯录,释放动态开辟的内存
      DestroyContact(&con);
      printf("退出通讯录\n");
      break;
    default:
      printf("选择错误\n");
      break;
    }
  } while (input);
  return 0;
}

20210923160700925.gif

欲知如何文档操作,点个赞,且待下集咱们慢慢探讨!

相关文章
|
7月前
|
存储
通讯录(动态实现与文件优化版)
通讯录(动态实现与文件优化版)
51 1
【动态通讯录】
【动态通讯录】
47 0
【文件版&动态版通讯录】
【文件版&动态版通讯录】
38 0
|
存储
【静态通讯录】
【静态通讯录】
40 0
|
存储
通讯录(静态版)
通讯录(静态版)
109 0
|
C语言
C/【静态通讯录】
C/【静态通讯录】
静态通讯录
C语言学习——教你学会静态通讯录的实现(保姆级教程哦~)
动态版通讯录
来了朋友们,今天给大家分享的是动态版本的通讯录。这个动态版本的通讯录较静态版本的通讯录的好处是,动态版本的通讯录对空间的浪费较少,并且可以随时增加空间,使用更加灵活。其实基本逻辑是跟静态版本的通讯录是一样的。