我们都知道通讯录有的一些基本简单的功能就是:
1.增加联系人 2.删除联系人
3.查找联系人 4.改动联系人
5.显示联系人 6. 清空联系人
7.给联系人排序 0. 退出
具有了这些基本的功能之后就是一个简单的通讯录了。说起来是不是很简单,当我初始准备确实现它的时候,我觉得真的好难好难。
其实简单的方法就是开始就给它一块固定大小的空间,比如100, 1000,但是如果我们这样去实现一个通讯录,就感觉太死板了,如果我的联系人比较广泛,申请固定大小的空间不足以存储了怎么办?还有就是如果我的联系人就那么几个,那么一开始给定太多的内存,是不是造成了空间的浪费呢?
想到了这些问题后,我就想到了使用动态内存(malloc),这使得我们的通讯录更加的灵活,使用起来也特别的方便。
但是问题就来了,具体我要怎么去动态申请一块空间?然后当我申请的空间不够的时候,怎么让它自动的增加一定大小的空间,这个问题困扰了我很久,最后终于找到了解决的办法。
一. 首先使用malloc动态申请一块内存,malloc使用方法如下:
void *malloc( size_t size );
2.当申请的空间不够的时候,使用realloc函数进行续接,在使用之前我们要注意的就是realloc这个函数,的返回值有可能不是初始申请空间的首地址,所以在使用它时候一定要小心。使用方法如下:
void *realloc( void *memblock, size_t size );
3.注意把这所有的一切都做完了以后,千万记得动态内存的释放,否则产生野指针就麻烦了。
解决了这些个问题以后,其他的都不难了,接下来我们看看具体的实现过程。
//头文件"contact.h"
#ifndef __CONTACT_H__
#define __CONTACT_H__
#define NAME_MAX 10
#define SEX_MAX 3
#define TEL_MAX 12
#define ADDR_MAX 12
#define INC 10 //不够存储时再增加
#define FIR 10 //初始申请10个人的空间
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
enum OP //枚举所有的函数,使程序的可读性更高
{
EXIT,
ADD,
DEL,
SEARCH,
CHANGE,
DISP,
EMPTY,
RANK
};
typedef struct Contact //定义一个结构体保存联系人相关信息
{
char name[NAME_MAX]; //名字
char sex[SEX_MAX]; //性别
int age; //年龄
char tel[TEL_MAX]; //电话
char addr[ADDR_MAX]; //住址
}Contact;
typedef struct List
{
Contact* data;
int count;
int sz;
}List, *Peo;
void Init_contact(Peo p);//动态内存申请
void Add_contact(Peo p);//添加联系人
void Del_contact(Peo p);//删除联系人
void Search_contact(Peo p);//查找联系人
void Change_contact(Peo p);//改动联系人
void Disp_contact(Peo p);//显示联系人
void Empty_contact(Peo p);//清空联系人
void Rank_contact(Peo p);//联系人排序
void release(Peo p);//动态内存释放
#endif //__CONTACT_H__
//函数部分 contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"
void Init_contact(Peo p) //初始化并动态申请一块空间
{
p->data = (Contact *)malloc(sizeof(Contact));
if(p->data == NULL)
{
printf("%s\n", strerror(errno));
exit(0);
}
else
{
memset(p->data, 0, FIR*sizeof(Contact));
p->count = 0;
p->sz = FIR;
}
}
static void Check_contact(Peo p) //检查是否人数是否达到上限,\
由于只是做简单检测,所以适用了static
{
if((p->count) == (p->sz))
{
Contact *ptr = (Contact*)realloc(p->data,(p->count+INC)*sizeof(Contact));
if(ptr == NULL)
{
printf("%s\n", strerror(errno));
exit(0);
}
else
{
p->data = ptr;
p->sz += INC;
}
}
}
static int find(Peo p, char name[]) //查看是否存在某个人
{
int i = 0;
if(p->count == 0)
printf("通讯录为空\n");
for(i=0; i<p->count; i++)
{
if(strcmp(p->data[i].name, name) == 0)
return i;
}
return -1;
}
void Add_contact(Peo p) //添加联系人
{
Check_contact(p);
printf("输入名字:");
scanf("%s", p->data[p->count].name);
printf("输入性别:");
scanf("%s", p->data[p->count].sex);
printf("输入年龄:");
scanf("%d", &p->data[p->count].age);
printf("输入电话:");
scanf("%s", p->data[p->count].tel);
printf("输入住址:");
scanf("%s", p->data[p->count].addr);
p->count++;
}
void Del_contact(Peo p)//删除联系人
{
int i = 0;
int j = 0;
int ret = 0;
char name[NAME_MAX] = {0};
Check_contact(p);
printf("请输入要删除的人名:");
scanf("%s", name);
ret = find(p, name);
if(ret == -1)
{
printf("不存在这个人\n");
return;
}
for(j=ret; j<p->count; j++)
{
p->data[j] = p->data[j+1];
}
p->count--;
printf("删除成功\n");
}
void Search_contact(Peo p)//查找某个联系人
{
int i = 0;
//int j = 0;
int ret = 0;
char name[NAME_MAX] = {0};
Check_contact(p);
printf("请输入要查找的人名:");
scanf("%s", name);
ret = find(p, name);
if(ret == -1)
{
printf("要查找的人不存在\n");
return;
}
else
{
printf("%10s%5s%5s%10s%10s\n","name", "sex", "age", "tel", "addr");
printf("%10s%5s%5d%10s%10s\n", p->data[i].name,
p->data[i].sex,
p->data[i].age,
p->data[i].tel,
p->data[i].addr );
}
}
void Change_contact(Peo p) //改动某个联系人
{
int ret = 0;
int a = 0;
char name[NAME_MAX] = {0};
printf("请输入要改的人名:");
scanf("%s", name);
ret = find(p, name);
if(ret == -1)
{
printf("不存在这个人\n");
return;
}
printf("请选择改动类型:");
//printf("*************************************************\n");
printf("1.名字 2.性别 3.年龄 4.电话 5.住址 0.退出\n");//选择确定的改动方式
//printf("*************************************************\n");
scanf("%d", &a);
switch(a)
{
case 1:
printf("name:");
scanf("%s", p->data[ret].name);
break;
case 2:
printf("sex:");
scanf("%s", p->data[ret].sex);
break;
case 3:
printf("age:");
scanf("%d", &p->data[ret].age);
break;
case 4:
printf("tel:");
scanf("%s", p->data[ret].tel);
break;
case 5:
printf("addr:");
scanf("%s", p->data[ret].addr);
break;
case 0:
break;
default:
printf("输入有误:");
}
}
void Disp_contact(Peo p) //显示联系人
{
int i = 0;
printf("%10s%5s%5s%10s%10s\n","name", "sex", "age", "tel", "addr");
for(i=0; i<p->count; i++)
{
printf("%10s%5s%5d%10s%10s\n", p->data[i].name,
p->data[i].sex,
p->data[i].age,
p->data[i].tel,
p->data[i].addr );
}
}
void Empty_contact(Peo p) //清空联系人
{
p->count = 0;
}
void Rank_contact(Peo p) //联系人按照名字排序
{
int i = 0;
int j = 0;
for(i=0; i<p->count; i++)
{
for(j=0; j<p->count-i-1; j++)
{
if(strcmp(p->data[j].name, p->data[j+1].name)>0)
{
Contact tmp = p->data[j];
p->data[j] = p->data[j+1];
p->data[j+1] = tmp;
}
}
}
}
void release(Peo p) //动态内存释放,很重要,避免产生野指针
{
if(p->data != NULL)
{
free(p->data);
}
p->data = NULL;
}
//测试函数部分 test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"
void menu()
{
printf("*****************************************************\n");
printf("************ address lists *******************\n");
printf("********1 add 2 delete *****\n");
printf("********3 search 4 change *****\n");
printf("********5 disp 6 empty *****\n");
printf("********7 rank 0 exit *****\n");
printf("*****************************************************\n");
}
int main()
{
int input = 0;
List con;
int ret = 0;
//法一:初始化一个函数指针数组,通过数组下标去进行函数调用
void (*pfun[8])(Peo) = {NULL ,Add_contact, Del_contact, Search_contact,
Change_contact, Disp_contact, Rank_contact};
Init_contact(&con);
do
{
menu();
printf("请选择>");
scanf("%d", &input);
(*pfun[input])(&con);
//法二:使用switch case 语句进行函数调用
/*switch(input)
{
case ADD:
Add_contact(&con);
break;
case RANK:
Rank_contact(&con);
break;
case DEL:
Del_contact(&con);
break;
case SEARCH:
Search_contact(&con);
break;
case CHANGE:
Change_contact(&con);
break;
case DISP:
Disp_contact(&con);
break;
case EMPTY:
Empty_contact(&con);
break;
case EXIT:
release(&con);
break;
default:
printf("输入有误:\n");
break;
}*/
}while(input);
return 0;
}