1.前言
本次展示是基于上期代码让你迷上动态内存的用法及管理的基础上进行修改的,上一期分享的通讯录设计其实还存在很多的不足之处。其一就是我们的成员人数是固定的1000个,但是如果我们要给用户使用的话我们并不知道用户需要多少个成员,如果要的个数大于1000了那么空间就不够了,如果要的个数小于1000那多出来的空间就浪费掉了。其二就是我们修改成员的时候,如果我们只要修改成员里面的一个信息而不是都修改那其实我们并不要将每个信息都查找一遍,而是单单找到成员信息里面的一个信息进行修改就行了。好了既然找到问题了,那我们就来解决问题。
2.主要改进
2.1自定义类型的重命名
我们在创建结构体成员的时候用到了结构体:
struct Contactinfo
{
char name[MAX_NAME];
int age;
char tala[MAX_TALA];
char sex[MAX_SEX];
char add[MAX_ADD];
};
struct Contact
{
struct Contactinfo s[MAX];
int size;
};
但是你会发现如果我们这样使用的话结构的的类型就是struct Contactinfo和struct Contact一旦我们要使用结构体的时候我们都要写上struct+结构体名这样的形式,这给时候我们就想到了用typedef关键字来重命名。
typedef struct Contactinfo
{
char name[MAX_NAME];
int age;
char tala[MAX_TALA];
char sex[MAX_SEX];
char add[MAX_ADD];
}Contactinfo;
typedef struct Contact
{
struct Contactinfo s[MAX];
int size;//记录当前个数
}Contact;
2.2成员动态创建
之前我们创建成员的时候是固定成员个数是1000给属于静态创建,而其实我们想要达到的效果是先创建一块比较小的空间进行添加成员,如果要的成员个数大于所开辟的空间我们在对其进行追加,这样既可以满足成员添加的需求,还可以避免空间的浪费,那这就得涉及动态内存的开辟了。
之前我们的代码是:
typedef struct Contact
{
struct Contactinfo s[MAX];
int size;//记录当前个数
}Contact;
这个代码是定义了一个结构体数组来存放1000个成员的信息的,但是空间开辟是固定的,所以我们并不采用。我们采用的是通过创建一个结构体指针,用这个指针来指向所开辟的空间,struct Contactinfo *s;。但是我们想啊,既然这块空间是达到了我们所定义的标准就自动追加一定的空间,到了一定的空间就自动追加,那我们就需要一个变量capacity来记录当前的容量,并通过size与capacity变量进行对比,看是否要进行内存追加,思路设计好了我们来实现代码。
typedef struct Contact
{
struct Contactinfo *s;
int capacity;//记录当前容量
int size;//记录当前个数
}Contact;
结构体的创建好了接下来就是成员的初始化了。
void ContactBigan( Contact* ps)
{
ps->s =( Contactinfo*) malloc(3* sizeof( Contactinfo));
//判断是否开辟成功
if (ps->s == NULL)
{
return;
}
ps->size = 0;
ps->capacity = 3;
}
这里我们给结构体指针先开辟了大小为3的结构体成员大小。
我们观察一下我们通讯录的功能当中只有添加成员这项功能涉及到了内存的变化。我们现在要实现的就是空间不够了,我们就对其进行追加空间,这就要用到realloc函数。
void ChekCapacity( Contact* ps)
{
if (ps->size == ps->capacity)
{
Contactinfo* ptr=realloc(ps->s, (ps->capacity + 2) * sizeof( Contactinfo));
if (ptr != NULL)
{
ps->s = ptr;
ps->capacity += 2;//如果满了就追加2个大小的空间
printf("增容成功\n");
}
else
{
printf("增容失败\n");
}
}
}
void ContactAdd( Contact* ps)
{
//检查通讯录的容量
ChekCapacity(ps);
//添加信息
printf("请输入添加的姓名:");
scanf("%s", ps->s[ps->size].name);
printf("请输入添加的年龄:");
scanf("%d", &(ps->s[ps->size].age));
printf("请输入添加的电话:");
scanf("%s", ps->s[ps->size].tala);
printf("请输入添加的性别:");
scanf("%s", ps->s[ps->size].sex);
printf("请输入添加的住址:");
scanf("%s", ps->s[ps->size].add);
ps->size++;
printf("添加成功\n");
}
效果展示:
2.3成员修改
我们刚才提到了我们进行成员的修改的时候,可能并不会把所有的信息都修改吊,可能只是改其中信息之一,所以我们就可以对一个成员的基本信息用一个switch语句进行选择。
void ContactModify( Contact* ps)
{
printf("请输入要修改人的名字");
int ret = find(ps);
if (ret == -1)
{
printf("要修改的人不在通讯录\n");
}
else
{
int input = 0;
do
{
printf("%s\t%s\t%s\t%s\t%s\t%s\n", "1.name", "2.age", "3.tala", "4.sex", "5.add", "0,exit");
printf("请输入要修改的信息:");
scanf("%d", &input);
switch(input)
{
case name:
printf("请输入修改的姓名:");
scanf("%s", ps->s[ret].name);
break;
case age:
printf("请输入修改的年龄:");
scanf("%d", &(ps->s[ret].age));
break;
case tala:
printf("请输入修改的电话:");
scanf("%s", ps->s[ret].tala);
break;
case sex:
printf("请输入修改的性别:");
scanf("%s", ps->s[ret].sex);
break;
case add:
printf("请输入修改的住址:");
scanf("%s", ps->s[ret].add);
break;
case run:
break;
default:
break;
}
} while (input);
ContactShow(ps);
}
}
这里我们还可以在定义一个枚举类型在增加代码的可读性。
enum s2
{
run,
name,
age,
tala,
sex,
add
};
展示效果:
2.4空间释放
之前我们说过了malloc和free是同时出现的,既然我们用malloc开辟了一块空间当我们用完的时候就要还给操作系统,不然可能会造成内存泄漏。
void DestroyContact( Contact* ps)
{
free(ps->s);
ps->s = NULL;
}
4.整体代码展示
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
//#define MAX 1000
#define DEFAULT_SZ 3
#define MAX_NAME 20
#define MAX_TALA 12
#define MAX_SEX 8
#define MAX_ADD 20
typedef struct Contactinfo
{
char name[MAX_NAME];
int age;
char tala[MAX_TALA];
char sex[MAX_SEX];
char add[MAX_ADD];
}Contactinfo;
typedef struct Contact
{
struct Contactinfo* s;
int capacity;//记录当前容量
int size;//记录当前个数
}Contact;
enum s1
{
Exit,
Add,
Show,
Seatch,
Del,
Modify,
Sort
};
enum s2
{
run,
name,
age,
tala,
sex,
add
};
//初始化结构体
void ContactBigan(Contact* ps);
//成员的增加
void ContactAdd( Contact* ps);
//成员的展示
void ContactShow(const Contact* ps);
//成员的查找
void ContactSeatch(const Contact* ps);
//成员的删除
void ContactDel( Contact* ps);
//成员的修改
void ContactModify( Contact* ps);
//成员的排序
void ContactSort( Contact* ps);
//释放空间按
void DestroyContact( Contact* ps);
#include "contact.h"
void ContactBigan( Contact* ps)
{
ps->s =( Contactinfo*) malloc(DEFAULT_SZ * sizeof( Contactinfo));
//判断是否开辟成功
if (ps->s == NULL)
{
return;
}
ps->size = 0;
ps->capacity = DEFAULT_SZ;
}
void ChekCapacity( Contact* ps)
{
if (ps->size == ps->capacity)
{
Contactinfo* ptr=realloc(ps->s, (ps->capacity + 2) * sizeof( Contactinfo));
if (ptr != NULL)
{
ps->s = ptr;
ps->capacity += 2;
printf("增容成功\n");
}
else
{
printf("增容失败\n");
}
}
}
void ContactAdd( Contact* ps)
{
//检查通讯录的容量
ChekCapacity(ps);
printf("请输入添加的姓名:");
scanf("%s", ps->s[ps->size].name);
printf("请输入添加的年龄:");
scanf("%d", &(ps->s[ps->size].age));
printf("请输入添加的电话:");
scanf("%s", ps->s[ps->size].tala);
printf("请输入添加的性别:");
scanf("%s", ps->s[ps->size].sex);
printf("请输入添加的住址:");
scanf("%s", ps->s[ps->size].add);
ps->size++;
printf("添加成功\n");
}
void ContactShow(const Contact* ps)
{
if (ps->size == 0)
{
printf("通讯录为空\n");
}
else
{
//打印列表
printf("%-10s\t%-8s\t%-15s\t%-6s\t%-20s\n", "姓名", "年龄", "电话", "性别", "住址");
//打印成员
int i = 0;
for (i = 0; i < ps->size; i++)
{
printf("%-10s\t%-8d\t%-15s\t%-6s\t%-20s\n",
ps->s[i].name,
ps->s[i].age,
ps->s[i].tala,
ps->s[i].sex,
ps->s[i].add);
}
}
}
static int find(const Contact* ret)
{
char name[MAX_NAME];
scanf("%s", name);
int i = 0;
for (i = 0; i < ret->size; i++)
{
if (strcmp(name, ret->s[i].name) == 0)
{
return i;
}
}
return -1;
}
void ContactSeatch(const Contact* ps)
{
//查找成员的名字
printf("请输入要查人的名字:");
int ret=find(ps);
if (ret == -1)
{
printf("要查找的人不在通讯录\n");
}
else
{
printf("%-10s\t%-8s\t%-15s\t%-6s\t%-20s\n", "姓名", "年龄", "电话", "性别", "住址");
printf("%-10s\t%-8d\t%-15s\t%-6s\t%-20s\n",
ps->s[ret].name,
ps->s[ret].age,
ps->s[ret].tala,
ps->s[ret].sex,
ps->s[ret].add);
}
}
void ContactDel( Contact* ps)
{
printf("请输入要删除人的名字:");
int ret=find(ps);
if (ret == -1)
{
printf("要删除的人不在通讯录\n");
}
else
{
int i = 0;
for (i = ret; i < ps->size - 1; i++)
{
ps->s[i] = ps->s[i + 1];
}
ps->size--;
printf("删除成功\n");
ContactShow(ps);
}
}
void ContactModify( Contact* ps)
{
printf("请输入要修改人的名字");
int ret = find(ps);
if (ret == -1)
{
printf("要修改的人不在通讯录\n");
}
else
{
int input = 0;
do
{
printf("%s\t%s\t%s\t%s\t%s\t%s\n", "1.name", "2.age", "3.tala", "4.sex", "5.add", "0,exit");
printf("请输入要修改的信息:");
scanf("%d", &input);
switch(input)
{
case name:
printf("请输入修改的姓名:");
scanf("%s", ps->s[ret].name);
break;
case age:
printf("请输入修改的年龄:");
scanf("%d", &(ps->s[ret].age));
break;
case tala:
printf("请输入修改的电话:");
scanf("%s", ps->s[ret].tala);
break;
case sex:
printf("请输入修改的性别:");
scanf("%s", ps->s[ret].sex);
break;
case add:
printf("请输入修改的住址:");
scanf("%s", ps->s[ret].add);
break;
case run:
break;
default:
break;
}
} while (input);
ContactShow(ps);
}
}
void ContactSort( Contact* ps)
{
int i = 0;
for (i = 0; i < ps->size - 1; i++)
{
int j = 0;
for (j = 0; j < ps->size - 1 - i; j++)
{
if (strcmp(ps->s[j].name, ps->s[j + 1].name) > 0)
{
struct Contactinfo tmp= ps->s[j];
ps->s[j] = ps->s[j + 1];
ps->s[j + 1] = tmp;
}
}
}
printf("排序成功\n");
ContactShow(ps);
}
void DestroyContact( Contact* ps)
{
free(ps->s);
ps->s = NULL;
}
#include "contact.h"
void emun()
{
printf("*************************************\n");
printf("*** 1.Add 2.Show *****\n");
printf("*** 3.Seatch 4.Del *****\n");
printf("*** 5.Modify 6.Sort *****\n");
printf("*** 0.Exit *****\n");
printf("*************************************\n");
}
int main()
{
int input = 0;
//创建结构体
struct Contact con;
//初始化结构体
ContactBigan(&con);
do
{
emun();
printf("请输入:>");
scanf("%d", &input);
switch (input)
{
case Add:
ContactAdd(&con);
break;
case Show:
ContactShow(&con);
break;
case Seatch:
ContactSeatch(&con);
break;
case Del:
ContactDel(&con);
break;
case Modify:
ContactModify(&con);
break;
case Sort:
ContactSort(&con);
break;
case Exit:
DestroyContact(&con);
break;
default:
printf("选择错误\n");
break;
}
} while (input);
return 0;
}