C实现通讯录管理系统(亮点:纯链表实现、子串匹配,文件读写)

题目:通讯录管理程序

问题描述

编写一个简单的通讯录管理程序。通讯录记录有姓名,地址(省、市(县)、街道),电话号码,邮政编码等四项。

基本要求

程序应提供的基本基本管理功能有:

1) 添加:即增加一个人的记录到通信录中

2) 显示:即在屏幕上显示所有通信录中的人员信息,应能分屏显示。

3) 存储:即将通讯录信息保存在一个文件中。

4) 装入:即将文件中的信息读入程序。

5) 查询:可根据姓名查找某人的相关信息,若找到显示其姓名、地址、电话号码和邮政编码。

6) 修改:可修改一个人的除姓名外其它信息。

测试数据

程序应输入不少于10个人员的通讯录信息,应考虑到人员可以同名的情况。

实现提示

程序可用一个结构体数组、单向链表或对象数组来管理人员信息,每个人员的姓名,地址,电话号码和邮政编码用一个结构体或类实现。

代码:

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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define CHARMAX 30
 
typedef struct record {
    char name[CHARMAX];
    char phonenumber[11];
    char address[3][CHARMAX]; //0-省 1-市 2-街道
    char postcode[6];
    struct record *next;
} RECORD;
 
void PrintMenu();
 
void AlterString(RECORD *head);
 
RECORD *InputRecord(RECORD *head, int *total);
 
void PrintAllRecords(RECORD *head, const int *total);
 
RECORD *DeleteRecord(RECORD *head,int *total);
 
RECORD *ReviseRecord(RECORD *head);
 
RECORD *SearchRecord(RECORD *head, int onlyOneRecord) ;
 
RECORD *ImportRecords(RECORD *head, int *total);
 
RECORD *ExportRecords(RECORD *head);
 
int main() {
    int total = 0, selection;
    RECORD *head = NULL;
    printf("Welcome to Directory Management System!\n");
    printf("By XZ&YYM\n");
    printf("---------------------------------------------\n");
 
    do {
        PrintMenu();
        scanf("%d", &selection);
        system("cls");
        switch (selection) {
            case 0:
                break;
            case 1:
                head = InputRecord(head, &total);
                break;
            case 2:
                PrintAllRecords(head, &total);
                break;
            case 3:
                head = DeleteRecord(head,&total);
                break;
            case 4:
                head = ReviseRecord(head);
                break;
            case 5:
                SearchRecord(head,0);
                break;
            case 6:
                head = ImportRecords(head,&total);
                break;
            case 7:
                ExportRecords(head);
                break;
            default:
                printf("\n\n-- Sorry!Please input 0-10!\n");
        };
    } while (selection != 0);
    return 0;
}
 
void PrintMenu() {
    printf("\n");
    printf("|1.Input record\n");
    printf("|2.List all records\n");
    printf("|3.Delete record\n");
    printf("|4.Revise record\n");
    printf("|5.Search record\n");
    printf("|6.Import records from file\n");
    printf("|7.Export records to file\n");
    printf("|0.Exit\n");
    printf("|Please input 0-7 to select function :");
}
 
//功能:将字符串后的回车删掉
//入参:链表首地址
//出参:无
void AlterString(RECORD *head) {
    int m;
    RECORD *p1 = head;
 
    while (p1 != NULL) {
        for (m = 0; m < CHARMAX; m++) {
            if (*((p1->name) + m) == '\n') {
                *((p1->name) + m) = '\0';
            }
        }
        for (m = 0; m < 11; m++) {
            if (*((p1->phonenumber) + m) == '\n') {
                *((p1->phonenumber) + m) = '\0';
            }
        }
        for (m = 0; m < CHARMAX; m++) {
            if (*((p1->address[0]) + m) == '\n') {
                *((p1->address[0]) + m) = '\0';
            }
        }
        for (m = 0; m < CHARMAX; m++) {
            if (*((p1->address[1]) + m) == '\n') {
                *((p1->address[1]) + m) = '\0';
            }
        }
        for (m = 0; m < CHARMAX; m++) {
            if (*((p1->address[2]) + m) == '\n') {
                *((p1->address[2]) + m) = '\0';
            }
        }
        for (m = 0; m < 6; m++) {
            if (*((p1->postcode) + m) == '\n') {
                *((p1->postcode) + m) = '\0';
            }
        }
        p1 = p1->next;
    }
}
 
