名字设计网站站长seo综合查询
1.首先是头文件:
//头文件
//contact.h//防止头文件被重复包含
#pragma once
//定义符号常亮,方便维护和修改
//联系人基本信息容量
#define NAME_MAX 20
#define AGE_MAX 5
#define SEX_MAX 5
#define TELE_MAX 15
#define ADDR_MAX 30
//联系人最大容量
#define MAX 1//定义联系人结构体
struct PeopleInfo
{char name[NAME_MAX];char age[AGE_MAX];char sex[SEX_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
};
//定义通讯录结构体
struct Contact
{struct PeopleInfo* data;int sz;int capacity;
};//声明函数
void clear_screen();
void AddContact(struct Contact* con);
void DelContact(struct Contact* con);
void ShowContact(struct Contact* con);
int FindContact(const struct Contact* con, char name[]);
void InitContact(struct Contact* con);
void menu();
void ModifyContact(struct Contact* con);
void SearchContact(struct Contact* con);
void SortContact(struct Contact* con);
void ClearContact(struct Contact* con);
void ClearCapContact(struct Contact* con);
2. 然后是功能函数contact.c文件
//功能函数文件
//contact.c #include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "contact.h"//定义菜单函数
void menu()
{printf("*********************************************\n");printf("******** 1.添加 2.删除 **************\n");printf("******** 3.查询 4.修改 **************\n");printf("******** 5.查看 6.排序 **************\n");printf("******** 7.清空 0.退出 **************\n");printf("*********************************************\n");
}//定义清屏函数
//清屏操作
void clear_screen() {//判断是否为Windows系统
#ifdef _WIN32system("cls");//其他系统
#elsesystem("clear");
#endif
}//初始化通讯录函数
void InitContact(struct Contact* con)
{con->sz = 0;//当前联系人数量:0//memset(con->data, 0, MAX * sizeof(struct PeopleInfo));//清空数组//动态分配成1,并初始化为0con->data = (struct People*)calloc(MAX, sizeof(struct PeopleInfo));if (con -> data == NULL) {printf("开辟空间失败!\n");return -1;}con->capacity = MAX;
}//添加联系人函数
void AddContact(struct Contact* con) {//检查通讯录是否溢出if (con->sz == con->capacity) {struct PeopleInfo* cap= (struct PeopleInfo*)realloc(con->data, ((con->capacity)++)* sizeof(struct PeopleInfo));if (cap != NULL){//扩容成功con->data = cap;printf("增容成功!\n");}else{//扩容失败return;}}printf("请输入姓名:");scanf("%s", con->data[con->sz].name);printf("请输入年龄:");scanf("%s", con->data[con->sz].age);printf("请输入性别:");scanf("%s", con->data[con->sz].sex);printf("请输入电话:");scanf("%s", con->data[con->sz].tele);printf("请输入地址:");scanf("%s", con->data[con->sz].addr);printf("添加成功!\n");(con->sz)++;
}//查找当前联系人函数
int FindContact(const struct Contact* con, char name[]) {for (int i = 0; i < con->sz; i++) {//利用比较函数strcmp判断姓名是否相等if (strcmp(con->data[i].name, name) == 0) {return i;}}printf("用户不存在!\n");return -1;
}//删除联系人函数
void DelContact(struct Contact* con) {if (con->sz == 0) {printf("通讯录为空!\n");}else{printf("请输入要删除的联系人姓名:\n");char name[NAME_MAX];scanf("%s", name);int ret = FindContact(con, name);if (ret != -1) {printf("删除成功!\n");for (int i = ret; i < con->sz - 1; i++) {con->data[i] = con->data[i + 1];}(con->sz)--;}}
}//查询当前通讯录
void ShowContact(struct Contact* con) {if (con->sz == 0) {printf("该通讯录为空\n");}else {printf("%-15s\t%-5s\t%-8s\t%-15s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");for (int i = 0; i < con->sz; i++) {printf("%-15s\t%-5s\t%-8s\t%-15s\t%-30s\n", con->data[i].name,con->data[i].age, con->data[i].sex, con->data[i].tele, con->data[i].addr);}}
}//查询联系人函数
void SearchContact(struct Contact* con) {if (con->sz == 0) {printf("当前通讯录为空\n");}else{printf("请输入要查询的联系人姓名:\n");char name[NAME_MAX];scanf("%s", name);int ret = FindContact(con, name);if (ret != -1) {printf("查询成功!\n");printf("%-15s\t%-5s\t%-8s\t%-15s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");printf("%-15s\t%-5s\t%-8s\t%-15s\t%-30s\n", con->data[ret].name,con->data[ret].age, con->data[ret].sex, con->data[ret].tele, con->data[ret].addr);}}
}//修改联系人函数
void ModifyContact(struct Contact* con) {if (con->sz == 0) {printf("通讯录为空\n");}else{printf("请输入要修改的联系人姓名:\n");char name[NAME_MAX];scanf("%s", name);int Mod_0 = 2;int ret = FindContact(con, name);if (ret != -1) {printf("当前联系人数据!\n");printf("%-15s\t%-5s\t%-8s\t%-15s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");printf("%-15s\t%-5s\t%-8s\t%-15s\t%-30s\n", con->data[ret].name,con->data[ret].age, con->data[ret].sex, con->data[ret].tele, con->data[ret].addr);printf("是否确定修改??(按1继续,按0退出)\n");while (1) {if (scanf("%d", &Mod_0) != 1) {printf("输入不合法,请重新输入");}if (Mod_0 == 1) {printf("请输入姓名:");scanf("%s", con->data[ret].name);printf("请输入年龄:");scanf("%s", con->data[ret].age);printf("请输入性别:");scanf("%s", con->data[ret].sex);printf("请输入电话:");scanf("%s", con->data[ret].tele);printf("请输入地址:");scanf("%s", con->data[ret].addr);printf("修改成功!\n");break;}else if (Mod_0 == 0) {break;}}}}
}//比较函数
int by_name_cmp1(const void* x1, const void* x2) {return strcmp(((struct PeopleInfo*)x1)->name, ((struct PeopleInfo*)x2)->name);
}
int by_name_cmp2(const void* x1, const void* x2) {return strcmp(((struct PeopleInfo*)x2)->name, ((struct PeopleInfo*)x1)->name);
}
//排序联系人函数
void SortContact(struct Contact* con) {if (con->sz == 0) {printf("通讯录为空\n");}else {int Sort_0 = 2;printf("请选择排序方式(按1升序,按0降序):\n");while (1) {if (scanf("%d", &Sort_0) != 1) {printf("输入不合法,请重新输入");}if (Sort_0 == 1) {qsort(con->data, con->sz, sizeof(struct PeopleInfo), by_name_cmp1);printf("升序排序已完成\n");break;}else if (Sort_0 == 0){qsort(con->data, con->sz, sizeof(struct PeopleInfo), by_name_cmp2);printf("降序排序已完成\n");break;}}}
}
//清空通讯录函数
void ClearContact(struct Contact* con) {if (con->sz == 0) {printf("通讯录为空\n");}else{con->sz = 0;memset(con->data, 0, MAX * sizeof(struct PeopleInfo));printf("当前通讯录已经清空\n");}
}//释放空间函数
void ClearCapContact(struct Contact* con) {free(con->data);con->data = NULL;con->sz = 0;con->capacity = 0;
}
3.最后是主程序test.c文件:
//主程序文件
//test.c#include <stdio.h>
#include <stdlib.h>
#include "contact.h"//枚举条件选择定义(搭配switch使用)
enum Option
{EXIT,//0,对应退出通讯录ADD,//1,对应添加联系人DEL,//2,对应删除联系人SEARCH,//3,对应查询联系人MODIFY,//4,对应修改联系人SHOW,//5,对应查看通讯录SORT,//6,对应排序通讯录CLEAR,//7,对应清空通讯录
};//主函数
int main()
{int input = 0;int menu_0 = 0;//创建通讯录struct Contact con;//调用函数初始化通讯录InitContact(&con);//传递参数地址do{//打印菜单while (1) {printf("************按1继续************\n");if (scanf("%d", &menu_0) != 1 && menu_0 != 1) {printf("输入不合法,请按1继续\n");return 1;}clear_screen();if (menu_0 == 1){menu();break;}}printf("请选择对应模式(0-7):\n");if (scanf("%d", &input) != 1 || input < 0 || input > 7) {printf("输入不合法,请输入整数0-7\n");return 1;}switch (input){case EXIT: {clear_screen();printf("退出通讯录!\n");break;}case ADD: {clear_screen();AddContact(&con);break;}case DEL: {clear_screen();DelContact(&con);break;}case SEARCH: {clear_screen();SearchContact(&con);break;}case SHOW: {clear_screen();ShowContact(&con);break;}case MODIFY: {clear_screen();ModifyContact(&con);break;}case SORT: {clear_screen();SortContact(&con);break;}case CLEAR: {clear_screen();ClearContact(&con);break;}default:break;}} while (input);ClearCapContact(&con);return 0;
}
整个项目只有三个文件,头文件和两个源代码
在“静态版通讯录”一章中,我们实现了一个静态版本的通讯录,所谓静态版就是通讯录中数组存储联系人的大小是固定的,如果我们并不需要有那么多的联系人,就造成内存的严重浪费,所以在本章,我们来实现一个动态版的通讯录,能存储联系人的个数可以根据需要改变。
首先,先介绍一下stdlib.h头文件中的动态空间分配库函数,在之前的文章中,我们介绍了malloc函数和realloc函数,今天我们要用calloc函数,下面我们来介绍一下他们之间的区别:
一、
calloc
的作用
功能:
分配一块 连续的内存空间。
自动将分配的内存初始化为零(所有字节设为
0x00
)。适用于需要批量分配并初始化内存的场景(如数组、结构体数组)。
函数原型:
void* calloc(size_t num_elements, size_t element_size);
参数:
num_elements
:需要分配的元素个数。
element_size
:每个元素的大小(单位:字节)。返回值:
成功:返回指向分配内存的指针。
失败:返回
NULL
(如内存不足)。
二、
calloc
的基本用法示例代码
#include <stdio.h> #include <stdlib.h> // 必须包含此头文件int main() {int n = 5;// 分配一个包含5个int的数组,并初始化为0int* arr = (int*)calloc(n, sizeof(int));if (arr == NULL) {printf("内存分配失败!\n");return 1;}// 使用内存for (int i = 0; i < n; i++) {printf("%d ", arr[i]); // 输出:0 0 0 0 0}// 释放内存free(arr);return 0; }
三、
calloc
vsmalloc
vsrealloc
函数 初始化内存 参数形式 典型用途 calloc
初始化为零 num_elements, element_size
分配并初始化数组、结构体数组 malloc
不初始化 total_bytes
分配内存但不关心初始值 realloc
可能保留数据 ptr, new_size
调整已分配内存的大小 关键区别
初始化行为:
calloc
:分配的内存会被自动清零。
malloc
:分配的内存内容是未定义的(可能是垃圾值)。
realloc
:调整内存大小时,原有数据可能保留(取决于实现)。参数形式:
calloc
需要指定 元素个数 和 每个元素的大小,适合分配数组。
malloc
直接指定 总字节数。
四、何时使用
calloc
?
需要初始化内存为零:
例如:创建数组或结构体数组时,希望所有元素初始为
0
。struct Student* students = (struct Student*)calloc(100, sizeof(struct Student));避免未初始化导致的问题:
如果直接使用
malloc
,内存中可能残留随机值,导致程序行为异常。
五、注意事项
内存对齐:
calloc
分配的内存会按系统要求对齐,无需手动处理。性能开销:
calloc
的初始化(清零)会带来额外开销,如果不需要初始化,优先用malloc
。内存释放:
和
malloc
一样,必须用free()
释放内存,否则会导致内存泄漏。检查返回值:
始终检查
calloc
返回的指针是否为NULL
,避免空指针解引用。
六、总结
calloc
是分配并清零内存的工具,适合需要安全初始化的场景。
malloc
更快但不初始化,适合不需要初始值的场景。
realloc
用于调整内存大小,可能保留原有数据。
知道了这些知识,下面我们就可以操作了:
struct Contact
{struct PeopleInfo* data;int sz;int capacity;
};
定义结构体这里,定义一个当前空间容量capacity(后面有用);
//初始化通讯录函数
void InitContact(struct Contact* con)
{con->sz = 0;//当前联系人数量:0//memset(con->data, 0, MAX * sizeof(struct PeopleInfo));//清空数组//动态分配成1,并初始化为0con->data = (struct People*)calloc(MAX, sizeof(struct PeopleInfo));if (con -> data == NULL) {printf("开辟空间失败!\n");return -1;}con->capacity = MAX;
}
初始化函数这里,使用calloc函数来分配空间并初始化通讯录,并检查是否分配成功;
让当前容量为开始时定义MAX(也就是1),这样后面可以用来重新分配;
//添加联系人函数
void AddContact(struct Contact* con) {//检查通讯录是否溢出if (con->sz == con->capacity) {struct PeopleInfo* cap= (struct PeopleInfo*)realloc(con->data, ((con->capacity)++)* sizeof(struct PeopleInfo));if (cap != NULL){//扩容成功con->data = cap;printf("增容成功!\n");}else{//扩容失败return;}}printf("请输入姓名:");scanf("%s", con->data[con->sz].name);printf("请输入年龄:");scanf("%s", con->data[con->sz].age);printf("请输入性别:");scanf("%s", con->data[con->sz].sex);printf("请输入电话:");scanf("%s", con->data[con->sz].tele);printf("请输入地址:");scanf("%s", con->data[con->sz].addr);printf("添加成功!\n");(con->sz)++;
}
既然是动态分配,添加这里肯定也是需要变化,每次添加时,都要重新分配一次,不断的使容量一次扩充一个;
之后,你要记得释放清理空间:
//释放空间函数
void ClearCapContact(struct Contact* con) {free(con->data);con->data = NULL;con->sz = 0;con->capacity = 0;
}
其他的代码和静态的通讯录一样。
下面附上源代码:
双叶/(C语言)动态通讯录
那么这样,我们的动态分配的动态通讯录就做好了,如果大家喜欢,希望可以得到大家的关注呦~
注:该代码是本人自己所写,可能不够好,不够简便,欢迎大家指出我的不足之处。如果遇见看不懂的地方,可以在评论区打出来,进行讨论,或者联系我。上述内容全是我自己理解的,如果你有别的想法,或者认为我的理解不对,欢迎指出!!!如果可以,可以点一个免费的赞支持一下吗?谢谢各位彦祖亦菲!!!!!