【C语言】通讯录的实现(静态, 动态, 文件)

简介: 【C语言】通讯录的实现(静态, 动态, 文件)

整体思路

本文将会用c语言实现一个通讯录的系统,并且存储若干人的信息,每个人的信息包括:姓名,性别,年龄,电话号码,住址。此通讯录系统的功能包括: 1.增加联系人 2.删除对应的联系人 3.查找联系人 4.修改联系人的信息 5.排序此通讯录 6.打印出通讯录每个人的信息


  1. 设置每一个联系人的结构体,里面存的是联系人的基本信息
  2. 然后我们想到联系人不止一个,这样就要开辟一个结构体类型的数组,然后还要有一个数字来存里面已经有了几个联系人,所以还要将这个结构体数组和数字再用一个结构体来存起来
  3. 最后就是各个细节的实现,注意:结构体传参是传址调用,这样少了重新开辟内存的一步,可以节省很多的时间。

主要函数功能:

  1. 初始化,构造出结构体数组
  2. 实现添加联系人的函数
  3. 实现删除联系人的函数
  4. 实现查找联系人的函数
  5. 实现修改联系人的函数
  6. 实现展示联系人的函数
  7. 实现排序联系人的函数


删除的思路:


删除联系人前,我们需要先判断用户输入的联系人是否存在,如果存在删除,不存在提示用户没有要删除的联系人

因此我们可以把检测联系人是否存在封装成一个函数中,如果存在,返回联系人在通讯录中的位置,不存在返回-1


添加的思路:

考虑是否需要添加容量的问题,如果需要就动态的添加内存

排序的思路:

排序就是根据我们前面学习的qsort函数来实现。

静态

直接上代码:

#define _CRT_SECURE_NO_WARNINGS
#define MAX 100
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct PeoInfo {
  char name[20];
  char sex[5];
  char tele[12];
  int age;
  char addr[30];
};
struct Contact {
  struct PeoInfo data[MAX];
  int sz;
};
//初始化
void initContact(struct Contact* pc) {
  pc->sz = 0;
  memset(pc->data, 0, MAX * sizeof(struct PeoInfo));
}
// 添加
void AddContact(struct Contact* pc) {
  if (pc->sz == MAX) {
    printf("通讯录已满,无法添加!\n");
    return;
  }
  else {
    printf("请输入名字>\n");
    scanf("%s", pc->data[pc->sz].name);
    printf("请输入性别>\n");
    scanf("%s", pc->data[pc->sz].sex);
    printf("请输入年龄>\n");
    scanf("%d", &pc->data[pc->sz].age);
    printf("请输入电话>\n");
    scanf("%s", pc->data[pc->sz].tele);
    printf("请输入家庭地址\n");
    scanf("%s", pc->data[pc->sz].addr);
    pc->sz++;
    printf("成功添加联系人\n");
  }
}
//显示
void ShowContact(struct Contact* pc) {
  for (int i = 0; i < pc->sz; i++) {
    printf("%s %s %d %s %s\n", pc->data[i].name,
      pc->data[i].sex,
      pc->data[i].age,
      pc->data[i].tele,
      pc->data[i].addr);
  }
}
static int FindByName(struct Contact* pc, char name[]) {
  for (int 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[20];
  printf("请输入要删除人的名字\n");
  scanf("%s", name);
  int ret = FindByName(pc, name);
  if (ret == -1) {
    printf("要删除的人不存在\n");
  }
  else {
    for (int i = ret; i < pc->sz - 1; i++) {
      pc->data[i] = pc->data[i + 1];
    }
    pc->sz--;
    printf("成功删除指定联系人\n");
  }
}
//查找
void SearchContact(struct Contact* pc) {
  char name[20];
  printf("请输入要查找人的名字\n");
  scanf("%s", name);
  int ret = FindByName(pc, name);
  if (ret == -1) {
    printf("联系人不存在\n");
  }
  else {
    printf("%s %s %d %s %s\n", pc->data[ret].name,
      pc->data[ret].sex,
      pc->data[ret].age,
      pc->data[ret].tele,
      pc->data[ret].addr);
  }
}
//修改
void ModifyContact(struct Contact* pc) {
  char name[20];
  printf("请输入要修改人的名字\n");
  scanf("%s", name);
  int ret = FindByName(pc, name);
  if (ret == -1) {
    printf("要修改的人不存在\n");
  }
  else {
    printf("请输入名字>\n");
    scanf("%s", pc->data[ret].name);
    printf("请输入性别>\n");
    scanf("%s", pc->data[ret].sex);
    printf("请输入年龄>\n");
    scanf("%d", &pc->data[ret].age);
    printf("请输入电话>\n");
    scanf("%s", pc->data[ret].tele);
    printf("请输入家庭地址\n");
    scanf("%s", pc->data[ret].addr);
    printf("修改成功\n");
  }
}
int cmp(const void* e1, const void* e2) {
  return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
}
//排序
void SortContact(struct Contact* pc) {
  qsort(pc->data, pc->sz, sizeof(struct PeoInfo), cmp);
}
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;
  struct Contact con;
  initContact(&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 :
      printf("选择错误\n");
      break;
    }
  } while (input);
}

