c语言小课设--通讯录(动态内存管理+可持久化数据)

简介: c语言小课设--通讯录(动态内存管理+可持久化数据)

前言:

在没学动态内存管理之前,我们用的结构体,数组等都是静态分配内存的,也就是说数组的长度是固定的,但是这并不满足我们的实际需求,所以在通讯录项目里面我就用到了动态内存分布。简单来说,就是当需要储存的联系人数据太多了的时候,我们就可以扩大一点空间用来存放新的数据,也就是说实现了要多少,就开辟多少的空间。

项目介绍:

该项目实现一个通讯录功能,除了能根据具体需求扩大空间之外,也实现了最基本基本的增删查改等功能,并在退出通讯录时销毁创造的空间,从而不造成内存泄露。

另外,这个项目由三部分组成,函数功能的实现在Contact.c源文件中,各种头文件、函数等声明则由文件Contact.h来实现,最后测试在源文件test.c文件中进行。

一、teat.c文件:

#define _CRT_SECURE_NO_WARNINGS 1
#include"Contact.h"
 
 
enum Option {
  Exit,
  add,
  modify,
  del,
  search,
  show,
  sort
};
 
void menu() {
  printf("************************\n");
  printf("**1.添加    2.修改******\n");
  printf("**3.删除    4.搜索******\n");
  printf("**5.展示    6.排序******\n");
  printf("**0.退出          ******\n");
  printf("************************\n");
}
 
 
int main() {
  int input = 0;
  Contacts Con;
  Init(&Con);
  do {
    menu();
    printf("请输入你的选择--》\n");
    scanf("%d", &input);
    switch (input) {
    case add://添加
      Add_Peo(&Con);
      break;
    case modify://修改
      Modify_Peo(&Con);
      break;
    case del:
      Del_Peo(&Con);
      break;
    case search:
      Sear_Peo(&Con); 
      break;
    case show:
      Show_Peo(&Con);
      break;
    case sort:
      Sort_Peo(&Con);
      break;
    case Exit:
      SaveContact(&Con);
      Destory_Contacts(&Con);
      printf("退出通讯录\n");
      break;
    default:
      printf("你的输入有误!\n");
      break;
 
    }
  } while (input != 0);
  return 0;
}

二、Contact.h头文件:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
 
#define name_max 20
#define sex_max 5
#define tele_max 12
#define addr_max 20
#define num_max 100
#define default_cap 3
 
typedef struct PeoInfo {
  char name[name_max];
  char sex[sex_max];
  char tele[tele_max];
  int age;
}PeoInfo;
//静态通讯录版本
//typedef struct Contacts {
//  PeoInfo data[num_max];
//  int sz;
//}Contacts;
//动态版本
typedef struct Contacts {
  PeoInfo *data;//存放数据
  int sz;//记录当前联系人的数量
  int cap;//当前通讯录的容量
}Contacts;
 
 
 
//初始化通讯录
void Init(Contacts* Con);
//添加功能
void Add_Peo(Contacts* Con);
//修改功能
void Modify_Peo(Contacts* Con);
//删除联系人
void Del_Peo(Contacts* Con);
//展示联系人
void Show_Peo(Contacts* Con);
//查询联系人
void Sear_Peo(Contacts* Con);
//排序
void Sort_Peo(Contacts* Con);
//保存数据到通讯录中
void SaveContact(Contacts* Con);
//加载信息到通讯录
void LoadContact(Contacts* Con);

三、Contact.c文件:

#define _CRT_SECURE_NO_WARNINGS 1
#include"Contact.h"
 
// 自定义比较剂,按名字字典序排序
 
int cmp(void* e1,void *e2) {
  //printf("%s %s\n", (, ((struct PeoInfo*)e2)->name);
  return strcmp(((struct PeoInfo*)e1)->name, ((struct PeoInfo*)e2)->name);
}
 
//初始化通讯录
void Init(Contacts* Con) {
  assert(Con);
  Con->sz = 0;
  Con->cap = default_cap;
  Con->data = calloc(Con->cap, sizeof(PeoInfo));
  if (Con->data == NULL) {
    printf("初始化失败\n");
    return;
  }
  LoadContact(Con);
}
 
//void Init(Contacts* Con) {
//  assert(Con);
//  Con->sz = 0;
//  memset(Con->data, 0, sizeof(Con->data));
//}
 
