上一版的通讯录实现时,一次性开辟了存储1000个人的信息的空间,造成内存空间的不合理利用。
改进版本中,需要实现以下功能:
默认可以存放3个人的信息,当前通讯录存满后进行扩容,每次增加2个容量。
test.c:
#define _CRT_SECURE_NO_WARNINGS
#include "contact.h"
void menu()
{
printf("****************-***************\n");
printf("****1.add 2.del ****\n");
printf("****3.search 4.modify ****\n");
printf("****5.show 0.exit ****\n");
printf("********************************\n");
}
int main()
{
int input = 1;
struct Contact con; //通讯录con中包含data指针、当前通讯录的容量、当前通讯录中的联系人个数size
InitContact(&con); //初始化通讯录,需要把con和size置为0,传址调用
do
{
menu();
printf("请选择->");
scanf("%d", &input);
switch (input)
{
//预编译时可以将ADD等改成0...
case ADD:
AddContact(&con); //元素增加后size随之改变,传址调用
break;
case DEL:
DelContact(&con);
break;
case SEARCH:
SearContact(&con);
break;
case MODIFY:
ModContact(&con);
break;
case SHOW:
ShowContact(&con);
break;
case EXIT:
//销毁通讯录,即释放malloc开辟的内存空间
DestContact(&con);
printf("退出通讯录\n");
break;
default:
printf("选择错误\n");
break;
}
} while (input);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
contact.c:
#define _CRT_SECURE_NO_WARNINGS
#include "contact.h"
void InitContact(struct Contact* ps)
{
//通讯录默认开辟3个联系人的空间
ps->data = (struct PeoInfo*)malloc(DEFAULT_SZ * sizeof(struct PeoInfo));
if (ps->data == NULL)
{
return; //开辟不成功不执行操作返回
}
ps->size = 0;
ps->capacity = DEFAULT_SZ;
}
//检查通讯录是否已被填满,已满则扩容,未满则不操作
void CheckCapacity(struct Contact* ps)
{
if (ps->size == ps->capacity)
{
//扩容
struct PeoInfo* ptr = realloc(ps->data, (ps->capacity + 2) * sizeof(struct PeoInfo));
if (ptr != NULL)
{
ps->data = ptr;
ps->capacity += 2;
printf("扩容成功\n");
}
else
{
printf("扩容失败\n");
}
}
}
void AddContact(struct Contact* ps)
{
//先检查数组中容量是否被填满
CheckCapacity(ps);
//增加联系人
printf("请输入姓名\n");
scanf("%s", &ps->data[ps->size].name);
printf("请输入年龄\n");
scanf("%d", &ps->data[ps->size].age);
printf("请输入性别\n");
scanf("%s", &ps->data[ps->size].sex);
printf("请输入电话\n");
scanf("%s", &ps->data[ps->size].tel);
printf("请输入地址\n");
scanf("%s", &ps->data[ps->size].addr);
ps->size++; //数组中成员数量+1
printf("添加成功\n");
}
void ShowContact(const struct Contact* ps)
{
if (ps->size == 0)
{
printf("通讯录为空\n");
}
else
{
int i = 0;
printf("%-10s\t%-3s\t%-5s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");
for (i = 0; i < ps->size; i++)
{
printf("%-10s\t%-3s\t%-5d\t%-12s\t%-20s\n",
ps->data[i].name,
ps->data[i].sex,
ps->data[i].age,
ps->data[i].tel,
ps->data[i].addr);
}
}
}
//删除、查找、改变都需要查找代码,代码冗余,单独写成函数调用
int FindName(const struct Contact* ps, char name[MAX_NAME])
{
//跳出for循环的两种情况:
//1.break跳出,说明数组中找到了要删除的数据
//2.for循环跳出,说明遍历完成后没有找到查找的数据
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (strcmp(ps->data[i].name, name) == 0)
{
return i; //找到了返回元素下标
}
}
return -1; //找不到返回-1
}
void DelContact(struct Contact* ps)
{
char name[MAX_NAME];
printf("请输入要删除的人的名字:->");
scanf("%s", &name);
//1.查找要删除的信息在数组中的位置(遍历)
int pos = FindName(ps, name); //返回位置或-1
if (pos == -1) //for循环跳出
{
printf("要删除的人不存在\n");
}
else //break跳出,此时的位置是data[i]
{
//2.删除信息(保证顺序不变,后面的信息逐个覆盖前面的)
int j = 0;
for (j = pos; j < ps->size - 1; j++)
{
ps->data[j] = ps->data[j + 1];
}
ps->size--;
printf("删除成功\n");
}
}
void SearContact(const struct Contact* ps)
{
char name[MAX_NAME];
printf("请输入要查找的联系人的名字\n");
scanf("%s", &name);
int pos = FindName(ps, name); //返回位置或-1
if (pos == -1)
{
printf("要查找的人不存在\n");
}
else //找到后打印元素的每一个字段
{
printf("%-10s\t%-3s\t%-5s\t%-12s\t%-20s\n",
"姓名", "性别", "年龄", "电话", "地址");
printf("%-10s\t%-3s\t%-5d\t%-12s\t%-20s\n",
ps->data[pos].name,
ps->data[pos].sex,
ps->data[pos].age,
ps->data[pos].tel,
ps->data[pos].addr);
}
}
void ModContact(struct Contact* ps)
{
char name[MAX_NAME];
printf("请输入要修改的联系人的名字\n");
scanf("%s", &name);
int pos = FindName(ps, name); //返回位置或-1
if (pos == -1)
{
printf("要修改的信息不存在\n");
}
else //找到后打印元素的每一个字段
{
printf("请输入姓名\n");
scanf("%s", &ps->data[pos].name);
printf("请输入年龄\n");
scanf("%d", &ps->data[pos].age);
printf("请输入性别\n");
scanf("%s", &ps->data[pos].sex);
printf("请输入电话\n");
scanf("%s", &ps->data[pos].tel);
printf("请输入地址\n");
scanf("%s", &ps->data[pos].addr);
printf("修改完成\n");
}
}
void DestContact(Contact* ps)
{
free(ps->data); //free释放malloc、realloc开辟改变过的内存空间
ps->data = NULL;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
contact.h:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_NAME 10
#define MAX_SEX 3
#define MAX_TEL 12
#define MAX_ADDR 20
#define DEFAULT_SZ 3
//使用枚举增加代码可读性
enum Option
{
EXIT, //0
ADD, //1
DEL, //2
SEARCH, //3
MODIFY, //4
SHOW, //5
SORT //6
};
struct PeoInfo //描述一个人的信息
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tel[MAX_TEL];
char addr[MAX_ADDR];
};
typedef struct Contact //描述通讯录
{
struct PeoInfo *data; //指向一块内存空间
int size; //记录当前已有的元素个数
int capacity; //记录当前通讯录容量
}Contact; //struct Contact重命名为Contact
//声明函数:
void InitContact(struct Contact* ps); //初始化函数,参数为struct Contact的指针
void AddContact(struct Contact* ps); //数组内增加元素
void ShowContact(const struct Contact* ps); //打印数组
void DelContact(struct Contact* ps); //删除指定信息
void SearContact(const struct Contact* ps); //查找指定信息
void ModContact(struct Contact* ps); //更改指定信息
void DestContact(struct Contact* ps); //销毁通讯录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48