contact.h
#ifndef __CONTACT__H
#define __CONTACT__H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <vld.h> //检测内存泄漏
#pragma warning (disable:4996)
#define MAX_NAME 10
#define MAX_SEX 5 //可能是中文可能是英文
#define MAX_TELE 12
#define MAX_ADDR 30
#define MAX_NUM 1000
#define DEFAULT_SIZE 2 //默认大小为2
enum Oper
{
EXIT,
ADD,
DEL,
SEAR,
SHOW,
CLEAR,
SORT,
DESTROY
};
typedef struct person
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tele[MAX_TELE];
char addr[MAX_ADDR];
}person; //个人信息
typedef struct contact
{
person *per; //per只有四个字节
//person per[MAX_NUM]; //每个人的信息由一个结构体组成,那么需要建立一个结构体数组来存放这些结构体 普通版本
int count;
int capacity;//容量
}contact;//通讯录
void initial(contact *p);//形参需要一个结构体指针来接收
void Addcontact(contact *p);
int Searcontact(contact *p);
void ShowContact(contact *p);
void Delcontact(contact *p);
void Clearcontact(contact *p);
void Destroycontact(contact *p);
#endif
main.c
#include "Contact.h"
void menu()
{
printf("****0.exit***********1.add*****\n");
printf("****2.del***********3.search*****\n");
printf("****4.show***********5.clear*****\n");
printf("****6.sort***********7.destroy*****\n");
printf("************************************\n");
}
int main()
{
int input = 0;
contact con;//定义一个通讯录,结构体传参不发生降维
initial(&con); //不传地址怎么修改里面的内容?
do
{
menu();
printf("请输入您的操作:");
scanf("%d", &input); //一定要加上取地址符,因为它是一个整型变量
switch (input)
{
case EXIT://使用枚举
break;
case ADD :
Addcontact(&con);
break;
case DEL:
Delcontact(&con);
break;
case SEAR:
Searcontact(&con);
break;
case SHOW:
ShowContact(&con);
break;
case CLEAR:
Clearcontact(&con);
break;
case SORT://可通过年龄排序,冒泡
break;
case DESTROY:
Destroycontact(&con);
break;
default:
break;
}
} while (input);
return 0;
}
contact.c
#include "Contact.h"
void LoadContact(contact *p)
{
FILE *pf = fopen("contact.bat", "rb");
person tmp = { 0 };
if (pf == NULL) //因为初始化加载的时候是没有这个文件的,第一次进行加载,什么都不做
{
return;
}
while (fread(&tmp, sizeof(person), 1, pf) > 0)//从pf文件里面读取到tmp中 返回值时读取成功的字节数
{
CheckFullAndRe(p);//必须判断是否为满,如果满了,扩容。
p->per[p->count] = tmp;
p->count++;
}
fclose(pf);
pf = NULL;
}
void initial(contact *p)
{
//p->count = 0;
//memset(p->per, '0', sizeof(p->per)); //初始化这个结构体数组 //普通版
p->count = 0;
p->capacity = DEFAULT_SIZE;
p->per = (person *)malloc( sizeof(person)*p->capacity);//第一次就是扩容至两个person结构体 malloc的返回值是void * 需要强转至与per类型相同
assert(p->per);//每开辟一次,都需要检查是否为空!!! //只能使用person!!! 不能使用p->per
LoadContact(p);
}
//返回值代表扩容是否成功
static int CheckFullAndRe(contact *p) //1 成功 0 失败
{
if (p->count == p->capacity)
{
person *ptr = NULL; //有可能realloc完失败了,会返回空给per,这样会导致per原来指向的内容没有了,所以需要一个临时指针。
ptr = (person*)realloc(p->per, sizeof(person)*p->capacity * 2); //开辟的新的空间的大小
if (ptr != NULL)
{
p->per = ptr;
p->capacity *= 2; //容量变成原来的2倍,然后更新容量
printf("扩容成功!\n");
return 1;
}
else
{
return 0;//扩容失败
}
}
return 1;//表示不需要扩容,可继续
}
void Addcontact(contact *p)
{
/*if (p->count == MAX_NUM)
{
printf("不好意思老铁,满了");
return;
}*/
if (CheckFullAndRe(p)!=1)
{
printf("扩容失败!");
return 0;
}
printf("请输入姓名:");
scanf("%s", p->per[p->count].name);//通讯录所指向的第几个人的name属性
printf("请输入年龄:");
scanf("%d", &(p->per[p->count].age));
printf("请输入性别:");
scanf("%s", p->per[p->count].sex);
printf("请输入电话:");
scanf("%s", p->per[p->count].tele);
printf("请输入住址:");
scanf("%s", p->per[p->count].addr);
printf("添加成功!\n");
p->count++;
}
int Searcontact(contact *p)
{
int i = 0;
char name[MAX_NAME];
if (p->count == 0)
{
printf("通讯录是空的!\n");
return -1;//这里如果不return 会导致程序继续往下走
}
printf("请输入要查找的姓名:");
scanf("%s", name);
for (; i < p->count; i++)
{
if (strcmp(p->per[i].name, name) == 0)
{
printf("已找到!\n");
printf("%-10s %-5s %-5s %-11s %-20s\n", "姓名", "年龄", "性别", "电话", "住址");
printf("%-10s %-5d %-5s %-11s %-20s\n", p->per[i].name, p->per[i].age, p->per[i].sex, p->per[i].tele, p->per[i].addr);
return i;
}
}
printf("没有这个人!\n");
return -1;
}
int Searcontact1(contact *p)
{
int i = 0;
char name[MAX_NAME] = { 0 };
if (p->count == 0)
{
printf("通讯录是空的!\n");
return -1;
}
printf("请输入要删除的姓名:");
scanf("%s", name);
for (; i < p->count; i++)
{
if (strcmp(p->per[i].name, name) == 0)
{
return i;
}
}
return -1;
}
void ShowContact(contact *p)
{
assert(p);
int i = 0;
printf("%-10s %-5s %-5s %-11s %-20s\n", "姓名", "年龄",
"性别", "电话", "住址");
for (i = 0; i < p->count; i++) //将count置0后,再次显示时,显而易见,数据虽然还在,但是循环不执行
{
printf("%-10s %-5d %-5s %-11s %-20s\n",
p->per[i].name, p->per[i].age,
p->per[i].sex, p->per[i].tele,
p->per[i].addr);
}
}
void Delcontact(contact *p)
{
int ret = Searcontact1(p);
int i = 0;
if (ret==-1)
{
printf("查无此人!\n");
return;
}
for (i = ret; i < p->count-1; i++) //最多只能走到倒数第二个数!!!!即长度为5(count),i不能等于4(count-1)
{
p->per[i] = p->per[i + 1];
}
p->count--;
printf("删除成功!\n");
}
void Clearcontact(contact *p)
{
p->count = 0;//最初存入一个用户的时候,结构体数组的第一个元素的下标是0,count更新为1;所以清空的时候将p->count 置0即可
}
//在摧毁之前我们需要用文件把信息存储起来
void Savecontact(contact *p)
{
FILE *pf = fopen("contact.bat", "wb");
assert(pf != NULL);
int i = 0;
for (; i < p->count; i++)
{
fwrite(p->per + i,sizeof(person),1,pf);
}
fclose(pf);
pf = NULL;
}
void Destroycontact(contact *p)
{
Savecontact(p);
free(p->per);
p->per = NULL;//预防野指针
p->capacity = 0;
p->count = 0;
}