抽丝剥茧C语言(高阶)动态+文件通讯录(下)

简介: 抽丝剥茧C语言(高阶)动态+文件通讯录

动态文件通讯录

无论是静态通讯录还是动态的通讯录其实都是在内存里面,第二次打开后之前的数据就全都没有了,那么这次我们让数据储存到文件里。

contacts.c

void stockpilecontact(contacts* pc)
{
  assert(pc != NULL);
  FILE* p1 = fopen("contacts.txt", "wb");//打开文件,以二进制方式写
  if (p1 == NULL)
  {
    perror("SaveContact");
    return;
  }
  int i = 0;
  for (i = 0; i < pc->count; i++)//输入通讯录中的成员信息
  {
    fwrite(pc->data + i, sizeof(person), 1, p1);
  }
  fclose(p1);//关闭文件
  p1 = NULL;
}

运行之后我们添加三个人的信息

然后打开我们的文件目录来看看:

这个就是我们刚刚生成的文件,里面有我们输入三个联系人的信息:

有些地方是乱码看不懂是因为这是以二进制形式输入。

现在我们想办法让这个通讯录读取这些联系人。

打开文件的地方当然要在初始化通讯录的时候读取文件内容。

读取要注意,我们把读取的联系人存在内存时,要先判断能不能放的下,放不下就要增容。

contacts.c

void capacity_increase(contacts* pc)//增容
{
  if (pc->count == pc->capacity)
  {
    person* str = (person*)realloc(pc->data, sizeof(person) * (pc->capacity + 2));
    if (str == NULL)
    {
      printf("addcontact:%s", strerror(errno));
      return 1;
    }
    else
    {
      pc->data = str;
      pc->capacity += 2;
    }
    printf("增容成功\n");
  }
}
void uploadcontacts(contacts* pc)//读取联系人函数
{
  FILE* p2 = fopen("contacts.txt", "rb");//打开文件二进制方式读
  if (p2 == NULL)
  {
    perror("OpenContacts");
    return 1;
  }
  person arr = { 0 };//文件读取数据的储存位置
  while (fread(&arr, sizeof(person), 1, p2))
  {
    capacity_increase(pc);//判断是否需要增容
    pc->data[pc->count] = arr;//存入内存中
    pc->count++;
  }
  fclose(p2);//关闭文件
  p2=NULL;
}
int initialize(contacts* pc)
{
  assert(pc != NULL);
  pc->count = 0;//将计数的变量初始化为0
  pc->data = (person*)calloc(3,sizeof(person));
  if (pc->data == NULL)
  {
    printf("initialize:%s",strerror(errno));
    return 1;
  }
  pc->capacity = 3;
  uploadcontacts(pc);// 读取通讯录
  return 0;
}

运行一下看看:

有上次输入的联系人。

我又添加了一个联系人,之后退出,再次打开然后展示:

完整版代码

contacts.h

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#define MAX 100//通讯录最大人数
//定义的结构体
typedef struct person
{
  char name[20];//名字
  int age;//年龄
  char sex[20];//性别
  char phone[20];//电话
  char location[20];//住址
}person;
typedef struct contacts
{
  person* data;//存放人信息的位置
  int count;//记录通讯录的人数
  int capacity;//记录当前通讯录有多少人
}contacts;
//函数声明区
int initialize(contacts* pc);//初始化通讯录
int addcontact(contacts* pc);//输入联系人信息
void showcontact(const contacts* pc);//打印通讯录
int delcontact(contacts* pc);//删除联系人
int modifycontact(contacts* pc);//修改联系人信息
int findcontact(contacts* pc);//查找联系人
void sortcontact(contacts* pc);//排序通讯录
void destroycontact(contacts* pc);//动态内存销毁
void stockpilecontact(contacts* pc);//储存到文件里
void uploadcontacts(contacts* pc);//读取文件

contacts.c

