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

Wesley13
• 阅读 765

题目:通讯录管理程序

问题描述

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

基本要求

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

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

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

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

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

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

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

测试数据

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

实现提示

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

代码:

#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;
}
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Stella981 Stella981
3年前
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解2016年09月02日00:00:36 \牧野(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fme.csdn.net%2Fdcrmg) 阅读数:59593
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这