这里的结构体传参,就像上篇文章提到的一样,传的是地址。

动态

#define _CRT_SECURE_NO_WARNINGS
#define MAX 100
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct PeoInfo {
  char name[20];
  char sex[5];
  char tele[12];
  int age;
  char addr[30];
};
struct Contact {
  struct PeoInfo* data;
  int sz;
  int capacity;
};
//初始化
void initContact(struct Contact* pc) {
  pc->data = (struct PeoInfo*)malloc(3 * sizeof(struct PeoInfo));
  if (pc == NULL) {
    printf("开辟失败\n");
  }
  pc->sz = 0;
  pc->capacity = 3;
}
// 添加
void AddContact(struct Contact* pc) {
  if (pc->sz == pc->capacity) {
    //增加容量
    struct PeoInfo* ptr = (struct PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo));
    if (ptr != NULL) {
      pc->data = ptr;
      pc->capacity += 2;
      printf("增容成功\n");
    }
    else {
      printf("调整失败\n");
      return;
    }
  }
  printf("请输入名字>\n");
  scanf("%s", pc->data[pc->sz].name);
  printf("请输入性别>\n");
  scanf("%s", pc->data[pc->sz].sex);
  printf("请输入年龄>\n");
  scanf("%d", &pc->data[pc->sz].age);
  printf("请输入电话>\n");
  scanf("%s", pc->data[pc->sz].tele);
  printf("请输入家庭地址\n");
  scanf("%s", pc->data[pc->sz].addr);
  pc->sz++;
  printf("成功添加联系人\n");
}
//显示
void ShowContact(struct Contact* pc) {
  for (int i = 0; i < pc->sz; i++) {
    printf("%s %s %d %s %s\n", pc->data[i].name,
      pc->data[i].sex,
      pc->data[i].age,
      pc->data[i].tele,
      pc->data[i].addr);
  }
}
static int FindByName(struct Contact* pc, char name[]) {
  for (int 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[20];
  printf("请输入要删除人的名字\n");
  scanf("%s", name);
  int ret = FindByName(pc, name);
  if (ret == -1) {
    printf("要删除的人不存在\n");
  }
  else {
    for (int i = ret; i < pc->sz - 1; i++) {
      pc->data[i] = pc->data[i + 1];
    }
    pc->sz--;
    printf("成功删除指定联系人\n");
  }
}
//查找
void SearchContact(struct Contact* pc) {
  char name[20];
  printf("请输入要查找人的名字\n");
  scanf("%s", name);
  int ret = FindByName(pc, name);
  if (ret == -1) {
    printf("联系人不存在\n");
  }
  else {
    printf("%s %s %d %s %s\n", pc->data[ret].name,
      pc->data[ret].sex,
      pc->data[ret].age,
      pc->data[ret].tele,
      pc->data[ret].addr);
  }
}
//修改
void ModifyContact(struct Contact* pc) {
  char name[20];
  printf("请输入要修改人的名字\n");
  scanf("%s", name);
  int ret = FindByName(pc, name);
  if (ret == -1) {
    printf("要修改的人不存在\n");
  }
  else {
    printf("请输入名字>\n");
    scanf("%s", pc->data[ret].name);
    printf("请输入性别>\n");
    scanf("%s", pc->data[ret].sex);
    printf("请输入年龄>\n");
    scanf("%d", &pc->data[ret].age);
    printf("请输入电话>\n");
    scanf("%s", pc->data[ret].tele);
    printf("请输入家庭地址\n");
    scanf("%s", pc->data[ret].addr);
    printf("修改成功\n");
  }
}
int cmp(const void* e1, const void* e2) {
  return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
}
//排序
void SortContact(struct Contact* pc) {
  qsort(pc->data, pc->sz, sizeof(struct PeoInfo), cmp);
}
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;
  struct Contact con;
  initContact(&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:
      free((&con)->data);
      (&con)->data = NULL;
      (&con)->capacity = 0;
      (&con)->sz = 0; 
      printf("退出通讯录\n");
      break;
    default:
      printf("选择错误\n");
      break;
    }
  } while (input);
}