//增加容量
void check_cap(Contacts* Con) {
  
    PeoInfo* ptr = realloc(Con->data, (Con->cap + 2) * sizeof(PeoInfo));
    if (ptr != NULL) {
      Con->data = ptr;
      Con->cap += 2;
      printf("增容成功\n");
    }
    else {
      perror("AddContacts->realloc");
      return;
    }
  
}
//添加功能
//动态版本
void Add_Peo(Contacts* Con) {
  assert(Con);
  if (Con->sz == Con->cap) {
    check_cap(Con);
  }
  printf("请输入添加人的姓名\n");
  scanf("%s", Con->data[Con->sz].name);
  printf("请输入添加人的年龄\n");
  scanf("%d", &Con->data[Con->sz].age);
  printf("请输入添加人的性别\n");
  scanf("%s", Con->data[Con->sz].sex);
  printf("请输入添加人的号码\n");
  scanf("%s", Con->data[Con->sz].tele);
  Con->sz++;
  return;
}
//静态版本
//void Add_Peo(Contacts* Con) {
//  assert(Con);
//  if (Con->sz == num_max) {
//    printf("通讯录已满\n");
//    return;
//  }
//  else {
//    printf("请输入添加人的姓名\n");
//    scanf("%s", Con->data[Con->sz].name);
//    printf("请输入添加人的年龄\n");
//    scanf("%d", &Con->data[Con->sz].age);
//    printf("请输入添加人的性别\n");
//    scanf("%s", Con->data[Con->sz].sex);
//    printf("请输入添加人的号码\n");
//    scanf("%s", Con->data[Con->sz].tele);
//    Con->sz++;
//    return;
//  }
//}
//按名字查找
int find_name(Contacts* Con,char *tager) {
  assert(Con);
  for (int i = 0; i < Con->sz; i++) {
    if (strcmp(Con->data[i].name, tager)==0) {
      return i;
    }
  }
  return -1;
  
  
}
//修改功能
void Modify_Peo(Contacts* Con) {
  assert(Con);
  char name[name_max] = {0};
  while (1) {
    printf("请输入你要修改联系人的名字\n");
    scanf("%s", name);
    int k = find_name(Con, name);
    if ( k!= -1&&k>=0&&k<Con->sz) {
      printf("请重新输入修改的姓名\n");
      scanf("%s", Con->data[k].name);
      printf("请重新输入修改的的年龄\n");
      scanf("%d",&Con->data[k].age);
      printf("请重新输入修改的的性别\n");
      scanf("%s", Con->data[k].sex);
      printf("请重新输入修改的的号码\n");
      scanf("%s", Con->data[k].tele);
      printf("修改成功!\n");
      break;
    }
    else {
      printf("查无此人\n");
      break;
    }
  }
 
}
//删除联系人
void Del_Peo(Contacts* Con) {
  assert(Con);
  if (Con->sz == 0) {
    printf("该通讯录还没有联系人\n");
    return;
  }
  printf("请输入你要删除联系人的姓名\n");
  char name1[name_max] = { 0 };
  scanf("%s", name1);
  int k = find_name(Con, name1);
  if (k != -1&&k>=0&&k<Con->sz) {
    for (int i = k; i < Con->sz - 1; i++) {
      Con->data[i] = Con->data[i + 1];
    }
    Con->sz--;
    printf("删除成功\n");
  }
  else {
        printf("查无此人\n");
    return;
  }
}
//展示联系人
void Show_Peo(Contacts* Con) {
  assert(Con);
  if (Con->sz == 0) {
    printf("没有联系人\n");
    return;
  }
  printf("-------------------------------------------------\n");
  printf("|%-20s |%-5s |%-5s |%-12s| \n","姓名","年龄","性别","号码");
  printf("-------------------------------------------------\n");
  for (int i = 0; i < Con->sz; i++) {
    printf("|%-20s |%-5d |%-5s |%-12s|\n", Con->data[i].name, Con->data[i].age, Con->data[i].sex, Con->data[i].tele);
    if (i != (Con->sz - 1)) {
      printf("-------------------------------------------------\n");
    }
  }
  printf("-------------------------------------------------\n");
}
//查询联系人
void Sear_Peo(Contacts* Con) {
  assert(Con);
  char tager[name_max] = { 0 };
  if (Con->sz == 0) {
    printf("没有联系人\n");
    return;
  }
  printf("请输入你要查找的名字\n");
  scanf("%s", tager);
  int k = find_name(Con, tager);
  if (k != -1 && k >= 0 && k < Con->sz) {
    printf("-------------------------------------------------\n");
    printf("|%-20s |%-5s |%-5s |%-12s| \n", "姓名", "年龄", "性别", "号码");
    printf("|%-20s |%-5d |%-5s |%-12s|\n", Con->data[k].name, Con->data[k].age, Con->data[k].sex, Con->data[k].tele);
    printf("-------------------------------------------------\n");
  }
  else {
    printf("查无此人\n");
    return;
  }
}
//排序
void Sort_Peo(Contacts* Con) {
  assert(Con);
  qsort(Con->data, Con->sz, sizeof(struct PeoInfo), cmp);
  printf("排序成功\n");
  return;
}
//销毁通讯录
void Destory_Contacts(Contacts* Con) {
  free(Con->data);
  Con->data = NULL;
  Con->cap = 0;
  Con->sz = 0;
}
 
