1. 前期准备
1.1. 创建三个文件
分别是"test.c", "contact.c","contact.h"
test.c 是 用来测试,框架就存放在这
contact.c 是 用来写实现功能的函数的
contact.h 是 用来声明,结构体,以及“contact.c”写的函数,
这样"test.c"就可以调用“contact.c”里的函数,实现跨文件调用。
1.2. 框架搭建
int main ()
{
int input = 0;
human contact [100] = { 0 };
do
{
menu1();
scanf("%d", &input);
switch(input)
{
case 1:
break;
...
case 6:
break;
default:
printf("输入错误请认真输入!\n");
}
}while(input);
return 0;
}
human 是 我自定义的类型,存放在"contact.h"如图
typedef struct human
{
...
}human;
上面做的只是把自定义类型和创建结构体一起写了
第一个human是结构体的,第二个human是自定义类型的名称
顺变把两个.c文件用得上的系统的头文件也放在这这样只用声明一次就好啦
创建一个能存放100个结构体的数组
human contact[100] = { 0 };
打印菜单menu1函数
do
{
menu1();
scanf("%d", &input);
switch(input)
{
case 1:
break;
...
case 6:
break;
default:
printf("输入错误请认真输入!\n");
}
}while(input);
return 0;
}
因为要实现6个不同的功能用switch刚刚好
input用来控制do...while循环和switch
2. 通讯录的6个功能
2.1.存储联系人的相关信息(姓名+年龄+性别+电话+地址)
test.c 的 传参部分
case 1:
printf("请输入你要存放的联系人个数->");
scanf("%d", &num);
contact_save(contact, num);
break;
contact.c 的 函数部分
void contact_save(human* man, int num)
{
for (int i = 0; i < num; i++)
{
printf("第%d位\n", i + 1);
printf("请以名字 年龄 性别 电话 地址 以空格的方式作为分隔符:\n");
scanf("%s %d %s %s %s", &man[i].name, &man[i].age,
&man[i].sex, &man[i].number, &man[i].site);
}
}
num用来存放用户输入要存储联系人的个数
human* man 接收 human类型的指针,而contact数组名为首元素的地址
i + 1 是因为 i 是从0开始的 所以为了用户方便理解 + 1;
2.2. 增加联系人
test.c 的 传参部分
case 2:
printf("请输入你要增加的联系人个数->");
scanf("%d", &add);
contact_add(contact, num, add);
break;
contact.c 的 函数部分
void contact_add(human* man, int num, int add)
{
for (int i = num; i < num + add; i++)
{
printf("第%d位\n", i + 1);
printf("请以名字 年龄 性别 电话 地址 以空格的方式作为分隔符:\n");
scanf("%s %d %s %s %s", &man[i].name, &man[i].age,
&man[i].sex, &man[i].number, &man[i].site);
}
}
add用来存放用户输入要增加联系人的个数
2.3. 删除联系人
test.c传参部分
char find[20] = { 0 };
case 3:
printf("请输入你要删除联系人的姓名->");
scanf("%s", &find);
if (f = contact_find(contact, find, num, add))
contact_delete(&contact[f - 1]);
else
printf("不存在该联系人\n");
break;
传参之前先判断有没有这个联系人调用查找函数
contact_find 调用完以后会返回整形当前函数所在的下标
存放到f用f来判断是否存在
contact.c函数部分
int contact_find(human* man, char* p, int num, int add)
{
for (int i = 0; i < num + add; i++)
{
for (int j = 0; man[i].name[j] != '\0'; j++)
{
if (man[i].name[j] != p[j])
break;
if (p[j + 1] == '\0')
return i + 1;
}
}
return 0;
}
char*p 接收 find数组的首元素的地址
第一个for 循环 num + add 通讯录目前有几个或者曾经有过几个
联系人
第二个for 循环 man[i] 结构体数组contact的第 i 个元素
.name[i] 把这个结构体的name数组的所有元素和*p所
指向的字符数组进行对比一致返回 i + 1
返回 i 是返回该函数的下标 ,+1 是为了避免返回值赋给
test.c 里的 变量f 在if做判断时不会把第一个元素的下标“0”
误认为没有联系人,所以做 +1 处理
void contact_delete_inside(char* p)
{
for (int i = 0; p[i] != '\0'; i++)
{
p[i] = 0;
}
}
void contact_delete(human* man)
{
man->age = 0;
contact_delete_inside(man->name);
contact_delete_inside(man->number);
contact_delete_inside(man->sex);
contact_delete_inside(man->site);
}
把man 所指向的结构体的所有变量全部归0
contact_delete_inside 遍历字符数组在遇到
‘\0’之前全部归0
2.4. 查找联系人
test.c 传参部分
case 4:
printf("请输入你要查找联系人的姓名->");
scanf("%s", &find);
if (f = contact_find(contact, find, num, add))
contact_one_printf(&contact[f - 1]);
else
printf("不存在该联系人\n");
break;
跟删除的功能传参部分差不多,就不多赘述了
contact.c 函数部分
int contact_find(human* man, char* p, int num, int add)
{
for (int i = 0; i < num + add; i++)
{
for (int j = 0; man[i].name[j] != '\0'; j++)
{
if (man[i].name[j] != p[j])
break;
if (p[j + 1] == '\0')
return i + 1;
}
}
return 0;
}
void contact_one_printf(human* man)
{
printf("-----------------------------------------------------------\n");
printf("%s %d %s %s %s\n", man->name, man->age,
man->sex, man->number, man->site);
printf("-----------------------------------------------------------\n");
}
contact_find在删除也说了,不多说了
contact_one_printf函数是为了只输出一个结构体的信息
2.5. 修改联系人
test.c 传参部分
if (f = contact_find(contact, find, num, add))
{
contact_one_printf(&contact[f - 1]);
do
{
menu2();
printf("请问输入需要修改项的编号->");
scanf("%d", &change);
switch (change)
{
case 1:
printf("请输入修改的姓名\n");
contact_change(contact[f - 1].name);
contact_one_printf(&contact[f - 1]);
break;
case 2:
printf("请输入修改的年龄\n");
scanf("%d", &contact[f - 1].age);
contact_one_printf(&contact[f - 1]);
break;
...
...
case 5:
printf("请输入修改的地址\n");
contact_change(contact[f - 1].site);
contact_one_printf(&contact[f - 1]);
break;
case 0:
printf("已退出联系人修改\n");
break;
default:
printf("输入错误请重新输入!\n");
}
} while (change);
}
else
printf("不存在该联系人\n");
break;
这边省略号代表case 3 ~ 4 都是大同小异,其实你看上面就看出来了
很多相同的冗余代码,为什么不改完全是懒,如果大家看着难受就直接
上手吧,我下面会附 Gitee 的链接源码
菜单2
void menu2()
{
printf("----------------------------------------------------------\n");
printf("-----------1.姓名 2.年龄 3.性别----------------\n");
printf("-----------4.电话 5.地址 0.exit----------------\n");
printf("----------------------------------------------------------\n");
}
contact.c 函数部分
void contact_change(char* p)
{
char arr[20] = { 0 };
scanf("%s", &arr);
for (int i = 0; p[i] != '\0'; i++)
{
p[i] = arr[i];
if (arr[i] == '\0')
break;
}
}
把要修改的内容赋给 arr 再用arr 对 p 所指向的数组 进行覆盖·
2.6. 排序
test.c 传参部分
case 6:
do
{
menu2();
printf("请问输入需要排序项的编号->");
scanf("%d", &change);
if (change > 0 && change < 6)
{
printf("你需要升序还是降序?升序请输入非0数,降序请输入0->");
scanf("%d", &sort);
contact_sort(contact, change, sort, num, add);
contact_all_printf(contact, num, add);
}
else if (change == 0)
break;
else
printf("输入错误请重新输入!\n");
} while (change);
break;
if (change > 0 && change < 6)
不管是用结构体的那个变量进行排序都用contact_sort函数
void contact_sort(human* man, int change, int sort, int num, int add)
{
switch (change)
{
case 1:
contact_sort_str(man, man->name, num, add, sort);
break;
case 2:
contact_sort_str(man, &man->age, num, add, sort);
case 3:
contact_sort_str(man, man->sex, num, add, sort);
break;
case 4:
contact_sort_str(man, man->number, num, add, sort);
break;
case 5:
contact_sort_str(man, man->site, num, add, sort);
break;
}
}
change存储用户的选择 根据选择传相应的参数
contact.c 函数部分
这边就把讲解写在代码块里面了,这一块太长了
至于我们不用双斜杠作注解主要是代码块里注解
的字颜色太淡了就只能这样了
void contact_sort_str(human* man,char* p, int num, int add, int sort)
{
----------------------------
用save作为交换的中转站
---------------------------
human save = { 0 };
----------------------------------------------------------
第一个循环主要是为了提高效率,其中z是代表下面的排序进行了几次
进行一次就代表有一个结构体元素排序好了,那么用z去减下面的遍历
次数从而减少不必要的遍历提高效率
----------------------------------------------------------
for (int z = 0; z < num + add; z++)
{
int j = 0;
----------------------------------------------------------
num + add 是 联系人的总数
-1 为了防止数组越界 因为下面的交换方式是用 man[j+1]来和man[j]
的值来进行互换的 假如循环到第100个联系人,即就j = 100 那么
j + 1 为101 第101个联系人并不存在,去进行赋值会导致把原来有效
的值变成其他无效的随机值或者其他的什么值(摊手)
至于,为什么(num + add)* 53?53怎么来的?
这边使用sizeof(contact)对存放结构体类型的数组查看他所占的字节
即5300,再/100 就得出来53
一个结构体占53字节,再加上char*只有访问1字节的权限,还有为了
函数的通用性,那么不管此时传来的是结构体的那个成员变量那么只
要给p + 53 就直接指向了下一个结构体的相同的成员变量的地址,
至于j 控制要交换的结构体
----------------------------------------------------------
for (int i = 0; i < ((num + add - 1 - z) * 53); i+=53)
{
if (p[i] != '\0')
{
if (sort == 1)
{
if (p[i] < p[i + 53])
{
save = man[j];
man[j] = man[j + 1];
man[j + 1] = save;
}
j++;
}
else
{
if (p[i] > p[i + 53])
{
save = man[j];
man[j] = man[j + 1];
man[j + 1] = save;
}
j++;
}
}
}
}
}
一些补充
scanf("%d", &contact[f - 1].age);
这个位置会报一个警告如图
这个是关结构体成员变量age的以下分两种情况
typedef struct human
{
char age;
char sex[10];
char name[20];
char number[12];
char site[10];
}human;
typedef struct human
{
char sex[10];
char name[20];
char number[12];
char site[10];
char age;
}human;
我想你应该在想就是把,char age 放在前后有什么区别么?
区别在如age在前面时,你用%d 去给age赋值,在编译器给你的
结构体分配内存时各个变量的内存其实基本是连续的(为什么说
是基本呢?还有一个概念就是”结构体内存对齐”的概念,这里我
就不详细说了有想了解的可以去看看其他的博客),
所以在scanf("%d",&&contact[f - 1].age),%d默认对4个字符进行
赋值,刚好我上面提到结构体的内存的连续,那么跟在age后面
的sex就是在内存中age后面的,这就会导致sex的值被篡改。
至于,为什么放在后面没事可能是因为结构体的访问内存权限只有
53字节的原因?导致放在后面就越界不了?具体的我也不太清楚,
有知道的可以在评论区说说,我也当学习学习。
源码
contact.h
# include<stdio.h>
typedef struct human
{
char sex[10];
char name[20];
char number[12];
char site[10];
char age;
}human;
void contact_save(human* man, int num);
void contact_add(human* man, int num, int add);
void contact_delete(human* man);
int contact_find(human* man, char* p, int num, int add);
void contact_change(char* p);
void contact_sort_str(human* man, char* p, int num, int add, int sort);
void contact_one_printf(human* man);
void contact_all_printf(human* man, int num, int add);
test.c
# define _CRT_SECURE_NO_WARNINGS 1
# include"contact.h"
void menu1()
{
printf("-----------------------------------------------------------\n");
printf("-----------1.存放联系人 2.增加联系人 3.删除联系人----------\n");
printf("-----------4.查找联系人 5.修改联系人 6.排序 ----------\n");
printf("----------- 0.exit ----------\n");
printf("-----------------------------------------------------------\n");
}
void menu2()
{
printf("-----------------------------------------------------------\n");
printf("-----------1.姓名 2.年龄 3.性别----------------\n");
printf("-----------4.电话 5.地址 0.exit ----------\n");
printf("-----------------------------------------------------------\n");
}
void contact_sort(human* man, int change, int sort, int num, int add)
{
switch (change)
{
case 1:
contact_sort_str(man, man->name, num, add, sort);
break;
case 2:
contact_sort_str(man, &man->age, num, add, sort);
case 3:
contact_sort_str(man, man->sex, num, add, sort);
break;
case 4:
contact_sort_str(man, man->number, num, add, sort);
break;
case 5:
contact_sort_str(man, man->site, num, add, sort);
break;
}
}
int main()
{
int input = 0;
int num = 0;
int add = 0;
int del = 0;
int f = 0;
int change = 0;
int sort = 0;
char find[20] = { 0 };
human contact [100] = { 0 };
//printf("%d", sizeof(contact));
do
{
menu1();
scanf("%d", &input);
switch (input)
{
case 1:
printf("请输入你要存放的联系人个数->");
scanf("%d", &num);
contact_save(contact, num);
break;
case 2:
printf("请输入你要增加的联系人个数->");
scanf("%d", &add);
contact_add(contact, num, add);
break;
case 3:
printf("请输入你要删除联系人的姓名->");
scanf("%s", &find);
if (f = contact_find(contact, find, num, add))
contact_delete(&contact[f - 1]);
else
printf("不存在该联系人\n");
break;
case 4:
printf("请输入你要查找联系人的姓名->");
scanf("%s", &find);
if (f = contact_find(contact, find, num, add))
contact_one_printf(&contact[f - 1]);
else
printf("不存在该联系人\n");
break;
case 5:
printf("请输入你要修改联系人的姓名->");
scanf("%s", &find);
if (f = contact_find(contact, find, num, add))
{
contact_one_printf(&contact[f - 1]);
do
{
menu2();
printf("请问输入需要修改项的编号->");
scanf("%d", &change);
switch (change)
{
case 1:
printf("请输入修改的姓名\n");
contact_change(contact[f - 1].name);
contact_one_printf(&contact[f - 1]);
break;
case 2:
printf("请输入修改的年龄\n");
scanf("%d", &contact[f - 1].age);
contact_one_printf(&contact[f - 1]);
break;
case 3:
printf("请输入修改的性别\n");
contact_change(contact[f - 1].sex);
contact_one_printf(&contact[f - 1]);
break;
case 4:
printf("请输入修改的电话\n");
contact_change(contact[f - 1].number);
contact_one_printf(&contact[f - 1]);
break;
case 5:
printf("请输入修改的地址\n");
contact_change(contact[f - 1].site);
contact_one_printf(&contact[f - 1]);
break;
case 0:
printf("已退出联系人修改\n");
break;
default:
printf("输入错误请重新输入!\n");
}
} while (change);
}
else
printf("不存在该联系人\n");
break;
case 6:
do
{
menu2();
printf("请问输入需要排序项的编号->");
scanf("%d", &change);
if (change > 0 && change < 6)
{
printf("你需要升序还是降序?升序请输入非0数,降序请输入0->");
scanf("%d", &sort);
contact_sort(contact, change, sort, num, add);
contact_all_printf(contact, num, add);
}
else if (change == 0)
break;
else
printf("输入错误请重新输入!\n");
} while (change);
break;
case 0:
printf("已退出!\n");
break;
default:
printf("输入错误请认真输入!\n");
}
} while (input);
contact_all_printf(contact, num, add);
return 0;
}
contact.c
# define _CRT_SECURE_NO_WARNINGS 1
# include"contact.h"
void contact_save(human* man, int num)
{
for (int i = 0; i < num; i++)
{
printf("第%d位\n", i + 1);
printf("请以名字 年龄 性别 电话 地址 以空格的方式作为分隔符:\n");
scanf("%s %d %s %s %s", &man[i].name, &man[i].age,
&man[i].sex, &man[i].number, &man[i].site);
}
}
void contact_add(human* man, int num, int add)
{
for (int i = num; i < num + add; i++)
{
printf("第%d位\n", i + 1);
printf("请以名字 年龄 性别 电话 地址 以空格的方式作为分隔符:\n");
scanf("%s %d %s %s %s", &man[i].name, &man[i].age,
&man[i].sex, &man[i].number, &man[i].site);
}
}
void contact_delete_inside(char* p)
{
for (int i = 0; p[i] != '\0'; i++)
{
p[i] = 0;
}
}
void contact_delete(human* man)
{
man->age = 0;
contact_delete_inside(man->name);
contact_delete_inside(man->number);
contact_delete_inside(man->sex);
contact_delete_inside(man->site);
}
int contact_find(human* man, char* p, int num, int add)
{
for (int i = 0; i < num + add; i++)
{
for (int j = 0; man[i].name[j] != '\0'; j++)
{
if (man[i].name[j] != p[j])
break;
if (p[j + 1] == '\0')
return i + 1;
}
}
return 0;
}
void contact_change(char* p)
{
char arr[20] = { 0 };
scanf("%s", &arr);
for (int i = 0; p[i] != '\0'; i++)
{
p[i] = arr[i];
if (arr[i] == '\0')
break;
}
}
void contact_sort_str(human* man,char* p, int num, int add, int sort)
{
human save = { 0 };
for (int z = 0; z < num + add; z++)
{
int j = 0;
for (int i = 0; i < ((num + add - 1 - z) * 53); i+=53)
{
if (p[i] != '\0')
{
if (sort == 1)
{
if (p[i] < p[i + 53])
{
save = man[j];
man[j] = man[j + 1];
man[j + 1] = save;
}
j++;
}
else
{
if (p[i] > p[i + 53])
{
save = man[j];
man[j] = man[j + 1];
man[j + 1] = save;
}
j++;
}
}
}
}
}
void contact_one_printf(human* man)
{
printf("-----------------------------------------------------------\n");
printf("%s %d %s %s %s\n", man->name, man->age,
man->sex, man->number, man->site);
printf("-----------------------------------------------------------\n");
}
void contact_all_printf(human* man, int num,int add)
{
int a = 0;
for (int i = 0; i < num + add; i++)
{
if (man[i].name[0] != '\0')
{
printf("-----------------------------------------------------------\n");
printf("第%d位\n", i + 1 - a);
printf("%s %d %s %s %s\n", man[i].name, man[i].age,
man[i].sex, man[i].number, man[i].site);
printf("-----------------------------------------------------------\n");
}
else
a++;
}
}