这个思路是通讯录那个结构体里面多添加了一个变量,来表示容量,当通讯录里面的个数和容量相等是就要考虑增容。就用之前文章提到的malloc,realloc函数来实现。

文件

需求:

通讯录退出后,之前保存的不能丢,当下一次重新运行通讯录的时候,还能看到上次保存的信息。

具体分析:

退出的时候,把数据保存到文件中,当下一次运行的时候,再从文件中加载信息就可以了

#define _CRT_SECURE_NO_WARNINGS
#define MAX 100
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct PeoInfo {
   char name[20];
   char sex[5];
   char tele[12];
   int age;
   char addr[30];
};
struct Contact {
   struct PeoInfo* data;
   int sz;
   int capacity;
};
void LoadContact(struct Contact* pc) {
   FILE* pf = fopen("data.txt", "rb");
   if (pf == NULL) {
    perror("LoadContact::fopen");
    return;
   }
   struct PeoInfo tmp = { 0 };
   while (fread(&tmp, sizeof(struct PeoInfo), 1, pf)) {
    //考虑增容量的问题
    if (pc->sz == pc->capacity) {
      struct PeoInfo* ptr = (struct PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo));
      if (ptr != NULL) {
        pc->data = ptr;
        pc->capacity += 2;
        printf("增容成功\n");
      }
      else {
        printf("调整失败\n");
        return;
      }
    }
    pc->data[pc->sz] = tmp;
    pc->sz++;
   }
   fclose(pf);
   pf = NULL;
}
//初始化
void initContact(struct Contact* pc) {
   pc->data = (struct PeoInfo*)malloc(3 * sizeof(struct PeoInfo));
   if (pc == NULL) {
    printf("开辟失败\n");
   }
   pc->sz = 0;
   pc->capacity = 3;
   //加载文件中的信息到通讯录
   LoadContact(pc);
}
// 添加
void AddContact(struct Contact* pc) {
   if (pc->sz == pc->capacity) {
    //增加容量
    struct PeoInfo* ptr = (struct PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo));
    if (ptr != NULL) {
      pc->data = ptr;
      pc->capacity += 2;
      printf("增容成功\n");
    }
    else {
      printf("调整失败\n");
      return;
    }
   }
   printf("请输入名字>\n");
   scanf("%s", pc->data[pc->sz].name);
   printf("请输入性别>\n");
   scanf("%s", pc->data[pc->sz].sex);
   printf("请输入年龄>\n");
   scanf("%d", &pc->data[pc->sz].age);
   printf("请输入电话>\n");
   scanf("%s", pc->data[pc->sz].tele);
   printf("请输入家庭地址\n");
   scanf("%s", pc->data[pc->sz].addr);
   pc->sz++;
   printf("成功添加联系人\n");
}
//显示
void ShowContact(struct Contact* pc) {
   for (int i = 0; i < pc->sz; i++) {
    printf("%s %s %d %s %s\n", pc->data[i].name,
      pc->data[i].sex,
      pc->data[i].age,
      pc->data[i].tele,
      pc->data[i].addr);
   }
}
static int FindByName(struct Contact* pc, char name[]) {
   for (int 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[20];
   printf("请输入要删除人的名字\n");
   scanf("%s", name);
   int ret = FindByName(pc, name);
   if (ret == -1) {
    printf("要删除的人不存在\n");
   }
   else {
    for (int i = ret; i < pc->sz - 1; i++) {
      pc->data[i] = pc->data[i + 1];
    }
    pc->sz--;
    printf("成功删除指定联系人\n");
   }
}
//查找
void SearchContact(struct Contact* pc) {
   char name[20];
   printf("请输入要查找人的名字\n");
   scanf("%s", name);
   int ret = FindByName(pc, name);
   if (ret == -1) {
    printf("联系人不存在\n");
   }
   else {
    printf("%s %s %d %s %s\n", pc->data[ret].name,
      pc->data[ret].sex,
      pc->data[ret].age,
      pc->data[ret].tele,
      pc->data[ret].addr);
   }
}
//修改
void ModifyContact(struct Contact* pc) {
   char name[20];
   printf("请输入要修改人的名字\n");
   scanf("%s", name);
   int ret = FindByName(pc, name);
   if (ret == -1) {
    printf("要修改的人不存在\n");
   }
   else {
    printf("请输入名字>\n");
    scanf("%s", pc->data[ret].name);
    printf("请输入性别>\n");
    scanf("%s", pc->data[ret].sex);
    printf("请输入年龄>\n");
    scanf("%d", &pc->data[ret].age);
    printf("请输入电话>\n");
    scanf("%s", pc->data[ret].tele);
    printf("请输入家庭地址\n");
    scanf("%s", pc->data[ret].addr);
    printf("修改成功\n");
   }
}
int cmp(const void* e1, const void* e2) {
   return ((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age;
}
//排序
void SortContact(struct Contact* pc) {
   qsort(pc->data, pc->sz, sizeof(struct PeoInfo), cmp);
}
void SaveContact(struct Contact* pc) {
   FILE* pf = fopen("data.txt", "wb");
   if (pf == NULL) {
    perror("SaveContact::fopen");
    return;
   }
   for (int i = 0; i < pc->sz; i++) {
    fwrite(pc->data + i, sizeof(struct PeoInfo), 1, pf);
   }
   fclose(pf);
   pf = NULL;
} 
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;
   struct Contact con;
   initContact(&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:
      SaveContact(&con);
      free((&con)->data);
      (&con)->data = NULL;
      (&con)->capacity = 0;
      (&con)->sz = 0;
      printf("退出通讯录\n");
      break;
    default:
      printf("选择错误\n");
      break;
    }
   } while (input);
}

文件操作终于学了,这篇文章也到了真正收尾的时候啦

相关文章
|
11月前
|
存储 编译器 程序员
c语言的文件操作与文件缓冲区
如果没有文件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运行程序,是看不到上次程序的数据的,如果要将数据进行持久化的保存,我们可以使用文件。磁盘(硬盘)上的文件是文件。但是在程序设计中,我们⼀般谈的⽂件有两种:程序文件、数据文件(从文件功能的角度来分类 的)。就比如说我们电脑中以.txt为后缀的就是文件的一种,他就是数据文件。.exe为后缀的就为程序文件。函数名功能适用范围fgetc字符输入函数所有输入流fputc字符输出函数所有输出流fgets。
385 0
|
人工智能 C语言
|
存储 小程序 C语言
【C语言程序设计——文件】文件操作(头歌实践教学平台习题)【合集】
本文介绍了C语言中的文件操作,分为两个关卡。第1关任务是将键盘输入的字符(以#结束)存入`file1.txt`并显示输出;第2关任务是从键盘输入若干行文本(每行不超过80个字符,用-1作为结束标志),写入`file2.txt`后再读取并显示。文中详细讲解了文件的打开、读取(使用`fgetc()`和`fgets()`)、写入(使用`fputc()`和`fputs()`)及关闭操作,并提供了示例代码和测试说明。
461 5
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
917 3
|
存储 编译器 C语言
如何在 C 语言中判断文件缓冲区是否需要刷新?
在C语言中,可以通过检查文件流的内部状态或使用`fflush`函数尝试刷新缓冲区来判断文件缓冲区是否需要刷新。通常,当缓冲区满、遇到换行符或显式调用`fflush`时,缓冲区会自动刷新。
|
存储 编译器 C语言
C语言:文件缓冲区刷新方式有几种
C语言中文件缓冲区的刷新方式主要包括三种:自动刷新(如遇到换行符或缓冲区满)、显式调用 fflush() 函数强制刷新、以及关闭文件时自动刷新。这些方法确保数据及时写入文件。
|
存储 C语言
探索C语言数据结构:利用顺序表完成通讯录的实现
本文介绍了如何使用C语言中的顺序表数据结构实现一个简单的通讯录,包括初始化、添加、删除、查找和保存联系人信息的操作,以及自定义结构体用于存储联系人详细信息。
244 2
|
C语言
【C语言】探索文件读写函数的全貌(三)
【C语言】探索文件读写函数的全貌
137 2
|
存储 C语言
【C语言】探索文件读写函数的全貌(二)
【C语言】探索文件读写函数的全貌
181 2
|
存储 C语言
手把手教你用C语言实现通讯录管理系统
手把手教你用C语言实现通讯录管理系统