前言
本文章重在讲述如何通讯录(存储内容的空间有限)优化成随着录入信息不断地增加动态开辟空间的通讯录。
提示:以下是本篇文章正文内容,下面案例可供参考
一、首先是创建结构体成员变量
1.创建一个含有联系人信息的结构体:
struct PeoInfo
{
char name[20];
char sex[5];
int age;
char phonenumber[11];
char address[30];
};
2.创建一个保存已录用联系人信息的结构体
struct Contact
{
struct PeoInfo* data;//指向PeoInfo结构体的指针
int sz;//已经放进多少组的信息
int capacity;//当前容量
};
二.明白动态内存函数的使用(malloc 、realloc、memset)
1.malloc
//该函数原型如下
void* malloc (size_t size);
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
-
如果开辟成功,则返回一个指向开辟好空间的指针。
-
如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
-
返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
-
如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。
2.realloc
//该函数原型如下
void* realloc (void* ptr, size_t size);
-
ptr 是要调整的内存地址
-
size 调整之后新大小
-
返回值为调整之后的内存起始位置。
-
这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到 新 的空间。
-
realloc在调整内存空间的是存在两种情况:
-
情况1:原有空间之后有足够大的空间
-
情况1:原有空间之后有足够大的空间
-
情况2:原有空间之后没有足够大的空间
-
3.memset
//该函数原型如下
void * memset ( void * ptr, int value, size_t num );
将 ptr 所指向的内存块的前 num 个字节设置为指定的值(解释为无符号字符)。 (此为机翻,若要详细了解memset的使用可以自行搜索。)
三.如何动态分配空间?
我们希望一开始先分配能存储三个联系人信息的空间:值得注意的是,如果我们不首先对指针con.data指向的数组开辟空间,memset函数是无法对所指向的空间进行初始化。
struct Contact con;
con.data = (struct PeoInfo* )malloc(3 * sizeof(struct PeoInfo));
开辟好空间后我们需要对这个空间初始化:
void InitContact(struct Contact* pc)
{
pc->sz = 0;
pc->capacity = 3;
//希望开始先动态分配能存储三个联系人信息的空间
memset(pc->data, 0, 3 * sizeof(pc->data[0]));
};
四.主函数设计
int main()
{
int input = 0;
struct Contact con;
con.data = (struct PeoInfo* )malloc(3 * sizeof(struct PeoInfo));
InitContact(&con);
do
{
menu();
printf("请选择\n");
scanf("%d", &input);
switch (input)
{
case 1:
AddContact(&con);
break;
case 2:
DelContact(&con);
break;
case 3:
SerchContact(&con);
break;
case 4:
ModifyContact(&con);
break;
case 5:
ShowContact(&con);
break;
case 6:
ClearContact(&con);
break;
case 7:
SortContact(&con);
break;
case 0:
printf("退出成功");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
free(con.data);
con.data = NULL;
return 0;
}
值得注意的是:当前空间是由我们自己(malloc)开辟的,所以当使用完后需要释放此空间,并将该指针置为NULL。
五.功能函数的设计
1.添加用户(AddContact)
void AddContact(struct Contact* pc)
{
printf("请输入姓名\n");
scanf("%s", pc->data[pc->sz].name);
printf("请输入电话\n");
scanf("%s", pc->data[pc->sz].phonenumber);
printf("请输入年龄\n");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入住址\n");
scanf("%s", pc->data[pc->sz].address);
printf("请输入性别\n");
scanf("%s", pc->data[pc->sz].sex);
pc->sz++;
printf("增加成功\n");
if (pc->sz == pc->capacity)
{
pc->data = (struct PeoInfo*)realloc(pc->data, (pc->sz + 3) * sizeof(struct PeoInfo));
pc->capacity += 3;
}
}
函数说明:每录用一次联系人的信息,都会对当前已录用联系人的个数以及当前容量进行判断,如果发现联系人个数和容量相等时,即空间已满,使用realloc函数再给它多分配三个联系人的空间 ,如此反复。
2. 显示用户
void ShowContact(const struct Contact* pc)
{
int i = 0;
printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
for (i = 0; i < pc->sz; i++)
{
printf(" % -20s\t % -5s\t % -5d\t % -12s\t % -30s\n", pc->data[i].name,
pc->data[i].sex,
pc->data[i].age,
pc->data[i].phonenumber,
pc->data[i].address);
}
}
对联系人数组进行遍历打印即可。
3.查找用户
static int FindPeople(const struct Contact* pc, char name[])
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (0 == strcmp(pc->data[i].name, name))
{
return i;
}
}
return -1;
}
首先引入一个自行设计的查找函数
void SerchContact(const struct Contact* pc)
{
char name[20] = "";
printf("请输入要查找人的姓名\n");
scanf("%s", name);
int i = FindPeople(pc, name);
if (i != -1)
{
printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
printf(" % -20s\t % -5s\t % -5d\t % -12s\t % -30s\n", pc->data[i].name,
pc->data[i].sex,
pc->data[i].age,
pc->data[i].phonenumber,
pc->data[i].address);
}
else
printf("为查询到此人\n");
}
在下面的查找函数中调用FindPeople函数,并接收它的返回值。
4.修改联系人
void ModifyContact(struct Contact* pc)
{
char name[20] = "";
printf("请输入要修改人的姓名\n");
scanf("%s", name);
int i = FindPeople(pc, name);
if (i != -1)
{
printf("请输入姓名\n");
scanf("%s", pc->data[i].name);
printf("请输入电话\n");
scanf("%s", pc->data[i].phonenumber);
printf("请输入年龄\n");
scanf("%d", &(pc->data[i].age));
printf("请输入住址\n");
scanf("%s", pc->data[i].address);
printf("请输入性别\n");
scanf("%s", pc->data[i].sex);
printf("修改成功\n");
}
else
printf("未查询到此人\n");
}
使用FindPeople函数找到数组中此联系人的下标,对它进行修改即可
5. 排序联系人
static int Compair(const void* a, const void* b)
{
return strcmp(((struct PeoInfo*)a)->name, ((struct PeoInfo*)b)->name);
}
void SortContact(struct Contact* pc)
{
qsort(pc->data, pc->sz, sizeof(struct PeoInfo), Compair);
}
使用联系人的姓名进行排序,qosrt中的比较函数为自行写的Compair 函数。
6. 删除联系人
void DelContact(struct Contact* pc)
{
char name[20] = " ";
printf("请输入要删除的联系人");
scanf("%s", name);
int i = FindPeople(pc, name);
if (i != -1)
{
int j = 0;
for (j = i; j < pc->sz - 1; j++)
{
pc->data[j] = pc->data[j + 1];
}
pc->sz--;
printf("成功删除指定联系人\n");
}
}
7. 清空联系人
void ClearContact(struct Contact* pc)
{
memset(pc->data, 0, pc->capacity * sizeof(struct PeoInfo));
pc->sz = 0;
}
利用memset函数将当前联系人数组所占空间全部置为0。
总结
- 保存已录用联系人信息的结构体中,可以设置一个指向联系人结构体的指针,利用该指针对联系人结构体进行操作。
- 创建了结构体成员变量后,需要对其先开辟空间后才可以对内存进行初始(memset)