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

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

相关文章
|
22天前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
30 3
|
9天前
|
监控 算法 应用服务中间件
“四两拨千斤” —— 1.2MB 数据如何吃掉 10GB 内存
一个特殊请求引发服务器内存用量暴涨进而导致进程 OOM 的惨案。
|
7天前
|
C语言
【c语言】动态内存管理
本文介绍了C语言中的动态内存管理,包括其必要性及相关的四个函数:`malloc`、``calloc``、`realloc`和`free`。`malloc`用于申请内存,`calloc`申请并初始化内存,`realloc`调整内存大小,`free`释放内存。文章还列举了常见的动态内存管理错误,如空指针解引用、越界访问、错误释放等,并提供了示例代码帮助理解。
23 3
|
8天前
|
存储 C语言
数据在内存中的存储方式
本文介绍了计算机中整数和浮点数的存储方式,包括整数的原码、反码、补码,以及浮点数的IEEE754标准存储格式。同时,探讨了大小端字节序的概念及其判断方法,通过实例代码展示了这些概念的实际应用。
18 1
|
13天前
|
存储
共用体在内存中如何存储数据
共用体(Union)在内存中为所有成员分配同一段内存空间,大小等于最大成员所需的空间。这意味着所有成员共享同一块内存,但同一时间只能存储其中一个成员的数据,无法同时保存多个成员的值。
|
15天前
|
监控 Java easyexcel
面试官:POI大量数据读取内存溢出?如何解决?
【10月更文挑战第14天】 在处理大量数据时,使用Apache POI库读取Excel文件可能会导致内存溢出的问题。这是因为POI在读取Excel文件时,会将整个文档加载到内存中,如果文件过大,就会消耗大量内存。以下是一些解决这一问题的策略:
43 1
|
18天前
|
缓存 安全 Java
使用 Java 内存模型解决多线程中的数据竞争问题
【10月更文挑战第11天】在 Java 多线程编程中,数据竞争是一个常见问题。通过使用 `synchronized` 关键字、`volatile` 关键字、原子类、显式锁、避免共享可变数据、合理设计数据结构、遵循线程安全原则和使用线程池等方法,可以有效解决数据竞争问题,确保程序的正确性和稳定性。
31 2
|
22天前
|
存储 编译器
数据在内存中的存储
数据在内存中的存储
35 4
|
23天前
|
编译器 程序员 C语言
深入C语言:动态内存管理魔法
深入C语言:动态内存管理魔法
|
9天前
|
存储 C语言
【c语言】字符串函数和内存函数
本文介绍了C语言中常用的字符串函数和内存函数,包括`strlen`、`strcpy`、`strcat`、`strcmp`、`strstr`、`strncpy`、`strncat`、`strncmp`、`strtok`、`memcpy`、`memmove`和`memset`等函数的使用方法及模拟实现。文章详细讲解了每个函数的功能、参数、返回值,并提供了具体的代码示例,帮助读者更好地理解和掌握这些函数的应用。
12 0