//功能:连续输入数据
//入参:链表首地址,数据总数地址
//出参:链表首地址
RECORD *InputRecord(RECORD *head, int *total) {
    int i = *total;
    char inputChar;
    RECORD *p = head, *input = (RECORD *) malloc(sizeof(RECORD));
 
    printf("\n-- Start to Input Record\n");
 
    //如果拥有数据,则输出现有数据总数
    if (*total) {
        printf("-- You have had %d records\n\n", *total);
    }
 
    do {
        //输入数据
        printf("Input NO.%d Record`s Name:", i + 1);
        fflush(stdin);
        fgets(input->name, CHARMAX + 1, stdin);
        printf("Input NO.%d Record`s Phone Number:", i + 1);
        fflush(stdin);
        fgets(input->phonenumber,CHARMAX + 1, stdin);
        printf("Input NO.%d Record`s Address:\n", i + 1);
        printf("- Input NO.%d Record`s Province:", i + 1);
        fflush(stdin);
        fgets(input->address[0], CHARMAX + 1, stdin);
        printf("- Input NO.%d Record`s City:", i + 1);
        fflush(stdin);
        fgets(input->address[1], CHARMAX + 1, stdin);
        printf("- Input NO.%d Record`s Street:", i + 1);
        fflush(stdin);
        fgets(input->address[2], CHARMAX + 1, stdin);
        printf("- Input NO.%d Record`s Postcode:", i + 1);
        fflush(stdin);
        fgets(input->postcode, 7, stdin);
        input->next = NULL; //插入时放于链表的最后
 
        //插入数据,分为首数据和非首数据
        if (head == NULL) {
            head = input;
            p = input;
        } else {
            while (p->next != NULL) {
                p = p->next;
            }
            p->next = input;
        }
 
        //增加数据计数
        (*total)++;
 
        //询问是否继续
        printf("\nDo you want to continue?(Y/N):");
        scanf(" %c", &inputChar);
        if (inputChar == 'Y' || inputChar == 'y') {  //直接用getchar必须输入大写Y才能继续
            //创建新的空间
            input = (RECORD *) malloc(sizeof(RECORD));
            i++;
        } else {
            break;
        }
    } while (1);
 
    //将字符串后面的回车删除
    AlterString(head);
    return head;
 
}
 
//功能:打印全部数据
//入参:链表首地址,数据总数地址
//出参:无
void PrintAllRecords(RECORD *head, const int *total) {
    int page = 1, firstIndex = 0, i, pageAmount = *total / 10 + 1;
    RECORD *p = head;
    do {
        system("cls");
 
        //处理输入的数字过大或过小
        if (page > pageAmount) {
            printf("-- Sorry! The MAX of pages is %d\n", pageAmount);
        } else if (page < 0) {
            printf("-- Sorry! The number have to be positive\n");
        } else {
            //处理分页
            firstIndex = 10 * (page - 1);
 
            printf("NO.\tName\tPhonenumber\tProvince\tCity\tStreet\tPostcode\t\n");
 
            //处理前置数据
            p = head;
            for (i = 0; i < firstIndex; ++i) {
                p = p->next;
            }
 
            i = 0;
 
            //输出数据
            while (p != NULL && i < 10) { //todo 大量数据可能出现问题
                i++;
                printf("NO.%d\t%s\t%s\t\t%s\t\t%s\t%s\t%s\t\n", i+firstIndex,p->name, p->phonenumber, p->address[0], p->address[1],
                       p->address[2],
                       p->postcode);
                p = p->next;
            }
            printf("-- Page %d (Total %d pages)\n ", page, pageAmount);
        }
 
        printf("-- Jump to page number (Input 0 to finish):");
        scanf("%d", &page);
    } while (page);
}
 
//功能:删除某条数据
//入参:链表首地址
//出参:链表首地址
RECORD *DeleteRecord(RECORD *head,int *total) {
    RECORD *p1 = head, *p2,*searchResult;
    searchResult = SearchRecord(head, 1);
 
    while (p1 != NULL && p1 != searchResult) {
        p2 = p1;         //p2上一个节点
        p1 = p1->next;   //p1下一个节点
    }
 
    if (p1 == head) {
        head = p1->next;
        free(p1);
        (*total)--; //todo
        printf("\n-- Success!\n");
    } else if (p1 != NULL) {
        p2->next = p1->next;
        free(p1);
        (*total)--;
        printf("\n-- Success!\n");
    } else {
        printf("\n-- Do not find this id!\n");
    }
    return head;
 
 
}
 
//功能:输出某条数据
//入参:数据地址
//出参:无
void PrintOneRecord(RECORD *p) {
    printf("Name:%s\tPhonenumber:%s\tProvince:%s\tCity:%s\tStreet::%s\tPostcode:%s\t\n", p->name, p->phonenumber,
           p->address[0], p->address[1], p->address[2], p->postcode);
}
 
