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

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

导语

这一片博客我会改进上次的静态+文件通讯录,先分析哪里可以改,然后再下手,最后测试。

先从动态方面开始改。

动态改进

首先是储存联系人的潍坊可以更改,因为你写了100不一定能存上100个位置,这样容易浪费空间,或者是100个不够你还要手动去更改,很麻烦,我们可以让他刚开始分配一小块那日村,不够就一直扩容。

我们这里初始能放3个联系人,不够的话每次加2个。(数量少方便测试)

初始化通讯录与添加联系人的更改

首先,因为动态内存函数的性质,我们需要把结构体:

contacts.h

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;

存放人信息的位置给更改成指针,然后需要一个变量来统计通讯录的容量。

首先改一下初始化通讯录的函数:

contacts.c

int initialize(contacts* pc)
{
  assert(pc != NULL);
  pc->count = 0;//将计数的变量初始化为0
  pc->data = calloc(3,sizeof(person));//开辟一个动态内存,然后把地址传给data指针
  if (pc->data == NULL)
  {
    printf("initialize:%s",strerror(errno));
    return 1;
  }
  pc->capacity = 3;//一开始让通讯录只有三个人的容量
  return 0;
}

这次改添加联系人的地方

既然是无限扩容,就没有通讯录已满这一说,我们把判断人是不是满给改掉。

当然,把增容的内容封装成一个函数更容易维护:

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");
  }
}
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 destroycontact(contacts* pc)
{
  assert(pc != NULL);
  free(pc->data);
  pc->data = NULL;
}

动态通讯录的完全体

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);//动态内存销毁

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");
  }
}
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;
  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;
}

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://退出程序
      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;
}


相关文章
|
16天前
|
存储 小程序 C语言
【C语言程序设计——文件】文件操作(头歌实践教学平台习题)【合集】
本文介绍了C语言中的文件操作,分为两个关卡。第1关任务是将键盘输入的字符(以#结束)存入`file1.txt`并显示输出;第2关任务是从键盘输入若干行文本(每行不超过80个字符,用-1作为结束标志),写入`file2.txt`后再读取并显示。文中详细讲解了文件的打开、读取(使用`fgetc()`和`fgets()`)、写入(使用`fputc()`和`fputs()`)及关闭操作,并提供了示例代码和测试说明。
34 5
|
2月前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
180 3
|
3月前
|
存储 编译器 C语言
如何在 C 语言中判断文件缓冲区是否需要刷新?
在C语言中,可以通过检查文件流的内部状态或使用`fflush`函数尝试刷新缓冲区来判断文件缓冲区是否需要刷新。通常,当缓冲区满、遇到换行符或显式调用`fflush`时,缓冲区会自动刷新。
|
3月前
|
存储 编译器 C语言
C语言:文件缓冲区刷新方式有几种
C语言中文件缓冲区的刷新方式主要包括三种:自动刷新(如遇到换行符或缓冲区满)、显式调用 fflush() 函数强制刷新、以及关闭文件时自动刷新。这些方法确保数据及时写入文件。
|
3月前
|
存储 C语言
探索C语言数据结构:利用顺序表完成通讯录的实现
本文介绍了如何使用C语言中的顺序表数据结构实现一个简单的通讯录,包括初始化、添加、删除、查找和保存联系人信息的操作,以及自定义结构体用于存储联系人详细信息。
51 2
|
3月前
|
C语言
【C语言】探索文件读写函数的全貌(三)
【C语言】探索文件读写函数的全貌
|
3月前
|
存储 C语言
【C语言】探索文件读写函数的全貌(二)
【C语言】探索文件读写函数的全貌
|
3月前
|
存储 C语言
手把手教你用C语言实现通讯录管理系统
手把手教你用C语言实现通讯录管理系统
|
7月前
|
C语言
C语言进阶——sprintf与sscanf、文件的随机读写(fseek、ftell、rewind)
C语言进阶——sprintf与sscanf、文件的随机读写(fseek、ftell、rewind)
73 0
|
存储 缓存 C语言
【C语言进阶】文件的顺序读写、随机读写、文本文件和二进制文件、文件读取结束的判定以及文件缓冲区相关知识(下)
【C语言进阶】文件的顺序读写、随机读写、文本文件和二进制文件、文件读取结束的判定以及文件缓冲区相关知识(下)

热门文章

最新文章