设计目标:写一个通讯录,每个人的信息包括:1.名字,2.年龄,3.性别,4.电话,5.住址
//功能:1. 增加一个人的信息
2. 删除一个指定的联系人
3. 查找一个指定的联系人
4. 修改一个指定的联系人
5. 显示通讯录中所有人的信息
6. 保存
7.销毁
0. 退出
静态版本 - 一次开辟1000个元素的连续空间
文件的版本 - 数据可以存储到文件中,不至于丢失,动态增长 - 按需开辟
成果图:增加:
查找:
删除:
保存:
销毁,展示:
1.通过结构保存个人信息和通讯录(静态动态两种建立方法)
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>
#define MAX 1000
#define NAME_MAX 20
#define SEX_MAX 5
#define TELL_MAX 12
#define ADDRESS_MAX 30
#define CAPACITY_SZ 3
typedef struct Personal //个人信息结构体
{
char name[NAME_MAX];
int age;
char sex[SEX_MAX];
char tell[TELL_MAX];
char address[ADDRESS_MAX];
}Persona;
//struct Contact //通讯录静态
//{
// Persona data[MAX]; //每创建一个就包含1000个 个人
// int sz;
//};
struct Contact //通讯录
{
Persona *data;
int sz;
int capacity; //最大容量
};
2.主函数:逻辑是创建通讯录--->初始化--->菜单--->功能,这里用枚举代替数字选择方便调试,更加直观。
enum Features
{
Exit = 0,
add,
del,
find,
mod,
show,
save,
Destroy,
};
void menu()
{
printf("*****************************\n");
printf("****1.add ****2. del ******\n");
printf("****3.find ****4. mod ******\n");
printf("****5.show ****6. save ******\n");
printf("****0.exit ****7. Dest******\n");
printf("*****************************\n");
printf("请选择--->");
}
int main()
{
int input = 0;
struct Contact Con; //创建一个通讯录
Initialize(&Con); //初始化
do
{
menu();
scanf("%d", &input);
switch (input)
{
case add:
addContacts(&Con);
break;
case del:
delContacts(&Con);
break;
case find:
findContacts(&Con);
break;
case mod:
modContacts(&Con);
break;
case show:
showContacts(&Con);
break;
case save:
saveContacts(&Con);
break;
case Destroy:
DestroyContacts(&Con);
break;
case Exit:
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
3.初始化函数,给出两个版本(静态,动态)
//void Initialize(struct Contact * Con) //静态
//{
// Con->sz = 0;
// memset(Con->data, 0, sizeof(Con->data)); //void *memset(void *s, int ch, size_t n);将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
//}
void Initialize(struct Contact* Con) //动态版本初始化
{
Con->sz = 0;
Con->capacity = CAPACITY_SZ;
Con->data = (struct PeoInfo*)malloc(CAPACITY_SZ * sizeof(struct Personal)); // void *malloc(size_t size) 分配所需的内存空间,并返回一个指向它的无类型指针。所以强制类型转换
if (Con->data == NULL)
{
printf("初始化失败\n");
exit(1); //exit(1)表示异常退出
}
LoadContact(Con); //读取文件中已有的
}
4.读取文件,动态初始化函数用到
void LoadContact(struct Contact* Con) //读取文件中已经有的
{
FILE* puin = fopen("contact.dat","rb"); //打开文件,二进制读
if (puin == NULL)
{
printf("打开失败\n");
return;
}
Persona tmp = { 0 }; //相当于中间变量
while (fread(&tmp, sizeof(Persona), 1, puin)) //取出一个单位的内容到tmp的地址中
{
if (Expansion(Con) == 0) //相当于增加,所以要判断容量
{
printf("容量不足且扩容失败\n");
return;
}
Con->data[Con->sz] = tmp; //当前位置的值
Con->sz++;
}
fclose(puin); //读完关闭文件,并将指针滞空
puin = NULL;
}
5.增加函数,先判断是否需要扩容
void addContacts(struct Contact * Con) //增加
{
if (Expansion(Con) == 0)
{
printf("容量不足且扩容失败\n");
return;
}
printf("请输入姓名:");
scanf("%s", &(Con->data[Con->sz].name));
printf("请输入年龄:");
scanf("%d", &(Con->data[Con->sz].age));
printf("请输入性别:");
scanf("%s", &(Con->data[Con->sz].sex));
printf("请输入电话:");
scanf("%s", &(Con->data[Con->sz].tell));
printf("请输入地址:");
scanf("%s", &(Con->data[Con->sz].address));
printf("保存成功\n");
(Con->sz)++;
}
6.扩容函数,增加函数中用到
int Expansion(struct Contact* Con) //扩容函数
{
if (Con->sz == Con->capacity) //满了才扩
{
//(起始地址,包含以前的大小的总大小所以是3+2)
struct PeoInfo* ptr = (struct PeoInfo*)realloc(Con->data, (Con->capacity + 2) * sizeof(struct Personal));
if (ptr == NULL)
{
printf("扩容失败\n");
return 0;
}
else
{
Con->data = ptr;
Con->capacity += 2;
printf("扩容成功\n");
return 1;
}
}
return 1;
}
7.展示函数,先判断是否为空。
void showContacts(struct Contact* pc)
{
int i = 0;
if ((pc->sz) == 0)
{
printf("通讯录为空\n");
}
else
{
printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
//%-20s -靠左,占20位 \t属于转义字符。是水平制表符
while (i < (pc->sz)) //从0向上加
{
printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].tell,
pc->data[i].address);
i++;
}
}
}
8.修改函数
void modContacts(struct Contact* Con) //修改
{
char name[NAME_MAX];
if (Con->sz == 0)
{
printf("通讯录为空\n");
}
else
{
printf("请输入需要修改人的姓名:>");
scanf("%s", &name);
int ret = FindName(name, Con); //这里Con本身就是指针变量,不能再取地址
if (ret == -1)
{
printf("不存在\n");
}
else
{
printf("请输入姓名:");
scanf("%s", &(Con->data[ret].name));
printf("请输入年龄:");
scanf("%d", &(Con->data[ret].age));
printf("请输入性别:");
scanf("%s", &(Con->data[ret].sex));
printf("请输入电话:");
scanf("%s", &(Con->data[ret].tell));
printf("请输入地址:");
scanf("%s", &(Con->data[ret].address));
printf("修改成功\n");
}
}
}
9.寻找名字对应的行数,修改中使用
static int FindName(char name[NAME_MAX],const struct Contact* Con) //寻找名字对应的行数,全局变量
{
int i = 0;
for (i = 0; i < Con->sz; i++)
{
//只能用strcmp判断完全相同,STRSTR不可
if (strcmp((Con->data[i].name), name) == 0)
{
return i;
}
}
return -1;
}
10.查找函数
void findContacts(struct Contact* Con) //查找
{
char name[NAME_MAX];
if (Con->sz == 0)
{
printf("通讯录为空\n");
}
else
{
printf("请输入需要查找人的姓名:>");
scanf("%s", &name);
int ret = FindName(name, Con); //这里Con本身就是指针变量,不能再取地址
if (ret == -1)
{
printf("查无此人\n");
}
else
{
printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n",
Con->data[ret].name,
Con->data[ret].age,
Con->data[ret].sex,
Con->data[ret].tell,
Con->data[ret].address);
}
}
}
11.删除函数
void delContacts(struct Contact* Con)
{
char name[NAME_MAX];
if (Con->sz == 0)
{
printf("通讯录为空,没法删除\n");
}
else
{
printf("请输入需要删除人的姓名:>");
scanf("%s", &name);
int ret = FindName(name, Con);
if (ret == -1)
{
printf("查无此人\n");
}
else
{
int j = 0;
for (j = ret; j < (Con->sz - 1); j++) //向前挪一个
{
Con->data[j] = Con->data[j + 1];
}
Con->sz--; //总数减一
printf("删除成功\n");
}
}
}
12.保存文件,也可使用其他保存类型
void saveContacts(struct Contact* Con)
{
FILE* pout = fopen("contact.dat", "wb"); //打开文件,二进制写
if (pout == NULL)
{
printf("打开失败\n");
return;
}
for (int i = 0; i < Con->sz; i++)
{
fwrite(Con->data + i, sizeof(Persona), 1, pout);
}
printf("保存成功\n");
fclose(pout);
pout = 0;
}
13.销毁函数,释放空间后,指针要滞空
void DestroyContacts(struct Contact* Con)
{
free(Con->data);
Con->data = NULL; //释放空间后要滞空
Con->capacity = 0;
Con->sz = 0;
printf("销毁成功\n"); //已经销毁
}
下面给出完整代码:
1.Contacts.h
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>
#define MAX 1000
#define NAME_MAX 20
#define SEX_MAX 5
#define TELL_MAX 12
#define ADDRESS_MAX 30
#define CAPACITY_SZ 3
typedef struct Personal //个人信息结构体
{
char name[NAME_MAX];
int age;
char sex[SEX_MAX];
char tell[TELL_MAX];
char address[ADDRESS_MAX];
}Persona;
//struct Contact //通讯录
//{
// Persona data[MAX]; //每创建一个就包含1000个 个人
// int sz;
//};
struct Contact //通讯录
{
Persona *data;
int sz;
int capacity; //最大容量
};
void addContacts(struct Contact* Con); //增加
void Initialize(struct Contact* Con); //初始化函数
void delContacts(struct Contact* Con); //删除
void modContacts(struct Contact* Con); //修改
void showContacts(struct Contact* Con); //展示
void findContacts(struct Contact* Con); //查找
void DestroyContacts(struct Contact* Con); //销毁
2.fun.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Contacts.h"
//void Initialize(struct Contact * Con)
//{
// Con->sz = 0;
// memset(Con->data, 0, sizeof(Con->data)); //void *memset(void *s, int ch, size_t n);将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
//}
int Expansion(struct Contact* Con) //扩容函数
{
if (Con->sz == Con->capacity) //满了才扩
{
//(起始地址,包含以前的大小的总大小所以是3+2)
struct PeoInfo* ptr = (struct PeoInfo*)realloc(Con->data, (Con->capacity + 2) * sizeof(struct Personal));
if (ptr == NULL)
{
printf("扩容失败\n");
return 0;
}
else
{
Con->data = ptr;
Con->capacity += 2;
printf("扩容成功\n");
return 1;
}
}
return 1;
}
void LoadContact(struct Contact* Con) //读取文件中已经有的
{
FILE* puin = fopen("contact.dat","rb"); //打开文件,二进制读
if (puin == NULL)
{
printf("打开失败\n");
return;
}
Persona tmp = { 0 }; //相当于中间变量
while (fread(&tmp, sizeof(Persona), 1, puin)) //取出一个单位的内容到tmp的地址中
{
if (Expansion(Con) == 0) //相当于增加,所以要判断容量
{
printf("容量不足且扩容失败\n");
return;
}
Con->data[Con->sz] = tmp; //当前位置的值
Con->sz++;
}
fclose(puin); //读完关闭文件,并将指针滞空
puin = NULL;
}
void Initialize(struct Contact* Con) //动态版本初始化
{
Con->sz = 0;
Con->capacity = CAPACITY_SZ;
Con->data = (struct PeoInfo*)malloc(CAPACITY_SZ * sizeof(struct Personal)); // void *malloc(size_t size) 分配所需的内存空间,并返回一个指向它的无类型指针。所以强制类型转换
if (Con->data == NULL)
{
printf("初始化失败\n");
exit(1); //exit(1)表示异常退出
}
LoadContact(Con); //读取文件中已有的
}
void addContacts(struct Contact * Con) //增加
{
if (Expansion(Con) == 0)
{
printf("容量不足且扩容失败\n");
return;
}
printf("请输入姓名:");
scanf("%s", &(Con->data[Con->sz].name));
printf("请输入年龄:");
scanf("%d", &(Con->data[Con->sz].age));
printf("请输入性别:");
scanf("%s", &(Con->data[Con->sz].sex));
printf("请输入电话:");
scanf("%s", &(Con->data[Con->sz].tell));
printf("请输入地址:");
scanf("%s", &(Con->data[Con->sz].address));
printf("保存成功\n");
(Con->sz)++;
}
void showContacts(struct Contact* pc)
{
int i = 0;
if ((pc->sz) == 0)
{
printf("通讯录为空\n");
}
else
{
printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
//%-20s -靠左,占20位 \t属于转义字符。是水平制表符
while (i < (pc->sz)) //从0向上加
{
printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",
pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].tell,
pc->data[i].address);
i++;
}
}
}
static int FindName(char name[NAME_MAX],const struct Contact* Con) //寻找名字对应的行数,全局变量
{
int i = 0;
for (i = 0; i < Con->sz; i++)
{
//只能用strcmp判断完全相同,STRSTR不可
if (strcmp((Con->data[i].name), name) == 0)
{
return i;
}
}
return -1;
}
void modContacts(struct Contact* Con) //修改
{
char name[NAME_MAX];
if (Con->sz == 0)
{
printf("通讯录为空\n");
}
else
{
printf("请输入需要修改人的姓名:>");
scanf("%s", &name);
int ret = FindName(name, Con); //这里Con本身就是指针变量,不能再取地址
if (ret == -1)
{
printf("不存在\n");
}
else
{
printf("请输入姓名:");
scanf("%s", &(Con->data[ret].name));
printf("请输入年龄:");
scanf("%d", &(Con->data[ret].age));
printf("请输入性别:");
scanf("%s", &(Con->data[ret].sex));
printf("请输入电话:");
scanf("%s", &(Con->data[ret].tell));
printf("请输入地址:");
scanf("%s", &(Con->data[ret].address));
printf("修改成功\n");
}
}
}
void findContacts(struct Contact* Con) //查找
{
char name[NAME_MAX];
if (Con->sz == 0)
{
printf("通讯录为空\n");
}
else
{
printf("请输入需要查找人的姓名:>");
scanf("%s", &name);
int ret = FindName(name, Con); //这里Con本身就是指针变量,不能再取地址
if (ret == -1)
{
printf("查无此人\n");
}
else
{
printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n",
Con->data[ret].name,
Con->data[ret].age,
Con->data[ret].sex,
Con->data[ret].tell,
Con->data[ret].address);
}
}
}
void delContacts(struct Contact* Con)
{
char name[NAME_MAX];
if (Con->sz == 0)
{
printf("通讯录为空,没法删除\n");
}
else
{
printf("请输入需要删除人的姓名:>");
scanf("%s", &name);
int ret = FindName(name, Con);
if (ret == -1)
{
printf("查无此人\n");
}
else
{
int j = 0;
for (j = ret; j < (Con->sz - 1); j++) //向前挪一个
{
Con->data[j] = Con->data[j + 1];
}
Con->sz--; //总数减一
printf("删除成功\n");
}
}
}
void saveContacts(struct Contact* Con)
{
FILE* pout = fopen("contact.dat", "wb"); //打开文件,二进制写
if (pout == NULL)
{
printf("打开失败\n");
return;
}
for (int i = 0; i < Con->sz; i++)
{
fwrite(Con->data + i, sizeof(Persona), 1, pout);
}
printf("保存成功\n");
fclose(pout);
pout = 0;
}
void DestroyContacts(struct Contact* Con)
{
free(Con->data);
Con->data = NULL; //释放空间后要滞空
Con->capacity = 0;
Con->sz = 0;
printf("销毁成功\n"); //已经销毁
}
3.test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Contacts.h"
enum Features
{
Exit = 0,
add,
del,
find,
mod,
show,
save,
Destroy,
};
void menu()
{
printf("*****************************\n");
printf("****1.add ****2. del ******\n");
printf("****3.find ****4. mod ******\n");
printf("****5.show ****6. save ******\n");
printf("****0.exit ****7. Dest******\n");
printf("*****************************\n");
printf("请选择--->");
}
int main()
{
int input = 0;
struct Contact Con; //创建一个通讯录
Initialize(&Con); //初始化
do
{
menu();
scanf("%d", &input);
switch (input)
{
case add:
addContacts(&Con);
break;
case del:
delContacts(&Con);
break;
case find:
findContacts(&Con);
break;
case mod:
modContacts(&Con);
break;
case show:
showContacts(&Con);
break;
case save:
saveContacts(&Con);
break;
case Destroy:
DestroyContacts(&Con);
break;
case Exit:
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
以上就是所有内容,希望大家多多指正!晚安!