#include "contacts.h"
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;
}
void capacity_increase(contacts* pc)//增容
{
  if (pc->count == pc->capacity)
  {
    person* str = (person*)realloc(pc->data, sizeof(person) * (pc->capacity + 2));
    if (str == NULL)
    {
      printf("addcontact:%s", strerror(errno));
      return 1;
    }
    else
    {
      pc->data = str;
      pc->capacity += 2;
    }
    printf("增容成功\n");
  }
}
void uploadcontacts(contacts* pc)//读取联系人函数
{
  FILE* p2 = fopen("contacts.txt", "rb");//打开文件二进制方式读
  if (p2 == NULL)
  {
    perror("OpenContacts");
    return 1;
  }
  person arr = { 0 };
  while (fread(&arr, sizeof(person), 1, p2))
  {
    capacity_increase(pc);//判断是否需要增容
    pc->data[pc->count] = arr;
    pc->count++;
  }
  fclose(p2);//关闭文件
  p2 = NULL;
}
int initialize(contacts* pc)
{
  assert(pc != NULL);
  pc->count = 0;//将计数的变量初始化为0
  pc->data = (person*)calloc(3,sizeof(person));
  if (pc->data == NULL)
  {
    printf("initialize:%s",strerror(errno));
    return 1;
  }
  pc->capacity = 3;
  uploadcontacts(pc);// 读取通讯录
  return 0;
}
int addcontact(contacts* pc)
{
  assert(pc != NULL);//断言pc指向的位置不是空指针
  capacity_increase(pc);//增容
  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);
  }
}
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("删除成功\n");
}
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");
}
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);
}
int estimate(const void* p1, const void* p2)
{
  return strcmp(((person*)p1)->name, ((person*)p2)->name);
}
void sortcontact(contacts* pc)
{
  assert(pc != NULL);
  qsort(pc->data, pc->count, sizeof(person), estimate);
  printf("排序成功\n");
}
void destroycontact(contacts* pc)
{
  assert(pc != NULL);
  free(pc->data);
  pc->data = NULL;
}
void stockpilecontact(contacts* pc)
{
  assert(pc != NULL);
  FILE* p1 = fopen("contacts.txt", "wb");//打开文件,以二进制方式写
  if (p1 == NULL)
  {
    perror("SaveContact");
    return;
  }
  int i = 0;
  for (i = 0; i < pc->count; i++)//输入通讯录中的成员信息
  {
    fwrite(pc->data + i, sizeof(person), 1, p1);
  }
  fclose(p1);//关闭文件
  p1 = NULL;
}

test.c

#include "contacts.h"
enum list
{
  EXIT,
  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://退出程序
      stockpilecontact(&con);
      destroycontact(&con);
      printf("退出通讯录\n");
      break;
    case ADD://添加联系人
      addcontact(&con);
      break;
    case DEL://删除联系人
      delcontact(&con);
      break;
    case FIND://查找联系人
      findcontact(&con);
      break;
    case MODIFY://修改联系人信息
      modifycontact(&con);
      break;
    case SHOW://展示联系人
      showcontact(&con);
      break;
    case SORT://排序通讯录
      sortcontact(&con);
      break;
    default:
      printf("输入错误请重新输入\n");
    }
  } while (n);
  return 0;
}


相关文章
|
1天前
|
存储 小程序 C语言
【C语言程序设计——文件】文件操作(头歌实践教学平台习题)【合集】
本文介绍了C语言中的文件操作,分为两个关卡。第1关任务是将键盘输入的字符(以#结束)存入`file1.txt`并显示输出;第2关任务是从键盘输入若干行文本(每行不超过80个字符,用-1作为结束标志),写入`file2.txt`后再读取并显示。文中详细讲解了文件的打开、读取(使用`fgetc()`和`fgets()`)、写入(使用`fputc()`和`fputs()`)及关闭操作,并提供了示例代码和测试说明。
16 5
|
2月前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
150 3
|
3月前
|
存储 编译器 C语言
如何在 C 语言中判断文件缓冲区是否需要刷新?
在C语言中,可以通过检查文件流的内部状态或使用`fflush`函数尝试刷新缓冲区来判断文件缓冲区是否需要刷新。通常,当缓冲区满、遇到换行符或显式调用`fflush`时,缓冲区会自动刷新。
|
3月前
|
存储 编译器 C语言
C语言:文件缓冲区刷新方式有几种
C语言中文件缓冲区的刷新方式主要包括三种:自动刷新(如遇到换行符或缓冲区满)、显式调用 fflush() 函数强制刷新、以及关闭文件时自动刷新。这些方法确保数据及时写入文件。
|
3月前
|
存储 C语言
探索C语言数据结构:利用顺序表完成通讯录的实现
本文介绍了如何使用C语言中的顺序表数据结构实现一个简单的通讯录,包括初始化、添加、删除、查找和保存联系人信息的操作,以及自定义结构体用于存储联系人详细信息。
45 2
|
3月前
|
C语言
【C语言】探索文件读写函数的全貌(三)
【C语言】探索文件读写函数的全貌
|
3月前
|
存储 C语言
【C语言】探索文件读写函数的全貌(二)
【C语言】探索文件读写函数的全貌
|
3月前
|
存储 C语言
手把手教你用C语言实现通讯录管理系统
手把手教你用C语言实现通讯录管理系统
|
1天前
|
算法 C语言
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
25 15
|
1天前
|
C语言
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
36 24