数据结构项目实战——通讯录

本文涉及的产品
性能测试 PTS,5000VUM额度
函数计算FC,每月15万CU 3个月
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: C语言通讯录是一个使用C语言编写的简单程序,用于存储和管理联系人信息。该程序允许用户添加、删除、查找和显示通讯录中的联系人。每个联系人通常包括姓名、电话号码和电子邮件地址等基本信息。程序使用结构体来存储联系人信息,并使用数组或链表等数据结构来组织和管理通讯录。通过命令行界面与用户进行交互,用户可以通过输入命令来执行相应的操作。C语言通讯录程序可以用于个人或小型组织的信息管理,提高联系人信息的管理效率。

c语言通讯录


前言

C语言通讯录是一个使用C语言编写的简单程序,用于存储和管理联系人信息。该程序允许用户添加、删除、查找和显示通讯录中的联系人。每个联系人通常包括姓名、电话号码和电子邮件地址等基本信息。程序使用结构体来存储联系人信息,并使用数组或链表等数据结构来组织和管理通讯录。通过命令行界面与用户进行交互,用户可以通过输入命令来执行相应的操作。C语言通讯录程序可以用于个人或小型组织的信息管理,提高联系人信息的管理效率。


一、基于动态顺序表实现通讯录

C语言基础要求:结构体、动态内存管理、顺序表、文件操作

1 功能要求

  1. 至少能够存储100个人的通讯信息
  2. 能够保存用户信息:名字、性别、年龄、电话、地址等
  3. 增加联系人信息
  4. 删除指定联系人
  5. 查找制定联系人
  6. 修改指定联系人
  7. 显示联系人信息

2 代码实现

【思考1】⽤静态顺序表和动态顺序表分别如何实现

【思考2】如何保证程序结束后,历史通讯录信息不会丢失

二、具体代码实现

需要使用的头文件及宏定义

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>//使用断言所需的头文件
#define _CRT_SECURE_NO_WARNINGS 1 //VS所需要使用的,关于代码安全性的问题
#define Name_max 20 // 姓名 年龄 性别 电话 地址
#define Sex_max 20
#define Tele_max 20
#define Addr_max 20
#define People_max 100
#define Move_people 3

通讯录所需要的结构体

typedef struct contact
{
  char name[Name_max];
  char sex[Sex_max];
  char addr[Addr_max];
  int tele[Tele_max];
  int age;
}contact;
//静态
/*typedef struct people
{
  contact data[People_max];
  int count;
}people;*/
typedef struct people//动态
{
  contact* data;
  int count;
  int capity;
}people;

通讯录的初始化函数

//void Initcontact(people* pc);//初始化函数
int Initcontact(people* pc);//动态初始化函数
/*void Initcontact(people* pc)静态
{
  pc->count = 0;
  memset(pc->data, 0, People_max);//
}*/
//动态
int Initcontact(people* pc)//#define Name_max 20 // 姓名 年龄 性别 电话 地址
//#define Sex_max 20
//#define Tele_max 20
//#define Addr_max 20
//#define People_max 100
//#define Move_people 3
{
  pc->capity = Move_people;//将通讯录的容量设置成第一次的最大容量
  pc->count = 0;//通讯录里的人是0人
  pc->data = calloc(pc->capity, sizeof(contact));//开辟空间并将数据初始化为0
  if (pc->data == NULL)//开辟空间失败会报错
  {
    printf("%s", strerror(errno));//或者使用perror("pc->data");
    return 1;
  }
  //读取函数
  FILE* pt = fopen("test.txt", "rb");//以二进制可读打开文件
  if (pt == NULL)//没有文件会报错
  {
    perror("FileRead: ");
  }
  contact tep = { 0 };//结构体tep
  while (fread(&tep, sizeof(contact), 1, pt))//从文件中读取二进制结构体数据存放到tep中
  {
    if (pc->count == pc->capity)//读取数据超过容量,扩容
    {
      contact* ptr = (contact*)realloc(pc->data, (pc->capity + 2) * sizeof(contact));
      if (ptr == NULL)
      {
        printf("Addcontact: %s\n", strerror(errno));
        printf("增容失败");
      }
      else
      {
        printf("增容成功");
        pc->capity += 2;
        pc->data = ptr;
      }
    }
    pc->data[pc->count] = tep;
    pc->count++;
  }
  fclose(pt);//关闭文件
  pt = NULL;
  return 0;
}

