抽丝剥茧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;
}


相关文章
|
5月前
|
存储 编译器 程序员
c语言的文件操作与文件缓冲区
如果没有文件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运行程序,是看不到上次程序的数据的,如果要将数据进行持久化的保存,我们可以使用文件。磁盘(硬盘)上的文件是文件。但是在程序设计中,我们⼀般谈的⽂件有两种:程序文件、数据文件(从文件功能的角度来分类 的)。就比如说我们电脑中以.txt为后缀的就是文件的一种,他就是数据文件。.exe为后缀的就为程序文件。函数名功能适用范围fgetc字符输入函数所有输入流fputc字符输出函数所有输出流fgets。
131 0
|
9月前
|
人工智能 C语言
|
10月前
|
存储 小程序 C语言
【C语言程序设计——文件】文件操作(头歌实践教学平台习题)【合集】
本文介绍了C语言中的文件操作,分为两个关卡。第1关任务是将键盘输入的字符(以#结束)存入`file1.txt`并显示输出;第2关任务是从键盘输入若干行文本(每行不超过80个字符,用-1作为结束标志),写入`file2.txt`后再读取并显示。文中详细讲解了文件的打开、读取(使用`fgetc()`和`fgets()`)、写入(使用`fputc()`和`fputs()`)及关闭操作,并提供了示例代码和测试说明。
275 5
|
12月前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
691 3
|
存储 编译器 C语言
如何在 C 语言中判断文件缓冲区是否需要刷新?
在C语言中,可以通过检查文件流的内部状态或使用`fflush`函数尝试刷新缓冲区来判断文件缓冲区是否需要刷新。通常,当缓冲区满、遇到换行符或显式调用`fflush`时,缓冲区会自动刷新。
|
存储 编译器 C语言
C语言:文件缓冲区刷新方式有几种
C语言中文件缓冲区的刷新方式主要包括三种:自动刷新(如遇到换行符或缓冲区满)、显式调用 fflush() 函数强制刷新、以及关闭文件时自动刷新。这些方法确保数据及时写入文件。
|
存储 C语言
探索C语言数据结构:利用顺序表完成通讯录的实现
本文介绍了如何使用C语言中的顺序表数据结构实现一个简单的通讯录,包括初始化、添加、删除、查找和保存联系人信息的操作,以及自定义结构体用于存储联系人详细信息。
169 2
|
2月前
|
存储 C语言
`scanf`是C语言中用于按格式读取标准输入的函数
`scanf`是C语言中用于按格式读取标准输入的函数,通过格式字符串解析输入并存入指定变量。需注意输入格式严格匹配,并建议检查返回值以确保读取成功,提升程序健壮性。
908 0
|
4月前
|
安全 C语言
C语言中的字符、字符串及内存操作函数详细讲解
通过这些函数的正确使用,可以有效管理字符串和内存操作,它们是C语言编程中不可或缺的工具。
301 15
|
10月前
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
525 23