//功能:更改数据
//入参:数据地址
//出参:无
RECORD *ReviseRecord(RECORD *head){
    RECORD *p1 = head, *p2,*searchResult,*input = (RECORD *) malloc(sizeof(RECORD));
    //返回需要更改的数组地址
    searchResult = SearchRecord(head, 1);
    if (!searchResult){
        return head;
    }
    //输入数据
    printf("\nInput the newRecord`s Name:");
    fflush(stdin);
    fgets(input->name, CHARMAX + 1, stdin);
    printf("Input the newRecord`s Phone Number:");
    fflush(stdin);
    fgets(input->phonenumber,CHARMAX + 1, stdin);
    printf("Input the Record`s Address:\n");
    printf("- Input the newRecord`s Province:");
    fflush(stdin);
    fgets(input->address[0], CHARMAX + 1, stdin);
    printf("- Input the newRecord`s City:");
    fflush(stdin);
    fgets(input->address[1], CHARMAX + 1, stdin);
    printf("- Input the newRecord`s Street:");
    fflush(stdin);
    fgets(input->address[2], CHARMAX + 1, stdin);
    printf("- Input the newRecord`s Postcode:");
    fflush(stdin);
    fgets(input->postcode, 7, stdin);
    //插入时放于链表的最后
    input->next = NULL;
 
    while (p1 != NULL && p1 != searchResult) {
        p2 = p1;         //p2上一个节点
        p1 = p1->next;   //p1下一个节点
    }
    if (p1 == head) {
        head = input;
        input->next = p1->next;
        free(p1); //是否要释放?
        printf("\n-- Success the Revise!\n");
    } else if (p1 != NULL) {
        p2->next = input;
        input->next = p1->next;
        free(p1);
        printf("\n-- Success Revise!\n");
    } else {
        printf("\n-- Do not find this id!\n");
    }
    AlterString(head);
    return head;
}
 
//功能:搜索数据,并返回唯一搜索结果
//入参:链表首地址,是否要求返回唯一结果
//出参:数据地址
RECORD *SearchRecord(RECORD *head, int onlyOneRecord) {
    int amount = 0, i = 0, selection = 0; //i,p1循环变量
    char input[CHARMAX];
    RECORD *p1 = head, *results[100] = {NULL}; //result是RECORD类型的指针数组
 
    printf("\n-- Search the record:");
    setbuf(stdin, NULL);
    fgets(input, CHARMAX + 1, stdin);
 
    //去除字符串回车
    for (i = 0; i < CHARMAX; ++i) {
        if (*((input) + i) == '\n') {
            *((input) + i) = '\0';
        }
    }
 
    //遍历搜索
    while (p1 != NULL) {
        if (strstr(p1->name, input) ||   //strstr()判断是否为子串
            strstr(p1->phonenumber, input) ||
            strstr(p1->address[0], input) ||
            strstr(p1->address[1], input) ||
            strstr(p1->address[2], input) ||
            strstr(p1->postcode, input)) {
            results[amount] = p1;
            amount++;
        }
        p1 = p1->next;
    }
 
    //若有多个结果,提示用户选择
    if (amount > 1) {
        printf("\n-- Search Result:\n");
        for (i = 0; i < amount; i++) {
            printf("NO.%d\t", i + 1);
            PrintOneRecord(results[i]);
        }
        if (!onlyOneRecord) {
            return NULL; //如果不需要去重,则返回NULL
        }
        printf("\n-- Input the number you want to change: ");
        scanf("%d", &selection);
        //处理输入数据不正确,默认返回第一个
        if (selection - 1 > amount || selection < 0) {
            printf("\n-- Wrong input (Choose the first record automatically)");
            return results[0];
        }
        return results[selection - 1];
    } else if (!amount) {
        printf("\n-- Sorry! No result!");
        return NULL;
    } else {
        printf("\n-- Search Result:\n");
        PrintOneRecord(results[0]);
        return results[0];
    }
 
 
}
 
//功能:导入文件中的数据
//入参:链表首地址,总条数
//出参:数据地址
RECORD *ImportRecords(RECORD *head, int *total) {
    int i = *total,m=3;
    FILE *fpRead;
    RECORD *p = head, *input;
 
    fpRead = fopen("stu.txt","r");
    if(fpRead==NULL){
        printf("can't open file\n");
        return 0;
    }
    do {
        //输入数据
        input = (RECORD *) malloc(sizeof(RECORD));
        fread(input, sizeof(struct record),1,fpRead);
        input->next = NULL; //插入时放于链表的最后
 
        //插入数据,分为首数据和非首数据
        if (head == NULL) {
            head = input;
            p = input;
        } else {
            while (p->next != NULL) {
                p = p->next;
            }
            p->next = input;
        }
 
        //增加数据计数
        (*total)++;
        m--;
 
    } while (m);
 
    return head;
 
}
 
//功能:搜索数据,并返回唯一搜索结果
//入参:链表首地址,是否要求返回唯一结果
//出参:数据地址
RECORD *ExportRecords(RECORD *head){
    FILE *fp;
    struct record *p=head;
    if((fp=fopen("stu.txt","wb"))==NULL)
    {
        printf("Fail to open the stu.txt!\n");
        exit(0);
    }
    while(p != NULL)
    {
        fwrite(p, sizeof(struct record),1,fp);
        p=p->next;
    }
    fclose(fp);
    printf("you have save correctly!\n");
    return 0;
}

  

posted @   dellyoung  阅读(1399)  评论(0编辑  收藏  举报
编辑推荐:
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
阅读排行:
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· .NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想
· Ai满嘴顺口溜,想考研?浪费我几个小时
· Browser-use 详细介绍&使用文档
· 软件产品开发中常见的10个问题及处理方法
点击右上角即可分享
微信分享提示