通讯录的初始化函数是构建整个通讯录系统的基石,它负责在程序启动时创建和配置通讯录的基本结构和功能。这个函数的任务繁重且关键,因为它不仅要确保通讯录能够正常运作,还要为后续的数据添加、修改、删除等操作提供坚实的基础。

初始化函数首先会创建一个空的通讯录数据结构,这个结构通常是一个列表、数组或更复杂的数据结构,用于存储联系人信息。每个联系人信息可能包括姓名、电话号码、电子邮件地址等字段。接下来,函数会设置一些基本的参数,比如通讯录的最大容量、默认的排序方式等。

在创建了基本的数据结构之后,初始化函数还会进行一些必要的配置工作。例如,它可能会加载一些预设的联系人信息,或者从外部文件、数据库中导入已有的数据。这些配置操作确保了通讯录在启动时就包含了必要的信息,用户无需手动添加。

除了创建和配置数据结构,初始化函数还会初始化一些与用户界面相关的元素。例如,它可能会设置通讯录界面的布局、样式和交互逻辑,确保用户能够方便地查看和编辑联系人信息。

最后,初始化函数会进行一些错误处理和优化工作。它会检查数据结构的完整性和一致性,确保没有错误或不一致的数据存在。同时,它还会进行一些性能优化,比如对数据结构进行预分配、使用缓存等,以提高通讯录的响应速度和稳定性。

总的来说,通讯录的初始化函数是一个综合性的函数,它负责创建和配置通讯录的基本结构和功能,为后续的操作提供坚实的基础。通过精心设计和实现初始化函数,可以确保通讯录系统的稳定性和可靠性,为用户提供良好的使用体验。

通讯录的添加函数

void Addcontact(people* pc);//添加函数
void Addcontact(people* pc)
{
  /*if (pc->count == People_max)静态
  {
    printf("数据已满");
    return;
  }*/
  if (pc->count == pc->capity)//增容
  {
    contact* ptr = (contact*)realloc(pc->data, (pc->capity + 2) * sizeof(contact));
    if (ptr == NULL)
    {
      printf("Addcontact: %s\n", strerror(errno));
      printf("增容失败");
    }
    else
    {
      printf("增容成功");
      pc->capity += 2;
      pc->data = ptr;
    }
  }
  else
  {
    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].tele);
    printf("请输入地址:>");
    scanf("%s", pc->data[pc->count].addr);
    pc->count++;
    printf("添加成功\n");
  }
}

通讯录添加函数是手机应用中不可或缺的一部分,它为用户提供了便捷的联系人管理方式。当用户想要添加新的联系人时,这个功能就发挥了它的作用。

一个好的添加函数应该简单、直观,让用户能够轻松完成操作。除了基本的联系人信息外,通讯录添加函数还可以提供一些高级功能。这些功能可以进一步提升用户的体验,让他们能够更个性化地管理自己的通讯录。同时,这些功能也应该易于使用,不会给用户带来额外的负担。

在实现通讯录添加函数时,我们还需要考虑到数据的安全性和完整性。用户的通讯录信息是非常敏感的,因此在添加新联系人时,我们需要确保这些信息能够安全地存储和传输。此外,我们还需要对数据进行验证,确保添加的联系人信息是准确和完整的。

在实际应用中,通讯录添加函数通常会与其他功能相结合,如搜索功能、联系人详情页面等。这些功能可以为用户提供更全面的通讯录管理体验,让他们能够更方便地查找、编辑和删除联系人。

通讯录的删除函数

void Delectcontact(people* pc);//删除函数

比较函数

static int Findnum(people* pc, char name[])//static 放在函数前面表示只在这个文件下使用的函数,别的文件使用不了,具体的可以看下面,因为这个函数我是放在contact.c中使用的,可以结合下面具体的代码来看
{
  int i = 0;
  for (i = 0; i < pc->count; i++)
  {
    if (strcmp(pc->data[i].name, name) == 0)//字符串比较函数,主要是用来判断两个函数是否相等
    {
      return i;
    }
  }
  return -1;
}

主要函数

void Delectcontact(people* pc)
{
  char name[Name_max] = { 0 };
  if (pc->count == 0)
  {
    printf("无需删除");
    return;
  }
  printf("输入要删除的姓名");
  scanf("%s", name);
  int pos = Findnum(pc, name);//见上面比较函数
  if (pos == -1)
  {
    printf("无删除数据");
    return;
  }
  int i = 0;
  for (i = pos; i < pc->count - 1; i++)
  {
    pc->data[i] = pc->data[i + 1];
  }
  pc->count--;
  printf("删除成功");
}

