为了使用通讯录时,可以随时调整大小,所以使用动态开辟内存函数写通讯录,可增加联系人容量。
动态开辟函数,即在内存的栈区开辟空间,所以使用完毕后,需要释放内存空间。
一、通讯录运行图
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<stdlib.h>
#define Max 10
enum function
{
quit,//退出 默认值为0
increase,//增加 默认值为1
delete,//删除 默认值为2
find,//查找 默认值为3
revise,//修改 默认值为4
show,//展示 默认值为5
empty,//清空 默认值为6
sort//排序 默认值为7
};
//创建人
typedef struct Person
{
char name[20];//姓名
size_t age;//年龄
char sex[8];//性别
char address[15];//地址
char phone[12];//电话
}person;
//动态
//创建通讯录
typedef struct contact
{
person *per;//指向人这个结构体类型
size_t sz;//通讯录已有人员个数
size_t ContactMax;//通讯录当前最大容量
}contact;
//初始化
void init_contact(contact* con);
//增容
void tune(contact* con);
//增加
void increase_contact(contact* con);
//删除
void delete_contact(contact* con);
//查找
//return -1(no) / address(yes)
int find1(const contact** con);
void find_contact(const contact* con);
//修改
void revise_contact(contact* con);
//展示
void show_contact(const contact* con);
//排序通讯录
void sort_contact(contact* con);
//销毁通讯录
void destroy_contact(contact* con);
//保存文件
void save_contact(contact* con);
//将文件信息保存到通讯录中
void load_contact(contact* con);
#include "contact.h"
void menu1()
{
printf("**************************************\n");
printf("******* Simplified address book ******\n");
printf("******* 1> increase contact ******\n");
printf("******* 2> delete contact ******\n");
printf("******* 3> find contact ******\n");
printf("******* 4> revise contact ******\n");
printf("******* 5> Show all contacts ******\n");
printf("******* 6> Empty all contacts ******\n");
printf("******* 7> Sort by name ******\n");
printf("******* 0> Quit Contacts ******\n");
printf("**************************************\n");
}
void test()
{
//创建通讯录
contact con;
//初始化通讯录
init_contact(&con);
//将文件信息保存到通讯录中
load_contact(&con);
size_t choice = 0;
do
{
menu1();
printf("请输入您的选择性:");
scanf("%u", &choice);
switch (choice)
{
case increase:
//增加
increase_contact(&con);
break;
case delete:
//删除
delete_contact( &con );
break;
case find:
//查找
find_contact(&con);
break;
case revise:
//修改
revise_contact(&con);
break;
case show:
//展示
show_contact(&con);
break;
case empty:
//清空
init_contact(&con);
break;
case sort:
//排序
sort_contact(&con);
break;
case quit:
//保存
save_contact(&con);
//销毁
destroy_contact(&con);
printf("Exiting Contacts...\n");
break;
default:
printf("You entered the wrong number, please re-enter it.\n");
break;
}
} while (choice);
printf("Exited Contacts.\n");
}
int main()
{
test();
return 0;
}
#include"contact.h"
void menu2()
{
system("cls");
printf("1> name \t 2> age\n");
printf("3> sex \t 4> address\n");
printf("5> phone\n");
printf("Please select:");
}
//动态
void init_contact(contact* con)
{
assert(con);
// per sz ContactMax
con->sz = 0;
person* p = (person*)calloc(Max, sizeof(person));
if (p == NULL)
{
perror("init_contact::calloc");
return;
}
con->per = p;
con->ContactMax = Max;
}
//将文件信息保存到通讯录中
void load_contact(contact* con)
{
//打开文件
FILE* p = fopen("contact.txt", "rb");
if (p == NULL)
{
perror("load_contact::fopen");
return;
}
person tmp = { 0 };
size_t i = 0;
while(fread(&tmp, sizeof(person), 1, p))
{
//考虑增容
tune(con);
con->per[i] = tmp;
con->sz++;
i++;
}
//关闭文件
fclose(p);
p = NULL;
}
void tune(contact* con)
{
if (con->sz == con->ContactMax)
{
person *p = (person *)realloc(con->per, (con->ContactMax + Max) * sizeof(person));
if (p == NULL)
{
perror("tune::realloc");
return;
}
con->per = p;
con->ContactMax += Max;
}
}
//动态开辟
void increase_contact(contact* con)
{
assert(con);
//检测当前通讯录是否需要增容
tune(con);
printf("name:");
scanf("%s", &(con->per[con->sz].name));
printf("age:");
scanf("%u", &(con->per[con->sz].age));
printf("sex:");
scanf("%s", &(con->per[con->sz].sex));
printf("address:");
scanf("%s", &(con->per[con->sz].address));
printf("phone:");
scanf("%s", &(con->per[con->sz].phone));
(con->sz)++;
}
void delete_contact(contact* con)
{
assert(con);
int result = find1(&con);
if (result != -1)
{
char true[5] = { 0 };
printf("Are you sure you want to delete %s's information?", &con->per[result].name);
printf("yes/no:");
scanf("%s", true);
if (!strcmp(true, "yes"))
{
if ( con->sz )
{
memmove(con->per[result].name, con->per[(con->sz) - 1].name, sizeof(con->per[0]));
}
else
{
memset(con->per[result].name, 0, sizeof(con->per[0]));
}
(con->sz)--;
printf("The deletion was successful, thanks for using!\n");
}
else
{
printf("Delete failed, please try again!\n");
}
}
else
{
printf("Delete failed, please try again!\n");
}
}
int find1(const contact** con)
{
assert(*con);
size_t i = 0;
char sample1[20] = { 0 };
printf("请输入你要查找的名字:");
scanf("%s", sample1);
while (i < (*con)->sz)
{
if (!strcmp(sample1, (*con)->per[i].name))
{
return i;
}
else
{
i++;
}
}
return -1;
}
void find_contact(const contact* con)
{
assert(con);
int result = find1(&con);
if (result != -1)
{
printf("Found, the basic information of the contact is:");
printf("name:%-20s\tage:%-4d\tsex:%-5s\taddress:%-30s\tphone:%-12s\n",
con->per[result].name,
con->per[result].age,
con->per[result].sex,
con->per[result].address,
con->per[result].phone);
}
else
{
printf("Didn't find it!\n");
}
}
void revise_contact(contact* con)
{
assert(con);
int result = find1(&con);
if (result != -1)
{
char choice1[5] = { 0 };
printf("Are you sure you want to revise %s's information?", con->per[result].name);
printf("yes/no:");
scanf("%s", choice1);
if (!strcmp(choice1, "yes"))
{
menu2();
printf("Please enter the option you want to modify:");
int choice2 = -1;
scanf("%d", &choice2);
char sample1[30] = { 0 };
size_t sample2 = 0;
printf("请输入:");
switch ( choice2 )
{
case 1:
case 3:
case 4:
case 5:
scanf("%s", sample1);
break;
case 2:
scanf("%d", sample2);
break;
}
switch (choice2)
{
case 1:
memmove(con->per[result].name, sample1, sizeof(sample1));
break;
case 3:
memmove(con->per[result].sex, sample1, sizeof(sample1));
break;
case 4:
memmove(con->per[result].address, sample1, sizeof(sample1));
break;
case 5:
memmove(con->per[result].phone, sample1, sizeof(sample1));
break;
case 2:
con->per[result].age = sample2;
break;
}
printf("修改成功,感谢使用!!!\n");
}
else
{
printf("修改失败,请再次尝试!!!\n");
}
}
else
{
printf("修改失败,请再次尝试!!!\n");
}
}
void show_contact(const contact* con)
{
assert(con);
printf("\n\n================================================\n");
printf("================================================\n\n");
if ( con->sz )
{
size_t i = 0;
for (; i < (con->sz); i++)
{
printf("name:%-20s\tage:%-4d\tsex:%-8s\taddress:%-15s\tphone:%-12s\n",
con->per[i].name, con->per[i].age, con->per[i].sex,
con->per[i].address, con->per[i].phone);
}
printf("\n\n");
}
else
{
printf("There is no contact information in the address book!\n");
}
}
int cmp_char(const void* str1, const void* str2)
{
return strcmp(((person*)str1)->name, ((person*)str2)->name);
}
void sort_contact(contact* con)
{
qsort(con -> per[0].name, con -> sz, sizeof(con -> per[0]), cmp_char);
}
void destroy_contact(contact* con)
{
free(con->per);
con->per = NULL;
con->ContactMax = 0;
con->sz = 0;
con = NULL;
}
void save_contact(contact* con)
{
//写文件
FILE* p = fopen("contact.txt", "wb");
if (p == NULL)
{
perror("save_contact::fopen");
return;
}
int i = 0;
for (i = 0; i < con->sz; i++)
{
fwrite(con->per + i, sizeof(person), 1, p);
}
//关闭文件
fclose(p);
p = NULL;
printf("保存成功\n");
}
使用realloc()调整通讯录大小。
联系人信息图为:
void tune(contact* con)
{
if (con->sz == con->ContactMax)
{
person *p = (person *)realloc(con->per, (con->ContactMax + Max) * sizeof(person));
if (p == NULL)
{
perror("tune::realloc");
return;
}
con->per = p;
con->ContactMax += Max;
}
}
//动态开辟
void increase_contact(contact* con)
{
assert(con);
//检测当前通讯录是否需要增容
tune(con);
printf("name:");
scanf("%s", &(con->per[con->sz].name));
printf("age:");
scanf("%u", &(con->per[con->sz].age));
printf("sex:");
scanf("%s", &(con->per[con->sz].sex));
printf("address:");
scanf("%s", &(con->per[con->sz].address));
printf("phone:");
scanf("%s", &(con->per[con->sz].phone));
(con->sz)++;
}
通过联系人的姓名来查找需要删除的联系人,找到之后确认删除该联系人。
例如:
int find1(const contact** con)
{
assert(*con);
size_t i = 0;
char sample1[20] = { 0 };
printf("请输入你要查找的名字:");
scanf("%s", sample1);
while (i < (*con)->sz)
{
if (!strcmp(sample1, (*con)->per[i].name))
{
return i;
}
else
{
i++;
}
}
return -1;
}
void delete_contact(contact* con)
{
assert(con);
int result = find1(&con);
if (result != -1)
{
char true[5] = { 0 };
printf("Are you sure you want to delete %s's information?", &con->per[result].name);
printf("yes/no:");
scanf("%s", true);
if (!strcmp(true, "yes"))
{
if ( con->sz )
{
memmove(con->per[result].name, con->per[(con->sz) - 1].name, sizeof(con->per[0]));
}
else
{
memset(con->per[result].name, 0, sizeof(con->per[0]));
}
(con->sz)--;
printf("The deletion was successful, thanks for using!\n");
}
else
{
printf("Delete failed, please try again!\n");
}
}
else
{
printf("Delete failed, please try again!\n");
}
}
通过联系人姓名查找联系人。
int find1(const contact** con)
{
assert(*con);
size_t i = 0;
char sample1[20] = { 0 };
printf("请输入你要查找的名字:");
scanf("%s", sample1);
while (i < (*con)->sz)
{
if (!strcmp(sample1, (*con)->per[i].name))
{
return i;
}
else
{
i++;
}
}
return -1;
}
void find_contact(const contact* con)
{
assert(con);
int result = find1(&con);
if (result != -1)
{
printf("Found, the basic information of the contact is:");
printf("name:%-20s\tage:%-4d\tsex:%-5s\taddress:%-30s\tphone:%-12s\n",
con->per[result].name,
con->per[result].age,
con->per[result].sex,
con->per[result].address,
con->per[result].phone);
}
else
{
printf("Didn't find it!\n");
}
}
先查找,再修改。
可以修改联系人的任一信息。
int find1(const contact** con)
{
assert(*con);
size_t i = 0;
char sample1[20] = { 0 };
printf("请输入你要查找的名字:");
scanf("%s", sample1);
while (i < (*con)->sz)
{
if (!strcmp(sample1, (*con)->per[i].name))
{
return i;
}
else
{
i++;
}
}
return -1;
}
void revise_contact(contact* con)
{
assert(con);
int result = find1(&con);
if (result != -1)
{
char choice1[5] = { 0 };
printf("Are you sure you want to revise %s's information?", con->per[result].name);
printf("yes/no:");
scanf("%s", choice1);
if (!strcmp(choice1, "yes"))
{
menu2();
printf("Please enter the option you want to modify:");
int choice2 = -1;
scanf("%d", &choice2);
char sample1[30] = { 0 };
size_t sample2 = 0;
printf("请输入:");
switch ( choice2 )
{
case 1:
case 3:
case 4:
case 5:
scanf("%s", sample1);
break;
case 2:
scanf("%d", sample2);
break;
}
switch (choice2)
{
case 1:
memmove(con->per[result].name, sample1, sizeof(sample1));
break;
case 3:
memmove(con->per[result].sex, sample1, sizeof(sample1));
break;
case 4:
memmove(con->per[result].address, sample1, sizeof(sample1));
break;
case 5:
memmove(con->per[result].phone, sample1, sizeof(sample1));
break;
case 2:
con->per[result].age = sample2;
break;
}
printf("修改成功,感谢使用!!!\n");
}
else
{
printf("修改失败,请再次尝试!!!\n");
}
}
else
{
printf("修改失败,请再次尝试!!!\n");
}
}
展示所有联系人及其所有信息。
void show_contact(const contact* con)
{
assert(con);
printf("\n\n================================================\n");
printf("================================================\n\n");
if ( con->sz )
{
size_t i = 0;
for (; i < (con->sz); i++)
{
printf("name:%-20s\tage:%-4d\tsex:%-8s\taddress:%-15s\tphone:%-12s\n",
con->per[i].name, con->per[i].age, con->per[i].sex,
con->per[i].address, con->per[i].phone);
}
printf("\n\n");
}
else
{
printf("There is no contact information in the address book!\n");
}
}
又名初始化通讯录。
重新向内存申请一片空间,存储联系人信息。
void init_contact(contact* con)
{
assert(con);
// per sz ContactMax
con->sz = 0;
person* p = (person*)calloc(Max, sizeof(person));
if (p == NULL)
{
perror("init_contact::calloc");
return;
}
con->per = p;
con->ContactMax = Max;
}
通过free()释放内存栈区的空间,避免内存泄露。
void destroy_contact(contact* con)
{
free(con->per);
con->per = NULL;
con->ContactMax = 0;
con->sz = 0;
con = NULL;
}
在使用完内存函数之后,一定一定要记得释放空间哦~
上述代码展示就是整个动态通讯录的全部啦,如果你有兴趣想要了解,可以通过C_Ccpp/C_study/contact at main · Yjun6/C_Ccpp (github.com)找到它们。