//保存数据到文件中
void SaveContact(Contacts* Con) {
  assert(Con);
 
  FILE* pf = fopen("Contact.txt", "wb");
  if (pf == NULL) {
    perror("SaveContact");
    return;
  }
 
  for (int i = 0; i < Con->sz; i++) {
    fwrite(Con->data + i, sizeof(PeoInfo), 1, pf);
  }
 
  fclose(pf);
  pf = NULL;
}
 
//加载文件中的数据到通讯录中
void LoadContact(Contacts* Con) {
  assert(Con);
 
  FILE* pf = fopen("Contact.txt", "rb");
  if (pf == NULL) {
    perror("LoadContact");
    return;
  }
 
  PeoInfo temp = { 0 };
  while (fread(&temp, sizeof(PeoInfo), 1, pf)) {
    check_cap(Con);
    Con->data[Con->sz] = temp;
    Con->sz++;
  }
 
  fclose(pf);
  pf = NULL;
}

好了以上就是整个项目的源代码了,是不是很简单呢?感兴趣的可以自己去试试哦!

相关文章
|
25天前
|
存储 程序员 编译器
C 语言中的数据类型转换:连接不同数据世界的桥梁
C语言中的数据类型转换是程序设计中不可或缺的一部分,它如同连接不同数据世界的桥梁,使得不同类型的变量之间能够互相传递和转换,确保了程序的灵活性与兼容性。通过强制类型转换或自动类型转换,C语言允许开发者在保证数据完整性的前提下,实现复杂的数据处理逻辑。
|
24天前
|
存储 编译器 程序员
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
在C语言中,内存布局是程序运行时非常重要的概念。内存布局直接影响程序的性能、稳定性和安全性。理解C程序的内存布局,有助于编写更高效和可靠的代码。本文将详细介绍C程序的内存布局,包括代码段、数据段、堆、栈等部分,并提供相关的示例和应用。
38 5
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
|
24天前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
52 6
|
26天前
|
存储 数据管理 C语言
C 语言中的文件操作:数据持久化的关键桥梁
C语言中的文件操作是实现数据持久化的重要手段,通过 fopen、fclose、fread、fwrite 等函数,可以实现对文件的创建、读写和关闭,构建程序与外部数据存储之间的桥梁。
|
28天前
|
传感器 人工智能 物联网
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发,以及面临的挑战和未来趋势,旨在帮助读者深入了解并掌握这些关键技术。
46 6
|
29天前
|
存储 数据建模 程序员
C 语言结构体 —— 数据封装的利器
C语言结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个整体。它支持数据封装,便于管理和传递复杂数据,是程序设计中的重要工具。
|
1月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
122 13
|
29天前
|
大数据 C语言
C 语言动态内存分配 —— 灵活掌控内存资源
C语言动态内存分配使程序在运行时灵活管理内存资源,通过malloc、calloc、realloc和free等函数实现内存的申请与释放,提高内存使用效率,适应不同应用场景需求。
|
1月前
|
存储 编译器 数据处理
C 语言结构体与位域:高效数据组织与内存优化
C语言中的结构体与位域是实现高效数据组织和内存优化的重要工具。结构体允许将不同类型的数据组合成一个整体,而位域则进一步允许对结构体成员的位进行精细控制,以节省内存空间。两者结合使用,可在嵌入式系统等资源受限环境中发挥巨大作用。
62 11
|
29天前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。

热门文章

最新文章