会写的不一定真的懂了,本篇文章结合了B站鹏哥的写作手法,循序渐进推进知识点,一步步教你写代码,非常适合初学者学习,建议反复观看。
同时作者我也是一个C语言B站初学者,欢迎一起学习交流,批评指正。
家人们,来都来了,动动你们发财的小手,给我点点关注,点点赞呗,你们的支持就是我创作的动力,我会持续发布高质量的文章供大家一起学习。
首先,我们在写的时候要明白通讯录的作用,其实通讯录就是我们的笔记本,只是用来记录联 系人的信息的,重要的是对通讯录的修改。通讯录的原理实现其实很简单,我们只需要创建一个数组,对这个数组进行增,删,查,改就可以了。写通讯录的基本程序大部分也就是在这方面下手的。接下来的通讯录的编写我会结合一些基本知识点逐步来为大家讲解。
在看我们整个打印菜单及菜单键的实现逻辑之前,我们先看看我们定义的头文件中干了什么吧
#include
#include
#include
enum Option
{
EXIT,
ADD,
DEL,
SAERCH,
MOD,
SHOW,
SAVE
};
没错!我们创建了一个枚举,它的作用就是利用枚举常量代替了数字0到6,接下来我们就可以体验到,当然,在源文件中要引用这个头文件哦。
#define _CRT_SECURE_NO_WARNINGS 1
#include"teat2.h"
void menu()
{
printf("*********************************************************\n");
printf("****************** 1.add 2.del ********************\n");
printf("****************** 3.saerch 4.modify ********************\n");
printf("****************** 5.show 6.save ********************\n");
printf("****************** 0.exit ********************\n");
printf("*********************************************************\n");
}
int main()
{
int arr = 0;
//创建通讯录
struct Contact con;
//通讯录初始化
InitContact(&con);
do {
menu();
printf("请输入->\n");
scanf("%d", &arr);
switch (arr)
{
//添加联系人
case ADD:
AddContact(&con);
break;
//删除联系人
case DEL:
DelContact(&con);
break;
//查找联系人
case SAERCH:
SaerchContact(&con);
break;
//修改联系人
case MODify:
SavveContact(&con);
ModContact(&con);
break;
//显示通讯录名单
case SHOW:
Contactcpy(&con);
break;
//保存联系人
case SAVE:
SavveContact(&con);
printf("保存成功!\n");
break;
case EXIT:
//指针指空
DestroyContact(&con);
printf("你已经退出。\n");
break;
default:
printf("你的输入有错,请重新输入!\n");
break;
}
} while (arr);
return 0;
}
case的同样的效果,而case 后的值再也不是数字了,而是字母,这样是不是很高级?用户在使用时同样输入数字就好了。
枚举有什么作用呢?
通常在没改变枚举常量默认赋值的情况下从前到后,每个枚举的常量是从0,1,2,3,4...这样+1一直到最后一个枚举常量的。就像这里的菜单键EXIT = 0, ADD = 1,DEL = 2,SAERCH = 3,MODIFY = 4,SHOW = 5 ,SAVE = 6一样。
其他的这里switch分支,while循环以及库函数的头文件的引用是为什么就不在这里解释了,不知道的可以看看我的其他文章,或者Q我哦。
main()中的创建讯录及通讯录初始化
我们创建了一个结构体和一个自定义函数
//创建通讯录
struct Contact con;
//通讯录初始化
InitContact(&con);
我们先看看我们定义的头文件中干了什么吧
#define DEFAULT_SZ 3
#define MAX_NAME 20
#define MAX_SEC 5
#define MAX_TELE 12
#define MAX_ADDR 20
//存放我们联系人的基本信息
struct Peotnfo
{
char name[MAX_NAME];
int age;
char sec[MAX_SEC];
char tele[MAX_TELE];
char addr[MAX_ADDR];
};
//通讯录
struct Contact
{
struct Peotnfo* data;
int size;
int capacity;
};
我们在头文件中完整的写出了Contact这个结构体,这个结构体用来存放的我们联系人,已及一个记录联系人数量的int变量size,还有一个开辟联系人数量空间的int变量capacity,但值得注意的是用来存放我们联系人的基本信息的也是一个结构体,在这个结构体中我们创建了5个变量,分别是name(名字) ,age(年龄),sec(性别),tale(电话),addr(地址)并为他们开辟了空间。
这里#define就是用大写的字母代替数字,数字表示为这个数组向内存申请了多少空间。
超级重要!!!!一开始#define设置开辟的空间一定要满足基本的存储,如这里的电话号码开辟的空间一定要大于12,否则一定会出问题。
void InitContact(struct Contact* pc)
{
pc->data = (struct Peotnfo*)malloc( DEFAULT_SZ * sizeof(struct Peotnfo));
if (pc->data == NULL)
{
return;
}
//空间初始化为3,DEFAULT_SZ在头文件中指定为3
pc->capacity = DEFAULT_SZ;
pc->size = 0;
}
我们在函数中传了一个结构体指针,并为这个指针取了个名字叫pc,然后用malloc库函数动态开辟了空间,data是个指针,指向了存放我们联系人的基本信息的那个结构体。为了严谨,我们还加了一句ifpc->data == NULL来判断是否有效。
void CheckCapacity(struct Contact* pc)
{
if (pc->size == pc->capacity)
{
struct Peotnfo* p = (struct Peotnfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(struct Peotnfo));
if (p != NULL)
{
pc->capacity += 2;
pc->data = p;
printf("增容成功!\n");
}
else {
printf("增容失败!\n");
}
}
}
//写入文件
void SavveContact(struct Contact* pc)
{
//二进制wb写入,增加保密性
FILE* pfwrite = fopen("contat.txt", "wb");
if (pfwrite == NULL)
{
printf("%d\n", strerror(errno));
return;
}
int i = 0;
for (i = 0; i < pc->size; i++)
{
fwrite(&(pc->data[i]), sizeof(Peotnfo), 1, pfwrite);
}
fclose(pfwrite);
pfwrite = NULL;
}
//从文件里读
void LoadContat(struct Contact* pc)
{
Peotnfo tmp = { 0 };
FILE* pfwrites = fopen("contat.txt", "rb");
if (pfwrites == NULL)
{
printf("%d\n", strerror(errno));
return;
}
while (fread(&tmp, sizeof(Peotnfo), 1, pfwrites))
{
CheckCapacity(pc);
pc->data[pc->size] = tmp;
pc->size++;
}
fclose(pfwrites);
pfwrites = NULL;
}
有了这个就可以把联系人的信息存储在"contat.txt"(自动创建)这个文件中,每次打开的时候就有上次写的记录,但是一定记得保存哦。至于fopen和fread的使用的详细语法我会在这几天赶出来,请关注主页。
看看效果:
void AddContact(struct Contact* pc)
{
char arr1;
CheckCapacity(pc);
do {
printf("请输入名字->");
scanf("%s", pc->data[pc->size].name);
printf("请输入年龄->");
scanf("%d", &(pc->data[pc->size].age));
printf("请输入性别->");
scanf("%s", pc->data[pc->size].sec);
printf("请输入电话->");
scanf("%s", pc->data[pc->size].tele);
printf("请输入地址->");
scanf("%s", pc->data[pc->size].addr);
getchar();
pc->size++;
printf("添加完成!是否继续添加->y/n");
scanf("%c", &arr1);
getchar();
if (arr1 == 'n')
{
break;
}
} while (1);
}
这里没什么讲的,就是利用scanf函数将值输入到pc对应的指针里面去,然后用while循环来保持持续性。
看看效果:
void Contactcpy(struct Contact* pc)
{
int arr2;
if (pc->size == 0)
{
printf("通讯录为空\n");
}
else {
for (arr2 = 0; arr2 < pc->size; arr2++) {
printf("名字: ");
printf("%-20s\n", pc->data[arr2].name);
printf("年龄: ");
printf("%-4d\n", (pc->data[arr2].age));
printf("性别: ");
printf("%-5s\n", pc->data[arr2].sec);
printf("电话: ");
printf("%-12s\n", pc->data[arr2].tele);
printf("地址: ");
printf("%-30s\n", pc->data[arr2].addr);
printf("---------------------------\n");
}
}
}
这里也没什么讲的,就是利用printf函数打印联系人信息。这里提前写是为了在写其他函数时方便打印调试。
看看效果:
查找,删除,修改联系人的第一个步骤是对联系人的定位,所有我们可以统一起来写一个对联系人定位的函数
static int FindName(struct Contact* pc, char name[MAX_NAME])
{
int i;
for (i = 0; i < pc->size; i++)
{
if (0 == strcmp(pc->data[i].name, name))
{
return i;
}
}
return -1;
}
利用循环去遍历,找到了返回i,即联系人的存储序号,没找到返回-1
void DelContact(struct Contact* pc)
{
int poc;
char name[MAX_NAME];
printf("请输入你要删除的对象名字->");
scanf("%s", &name);
//对定位函数的使用
poc = FindName(pc, name);
if (poc == -1)
{
printf("你要删除的对象不在。");
}
else {
for (int j = poc; j < pc->size - 1; j++)
{
pc->data[j] = pc->data[j + 1];
}
pc->size--;
printf("删除成功!\n");
}
}
减少一个联系人size--一次
看看效果:
void SaerchContact(struct Contact* pc)
{
int poc;
char name[MAX_NAME];
printf("请输入你要查找的对象名字->");
scanf("%s", &name);
//对定位函数的使用
poc = FindName(pc, name);
if (poc == -1)
{
printf("你要查找的对象不在。");
}
else {
printf("名字: ");
printf("%-20s\n", pc->data[poc].name);
printf("年龄: ");
printf("%-4d\n", (pc->data[poc].age));
printf("性别: ");
printf("%-5s\n", pc->data[poc].sec);
printf("电话: ");
printf("%-12s\n", pc->data[poc].tele);
printf("地址: ");
printf("%-30s\n", pc->data[poc].addr);
}
}
查找联系人的函数使用原理就是定位加打印。
看看效果:
void ModContact(struct Contact* pc)
{
int poc;
char name[MAX_NAME];
printf("请输入你要修改的对象->");
scanf("%s", &name);
//对定位函数的使用
poc = FindName(pc, name);
if (poc == -1)
{
printf("你要修改的对象不在。");
}
else {
printf("请输入名字->");
scanf("%s", pc->data[poc].name);
printf("请输入年龄->");
scanf("%d", &(pc->data[poc].age));
printf("请输入性别->");
scanf("%s", pc->data[poc].sec);
printf("请输入电话->");
scanf("%s", pc->data[poc].tele);
getchar();
printf("请输入地址->");
scanf("%s", pc->data[poc].addr);
getchar();
printf("修改完成!");
}
}
修改联系人的函数使用原理就是定位加添加,但值得注意的是size不变。
看看效果:
加密的哦。
家人们,来都来了,动动你们发财的小手,给我点点关注,点点赞呗,你们的支持就是我创作的动力,我会持续发布高质量的文章供大家一起学习。