C语言通讯录的删除函数通常涉及以下步骤:

  1. 接收输入:首先,用户需要输入要删除的联系人的信息,如姓名或ID。
  2. 遍历通讯录:然后,程序会遍历通讯录中的每个联系人,查找与输入信息匹配的联系人。
  3. 删除联系人:一旦找到匹配的联系人,程序会从通讯录中删除该联系人。这通常是通过移动其他联系人来填补删除的联系人的位置,或者通过减小通讯录的大小来实现。
  4. 更新通讯录:删除操作完成后,程序需要更新通讯录,以确保数据的准确性。
  5. 返回结果:最后,程序会返回一个消息,告知用户删除操作是否成功。

总的来说,C语言通讯录的删除函数通过接收用户输入,遍历通讯录,删除匹配的联系人,更新通讯录,并返回结果,实现了对通讯录中联系人的删除操作。

通讯录的查找函数

void Searchcontact(people* pc);//查找函数
void Searchcontact(people* pc)
{
  char name[Name_max] = { 0 };
  if (pc->count == 0)
  {
    printf("没有数据");
    return;
  }
  printf("输入要查找的姓名");
  scanf("%s", name);
  int pos = Findnum(pc, name);
  if (pos == -1)
  {
    printf("无查找的人");
    return;
  }
  else
  {
    printf("%-20s\t%-5s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
    //打印数据
    printf("%-20s\t%-5d\t%-5s\t%-12s\t%-20s\n",
      pc->data[pos].name,
      pc->data[pos].age,
      pc->data[pos].sex,
      pc->data[pos].tele,
      pc->data[pos].addr);
  }
}

通讯录的查找函数是手机或电脑等通讯设备中不可或缺的一部分。它的主要作用是根据用户提供的关键词或条件,快速定位到通讯录中的特定联系人。在这个信息时代,人们的社交圈不断扩大,通讯录中的联系人数量也随之增长,因此,一个高效、准确的查找函数显得尤为重要。

在设计通讯录查找函数时,需要考虑到多种因素。首先是查找速度。当用户输入关键词时,函数应该能够迅速筛选出符合条件的联系人,避免用户长时间等待。其次是查找准确性。函数需要确保筛选出的联系人确实符合用户输入的关键词或条件,避免出现误判或遗漏。

为了实现这些目标,开发者通常会采用一些先进的技术手段。例如,利用数据库索引技术,将通讯录中的联系人信息按照一定的规则进行分类和排序,从而提高查找速度。同时,还会采用智能匹配算法,对用户输入的关键词进行语义分析和处理,以提高查找准确性。

除了技术手段外,通讯录查找函数的设计还需要考虑到用户体验。例如,函数应该提供多种查找方式,如按姓名、按电话号码、按邮箱等,以满足用户的不同需求。同时,还应该提供模糊查找功能,允许用户输入不完整的关键词或拼音等,以提高查找的灵活性。

综上所述,查找函数很重要,本文将以关键词为基础,展现一下简单的查找函数应该怎么来写

通讯录的修改函数

void Modifycontact(people* pc);//修改函数
void Modifycontact(people* pc)
{
  char name[Name_max] = { 0 };
  if (pc->count == 0)
  {
    printf("无需修改");
    return;
  }
  printf("输入要修改的姓名");
  scanf("%s", name);
  int pos = Findnum(pc, name);
  if (pos == -1)
  {
    printf("无修改数据");
    return;
  }
  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");
}

通讯录的修改函数是通讯录管理系统中的一个核心功能,它允许用户根据需要对已存储的联系人信息进行更新和修正。在实际应用中,这个函数通常需要处理各种可能的异常情况,比如联系人信息不存在、输入数据格式错误等。

一个典型的修改函数实现可能包括以下几个步骤:

首先,函数会接收用户输入的新联系人信息,这通常包括姓名、电话号码、电子邮件地址等字段。然后,函数会检查输入的数据是否满足格式要求,比如电话号码是否符合常见的格式,电子邮件地址是否有效等。如果输入数据不符合要求,函数会返回错误信息,提示用户重新输入。

接下来,函数会根据用户提供的唯一标识符(如联系人ID或姓名)在通讯录数据库中查找对应的联系人记录。如果找不到匹配的记录,函数会返回错误信息,告知用户联系人不存在。

如果找到了匹配的记录,函数会进一步比较新旧信息,确定哪些字段发生了变化。然后,它会更新数据库中的联系人记录,将旧的信息替换为新的信息。在这个过程中,函数还会检查是否有必要的数据丢失或更改,如果有,它也会进行相应的处理。

最后,函数会返回一个确认信息,告知用户联系人信息已成功更新。同时,它还会提醒用户,如果需要进一步的操作或有其他问题,可以通过相应的接口或联系方式与系统管理员联系。

本文将以c语言学习阶段常用的形式来展示

通讯录的排序函数

void Qsortcontact(people* pc);//排序函数
int cmp_by_name(const void* e1, const void* e2)//按姓名来排
{
  return strcmp(((contact*)e1)->name, ((contact*)e2)->name);
}
int cmp_by_sex(const void* e1, const void* e2)//按性别来排
{
  return strcmp(((contact*)e1)->sex, ((contact*)e2)->sex);
}
int cmp_by_tele(const void* e1, const void* e2)//按电话来排
{
  return strcmp(((contact*)e1)->tele, ((contact*)e2)->tele);
}
int cmp_by_addr(const void* e1, const void* e2)//按地址来排
{
  return strcmp(((contact*)e1)->addr, ((contact*)e2)->addr);
}
int cmp_by_age(const void* e1, const void* e2)//按年龄来排
{
  return _stricmp(((contact*)e1)->age, ((contact*)e2)->age);
}
void Qsortcontact(people* pc)//排序函数
{
  char name[Name_max] = { 0 };
  printf("按照什么排序> \n");
  scanf("%s", name);
  if (strcmp(name, "姓名") == 0)//本文使用qsort函数来进行排序,qsort函数排序的本质是快速排序,想要了解qsort函数可以去看我之前的文章
  {
    qsort(pc->data, pc->count, sizeof(contact),cmp_by_name);
  }
  if (strcmp(name, "年龄") == 0)
  {
    qsort(pc->data, pc->count, sizeof(contact), cmp_by_age);
  }
  if (strcmp(name, "性别") == 0)
  {
    qsort(pc->data, pc->count, sizeof(contact), cmp_by_sex);
  }
  if (strcmp(name, "电话") == 0)
  {
    qsort(pc->data, pc->count, sizeof(contact), cmp_by_tele);
  }
  if (strcmp(name, "地址") == 0)
  {
    qsort(pc->data, pc->count, sizeof(contact), cmp_by_addr);
  }
  printf("排序完成");
}

c语言从入门到实战——回调函数与qsort的讲解和模拟实现

这篇文章写了我对qsort函数的讲解

通讯录的排序函数是手机或电脑中常用的一个功能,它根据特定的规则将联系人列表进行排序,使用户能够快速找到并联系到需要的人。然而,这个看似简单的功能背后,却蕴含了多种排序算法和逻辑思考。

首先,通讯录的排序可以根据不同的标准进行,比如姓名、电话号码、最后联系时间等。这就涉及到了选择排序算法的问题。对于姓名排序,我们通常会采用字典序,也就是按照字母表顺序进行排序。而对于电话号码排序,则需要考虑到数字的特殊性,可能采用数值排序算法更为合适。最后联系时间排序则需要一个时间戳来记录每次联系的时间,然后按照时间先后进行排序。

其次,通讯录的排序还需要考虑到用户的个性化需求。有些用户可能更习惯于按照姓名的拼音首字母进行排序,而有些用户则可能更喜欢按照电话号码的区号进行排序。因此,通讯录的排序函数需要支持用户自定义排序规则,以满足不同用户的需求。

此外,通讯录的排序还需要考虑到性能问题。当联系人数量庞大时,如果采用简单的冒泡排序等低效算法,可能会导致排序时间过长,影响用户体验。因此,通讯录的排序函数需要采用高效的排序算法,如快速排序、归并排序等,以提高排序速度。

最后,通讯录的排序函数还需要考虑到稳定性和易用性。稳定性是指排序过程中不会改变原有数据的顺序,这对于保持通讯录的原始结构非常重要。易用性则是指排序函数需要简单易懂,方便用户操作。

综上所述,通讯录的排序函数不仅仅是一个简单的功能,它涉及到了多种排序算法、用户个性化需求、性能优化以及稳定性和易用性等方面的考虑。只有在这些方面都做得足够好,才能为用户提供一个高效、方便、稳定的通讯录排序体验。

通讯录的打印函数

void Printcontact(people* pc);//打印函数
void Printcontact(people* pc)
{
  int i = 0;
  //打印标题
  printf("%-20s\t%-5s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
  //打印数据
  for (i = 0; i < pc->count; i++)
  {
    printf("%-20s\t%-5d\t%-5s\t%-12s\t%-20s\n",
      pc->data[i].name,
      pc->data[i].age,
      pc->data[i].sex,
      pc->data[i].tele,
      pc->data[i].addr);
  }
}

通讯录的打印函数是许多应用程序中不可或缺的一部分,它负责将存储在数据库或内存中的联系人信息以人类可读的形式展示出来。这个函数的设计和实现,不仅关系到用户界面的友好程度,还直接影响到程序的性能和效率。

在实现通讯录的打印函数时,首先要考虑的是数据的来源和格式。通讯录中的数据通常以结构化的方式存储,比如每个联系人可能包含姓名、电话号码、电子邮件地址等字段。这些数据可以存储在文件、数据库或内存中,而打印函数则需要从这些源中读取数据,并将其转换为适合展示的格式。

其次,打印函数还需要考虑如何呈现联系人信息。最简单的方式是将所有联系人的信息按照一定格式连续打印出来,例如按姓名排序或按添加时间排序。然而,在实际应用中,用户可能希望根据不同的条件筛选联系人,或者对联系人信息进行分组和排序。这就需要打印函数支持灵活的查询和排序功能。

此外,为了提高用户体验,打印函数还可以加入一些额外的功能。比如,可以为每个联系人信息添加高亮或颜色编码,以便用户更容易地识别重要信息或区分不同类型的联系人。还可以添加搜索功能,允许用户快速找到特定的联系人。

在实现这些功能时,需要注意程序的性能和效率。如果通讯录中包含大量的联系人信息,打印函数可能会消耗大量的计算资源和时间。因此,需要采用一些优化措施,比如使用高效的数据结构和算法,或者将部分计算任务异步处理,以避免阻塞用户界面。

内存返回函数

void Quitcoontact(people* pc);//内存返回函数
void Quitcoontact(people* pc)
{
  free(pc->data);
  pc->data = NULL;
}

内存返回函数是编程中常用的一个概念,它指的是一个函数在执行完毕后,将其所使用的内存空间返还给操作系统或其他需要使用的程序。在多数编程语言中,内存管理是一个重要且复杂的任务,因为它直接关系到程序的性能和稳定性。

当我们创建一个变量或对象时,系统会在内存中为其分配空间。随着程序的执行,这些内存块可能会被频繁地创建和销毁。如果没有有效的内存管理机制,这些不再使用的内存块会占用系统资源,导致内存泄漏和程序崩溃。

内存返回函数就是在这样的背景下诞生的。它的作用是在函数执行完毕后,自动释放函数内部创建的所有局部变量和动态分配的内存空间。这样,操作系统或其他程序就可以重新利用这些内存空间,提高了内存的使用效率。

在C语言中,内存返回通常是通过手动调用free()函数来实现的。而在一些高级语言如Python和Java中,内存管理则是自动进行的,程序员无需手动调用内存返回函数。

然而,即使在这些高级语言中,内存管理仍然是一个需要注意的问题。因为虽然语言本身提供了自动内存管理功能,但如果程序员不正确地使用数据结构和算法,仍然可能导致内存泄漏或其他问题。

因此,无论在哪种编程语言中,程序员都应该对内存管理有一个清晰的认识,并时刻关注程序的内存使用情况。只有这样,才能编写出高效、稳定、可靠的程序。

总之,内存返回函数是编程中不可或缺的一部分。它帮助程序员有效地管理内存资源,防止内存泄漏和程序崩溃。同时,程序员也应该在编程过程中时刻关注内存管理问题,确保程序的性能和稳定性。

数据保存函数

void Filewrite(people* pc);//数据保存函数
void Filewrite(people* pc)
{
  FILE* pf = fopen("test.txt", "wb");
  if (pf == NULL)
  {
    perror("Filewrite: ");
    return;
  }
  int i = 0; 
  /*for (i = 0; i < pc->count; i++)
  {
    fwrite(pc->data + i, sizeof(contact), 1, pf);
  }*/
  fwrite(pc->data, sizeof(contact), pc->count, pf);
  fclose(pf);
  pf = NULL;
}

数据保存函数是信息系统中至关重要的组成部分,它负责将处理后的数据以安全、有效的方式存储在计算机系统的硬盘或其他持久化存储介质中。在软件开发过程中,数据保存函数的设计和实现直接关系到数据的安全性和完整性,因此,编写一个稳健、高效的数据保存函数是每一个程序员都必须认真对待的任务。

编写数据保存函数时,我们首先要考虑的是数据的格式。不同的数据格式有不同的存储效率和读取速度,同时还会影响到数据在不同系统之间的兼容性。例如,对于大量结构化数据,我们通常会选择使用关系型数据库来存储,而对于非结构化数据或者需要高效读写的场景,可能会选择NoSQL数据库或者键值存储等方案。

在确定了数据格式之后,我们还需要考虑数据的安全性问题。这包括数据的加密、备份和恢复等方面。为了防止数据被非法访问或篡改,我们通常会对敏感数据进行加密处理,确保即使数据被窃取也无法被轻易解密。同时,为了防止数据丢失,我们还会定期备份数据,并测试备份数据的恢复能力,确保在数据出现问题时能够迅速恢复。

除了安全性和完整性之外,数据保存函数还需要考虑性能问题。在大数据环境下,数据的写入和读取操作可能会变得非常频繁,如果数据保存函数的设计不合理,可能会成为系统的瓶颈。因此,我们需要在设计数据保存函数时充分考虑其性能,可能需要采用异步处理、批量写入等技术来提高性能。

最后,数据保存函数还需要考虑错误处理和日志记录。在数据保存过程中,可能会出现各种错误,如磁盘空间不足、数据库连接失败等。我们需要为这些情况编写相应的错误处理代码,确保在出现错误时能够及时处理并记录日志,方便后续的故障排查和问题定位。

综上所述,数据保存函数的设计和实现是一个复杂而重要的任务,需要综合考虑数据格式、安全性、性能和错误处理等多个方面。只有在这些方面都做得足够好,才能确保数据的安全性和完整性,为信息系统的稳定运行提供坚实的保障。

枚举函数

enum num//通过使用枚举函数来实现函数的控制
{
  go,
  add,
  delect,
  search,
  modify,
  sort,
  show
};

枚举函数,作为一种编程中的重要工具,它的作用在于列出特定类型对象的所有可能值。在编程领域,枚举函数不仅提高了代码的可读性和可维护性,还有助于减少错误和增强代码的安全性。

在日常的软件开发中,枚举函数常常被用于处理那些具有固定、有限且明确值集合的数据类型。比如,一个表示星期几的数据类型,其值集合就是“星期一”、“星期二”一直到“星期日”。通过使用枚举函数,我们可以确保程序在处理这些数据时,不会出现意外的、不在预期范围内的值。

此外,枚举函数还能提高代码的健壮性。在复杂的程序中,有时需要对某种类型的数据进行多种不同的处理。如果这些数据的值没有明确的界限或定义,那么在处理过程中就很容易出现错误。通过使用枚举函数,我们可以清楚地定义这些数据的取值范围,并在代码中对每一种取值进行相应的处理,从而有效地避免这类错误的发生。

当然,枚举函数并不是万能的。在某些情况下,使用枚举函数可能会导致代码变得过于复杂或难以理解。比如,当需要表示的数据类型具有大量的可能值时,如果全部使用枚举函数进行定义,那么可能会导致代码变得冗长且难以维护。在这种情况下,可能需要考虑使用其他的数据结构或方法来进行处理。

总的来说,枚举函数是一种非常有用的编程工具,它可以帮助我们更好地处理和管理具有固定、有限且明确值集合的数据类型。但是,在使用枚举函数时,我们也需要根据具体的情况进行考虑和选择,以确保代码的质量和效率。

菜单函数

void menu()
{
  printf("************************************\n");
  printf("*****1.增添         2.删除**********\n");
  printf("************************************\n");
  printf("*****3.查找         4.修改**********\n");
  printf("************************************\n");
  printf("*****5.排序         6.显示**********\n");
  printf("*************0.退出*****************\n");
}

三、通讯录完整代码实现

contact.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define _CRT_SECURE_NO_WARNINGS 1
#define Name_max 20 // 姓名 年龄 性别 电话 地址
#define Sex_max 20
#define Tele_max 20
#define Addr_max 20
#define People_max 100
#define Move_people 3
typedef struct contact
{
  char name[Name_max];
  char sex[Sex_max];
  char addr[Addr_max];
  int tele[Tele_max];
  int age;
}contact;
//静态
/*typedef struct people
{
  contact data[People_max];
  int count;
}people;*/
typedef struct people
{
  contact* data;
  int count;
  int capity;
}people;
//void Initcontact(people* pc);//初始化函数
int Initcontact(people* pc);//动态初始化函数
void Addcontact(people* pc);//添加函数
void Delectcontact(people* pc);//删除函数
void Searchcontact(people* pc);//查找函数
void Modifycontact(people* pc);//修改函数
void Qsortcontact(people* pc);//排序函数
void Printcontact(people* pc);//打印函数
void Quitcoontact(people* pc);//内存返回函数
void Filewrite(people* pc);//数据保存函数

contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"
/*void Initcontact(people* pc)静态
{
  pc->count = 0;
  memset(pc->data, 0, People_max);
}*/
//动态
int Initcontact(people* pc)
{
  pc->capity = Move_people;
  pc->count = 0;
  pc->data = calloc(pc->capity, sizeof(contact));
  if (pc->data == NULL)
  {
    printf("%s", strerror(errno));
    return 1;
  }
  //读取函数
  FILE* pt = fopen("test.txt", "rb");
  if (pt == NULL)
  {
    perror("FileRead: ");
  }
  contact tep = { 0 };
  while (fread(&tep, sizeof(contact), 1, pt))
  {
    if (pc->count == pc->capity)
    {
      contact* ptr = (contact*)realloc(pc->data, (pc->capity + 2) * sizeof(contact));
      if (ptr == NULL)
      {
        printf("Addcontact: %s\n", strerror(errno));
        printf("增容失败");
      }
      else
      {
        printf("增容成功");
        pc->capity += 2;
        pc->data = ptr;
      }
    }
    pc->data[pc->count] = tep;
    pc->count++;
  }
  fclose(pt);
  pt = NULL;
  return 0;
}
void Addcontact(people* pc)
{
  /*if (pc->count == People_max)静态
  {
    printf("数据已满");
    return;
  }*/
  if (pc->count == pc->capity)
  {
    contact* ptr = (contact*)realloc(pc->data, (pc->capity + 2) * sizeof(contact));
    if (ptr == NULL)
    {
      printf("Addcontact: %s\n", strerror(errno));
      printf("增容失败");
    }
    else
    {
      printf("增容成功");
      pc->capity += 2;
      pc->data = ptr;
    }
  }
  else
  {
    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].tele);
    printf("请输入地址:>");
    scanf("%s", pc->data[pc->count].addr);
    pc->count++;
    printf("添加成功\n");
  }
}
static int Findnum(people* pc, char name[])
{
  int i = 0;
  for (i = 0; i < pc->count; i++)
  {
    if (strcmp(pc->data[i].name, name) == 0)
    {
      return i;
    }
  }
  return -1;
}
void Delectcontact(people* pc)
{
  char name[Name_max] = { 0 };
  if (pc->count == 0)
  {
    printf("无需删除");
    return;
  }
  printf("输入要删除的姓名");
  scanf("%s", name);
  int pos = Findnum(pc, name);
  if (pos == -1)
  {
    printf("无删除数据");
    return;
  }
  int i = 0;
  for (i = pos; i < pc->count - 1; i++)
  {
    pc->data[i] = pc->data[i + 1];
  }
  pc->count--;
  printf("删除成功");
}
void Searchcontact(people* pc)
{
  char name[Name_max] = { 0 };
  if (pc->count == 0)
  {
    printf("没有数据");
    return;
  }
  printf("输入要查找的姓名");
  scanf("%s", name);
  int pos = Findnum(pc, name);
  if (pos == -1)
  {
    printf("无查找的人");
    return;
  }
  else
  {
    printf("%-20s\t%-5s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
    //打印数据
    printf("%-20s\t%-5d\t%-5s\t%-12s\t%-20s\n",
      pc->data[pos].name,
      pc->data[pos].age,
      pc->data[pos].sex,
      pc->data[pos].tele,
      pc->data[pos].addr);
  }
}
void Modifycontact(people* pc)
{
  char name[Name_max] = { 0 };
  if (pc->count == 0)
  {
    printf("无需修改");
    return;
  }
  printf("输入要修改的姓名");
  scanf("%s", name);
  int pos = Findnum(pc, name);
  if (pos == -1)
  {
    printf("无修改数据");
    return;
  }
  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");
}
int cmp_by_name(const void* e1, const void* e2)
{
  return strcmp(((contact*)e1)->name, ((contact*)e2)->name);
}
int cmp_by_sex(const void* e1, const void* e2)
{
  return strcmp(((contact*)e1)->sex, ((contact*)e2)->sex);
}
int cmp_by_tele(const void* e1, const void* e2)
{
  return strcmp(((contact*)e1)->tele, ((contact*)e2)->tele);
}
int cmp_by_addr(const void* e1, const void* e2)
{
  return strcmp(((contact*)e1)->addr, ((contact*)e2)->addr);
}
int cmp_by_age(const void* e1, const void* e2)
{
  return _stricmp(((contact*)e1)->age, ((contact*)e2)->age);
}
void Qsortcontact(people* pc)
{
  char name[Name_max] = { 0 };
  printf("按照什么排序> \n");
  scanf("%s", name);
  if (strcmp(name, "姓名") == 0)
  {
    qsort(pc->data, pc->count, sizeof(contact),cmp_by_name);
  }
  if (strcmp(name, "年龄") == 0)
  {
    qsort(pc->data, pc->count, sizeof(contact), cmp_by_age);
  }
  if (strcmp(name, "性别") == 0)
  {
    qsort(pc->data, pc->count, sizeof(contact), cmp_by_sex);
  }
  if (strcmp(name, "电话") == 0)
  {
    qsort(pc->data, pc->count, sizeof(contact), cmp_by_tele);
  }
  if (strcmp(name, "地址") == 0)
  {
    qsort(pc->data, pc->count, sizeof(contact), cmp_by_addr);
  }
  printf("排序完成");
}
void Printcontact(people* pc)
{
  int i = 0;
  //打印标题
  printf("%-20s\t%-5s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
  //打印数据
  for (i = 0; i < pc->count; i++)
  {
    printf("%-20s\t%-5d\t%-5s\t%-12s\t%-20s\n",
      pc->data[i].name,
      pc->data[i].age,
      pc->data[i].sex,
      pc->data[i].tele,
      pc->data[i].addr);
  }
}
void Quitcoontact(people* pc)
{
  free(pc->data);
  pc->data = NULL;
}
void Filewrite(people* pc)
{
  FILE* pf = fopen("test.txt", "wb");
  if (pf == NULL)
  {
    perror("Filewrite: ");
    return;
  }
  int i = 0; 
  /*for (i = 0; i < pc->count; i++)
  {
    fwrite(pc->data + i, sizeof(contact), 1, pf);
  }*/
  fwrite(pc->data, sizeof(contact), pc->count, pf);
  fclose(pf);
  pf = NULL;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"
enum num
{
  go,
  add,
  delect,
  search,
  modify,
  sort,
  show
};
void menu()
{
  printf("************************************\n");
  printf("*****1.增添         2.删除**********\n");
  printf("************************************\n");
  printf("*****3.查找         4.修改**********\n");
  printf("************************************\n");
  printf("*****5.排序         6.显示**********\n");
  printf("*************0.退出*****************\n");
}
int main()
{
  int input = 0;
  people num;//定义结构体num
  Initcontact(&num);//结构体初始化
  do
  {
    menu();
    printf("请输入>");
    scanf("%d", &input);
    switch (input)
    {
    case add:Addcontact(&num); break;
    case delect:Delectcontact(&num); break;
    case search:Searchcontact(&num); break;
    case modify:Modifycontact(&num); break;
    case sort:Qsortcontact(&num); break;
    case show:Printcontact(&num); break;
    case go: Filewrite(&num); Quitcoontact(&num); break;
    default:
      printf("重新输入"); break;
    }
  } while(input);
  return 0;
}


相关文章
|
1月前
|
存储 C语言
探索C语言数据结构:利用顺序表完成通讯录的实现
本文介绍了如何使用C语言中的顺序表数据结构实现一个简单的通讯录,包括初始化、添加、删除、查找和保存联系人信息的操作,以及自定义结构体用于存储联系人详细信息。
19 2
|
6月前
|
存储
【数据结构】----顺序表项目-通讯录
【数据结构】----顺序表项目-通讯录
26 0
|
6月前
|
存储 算法 C语言
C语言进阶:顺序表(数据结构基础) (以通讯录项目为代码练习)
C语言进阶:顺序表(数据结构基础) (以通讯录项目为代码练习)
|
11月前
|
存储
数据结构——基于顺序表实现通讯录
数据结构——基于顺序表实现通讯录
129 0
|
存储 Java 数据安全/隐私保护
java数据结构基于哈希表的学生通讯录程序设计
利用哈希表的思想设计一个能快速查询的学生通讯录程序。每个学生的信息至少包括:学号(10个数字)、姓名(不超过20字符)、手机号码(11个数字)。程序主要功能:从键盘输入学生通讯录,以学号为关键字建立哈希表,酌情设计哈希函数和处理冲突的策略;采用哈希表方法根据输入的学号显示该学生的通讯录信息;能够修改学生的手机号码;能够添加和删除某个学生的通讯录信息。
109 0
|
15天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
90 9
|
6天前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
15 1
|
9天前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
12天前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
14天前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
42 4