欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C语言-《通讯录》

程序员文章站 2022-06-15 15:15:21
---------------------- --1-- 需求分析1.1 需求1.2 原型展示1.3功能分析--2-- 代码实现2.1外部声明、变量、宏2.2 模块实现 --------------...

----------------------

--1-- 需求分析1.1 需求1.2 原型展示1.3功能分析--2-- 代码实现2.1外部声明、变量、宏2.2 模块实现

----------------------

--1-- 需求分析 1.1 需求

实现简单计算器的计算功能,用命令行的方式选择具体的操作

1.2 原型展示

欢迎界面:

C语言-《通讯录》

 

1)添加联系人:

C语言-《通讯录》

 

2)删除联系人:

C语言-《通讯录》

 

3)修改联系人:

C语言-《通讯录》

 

4)查看联系人:

C语言-《通讯录》

 

5)搜索联系人:

C语言-《通讯录》

 

文件:

C语言-《通讯录》

 

1.3功能分析

按照原型编写相应的流程功能。

/**

分析:

0、初始化

初始化方法,用于初始化数据

思路:

1)尝试性的读取文件

2)如果成功了,说明文件存在,则读取文件内容

3)不成功,说明文件不存在

1)创建文件

2)写入联系人数量

 

1、添加联系人

思路:

1)提示用户输入姓名和电话号码

2)接收用户输入的内容

3)保存到联系人数组

4)写入到文件中

 

2、删除联系人

思路:

1)让用户输入要删除的数据的编号

2)判断编号是否合法

3)让用户再次确认删除

4)开始删除数组元素

5)删除文件的内容

 

3、修改联系人

更新联系人信息

思路:

1)提示用户输入要删除联系人的编号

2)判断编号是否合法

3)让用户再次确认修改

4)开始修改用户信息

5)更新到文件中

 

4、查看联系人

查看所有联系人

思路:

1)先判断联系人是否为空

2)如果不为空,则遍历数组,列出所有的联系人

 

5、搜索联系人

根据输入的姓名查找联系人

思路:

1)提示用户要输入查找的人的姓名

2)遍历联系人数组,查找是否有这个人

3)如果找到,就把电话号码显示出来

4)没有找到,则显示没有该联系人信息

 

6、退出

*/

用到的知识点:

常量、变量的使用;全局变量;数组;分支语句;函数;宏;循环语句;scanf和printf;数据;结构体;文件操作;指针*

难点:

数组元素的删除(可变数组,使用链表会更优)

 

--2-- 代码实现 2.1 外部声明、变量、宏

需定义的宏

//******宏定义
#define n 100 //联系人数组的长度
#define namelen 13 //姓名长度
#define numlen 12 //手机号长度
//**********

全局变量

//******定义变量
int inputnum; //接收键盘输入
int telcount; //联系人个数
int flag; //接收确认标记
char *telbook = "telnumbook.data"; //数据库文件
//****

函数声明

//*****函数声明
void doadd();
void dodel();
void doedit();
void dolist();
void dosearch();
void startview();
int writefile();
void init();
int validateinput(int num, int min, int max);
//********

联系人结构体

//******联系人结构体
typedef struct{
    char telname[namelen];
    char telnum[numlen];
}person;

person contacts[n]; //联系人数组
//*********
2.2 模块实现

1)添加联系人模块

 1 /**
 2  *  添加联系人
 3  */
 4 void doadd(){
 5     printf("您选择了添加联系人操作\n");
 6     printf("请输入要添加的联系人的姓名:(*注意联系人姓名中间不能有空格)\n");
 7     scanf("%s", contacts[telcount].telname); //存入数组
 8     
 9     printf("请输入要添加的联系人的电话号码:(*注意联系人电话号码中间不能有空格)\n");
10     scanf("%s", contacts[telcount].telnum);
11     
12     //提示确认
13     printf("是否确认添加\"%s\"联系人?  1.确认  0.取消\n", contacts[telcount].telname);
14     scanf("%d", &flag);
15     if (flag) {
16         //联系人个数+1
17         telcount++;
18         //写入文件中
19         writefile();
20         
21         printf("\n");
22     }
23 
24 }

 

2)删除联系人模块

 1 /**
 2  *  删除联系人
 3  */
 4 void dodel(){
 5     printf("您当前选择的是删除联系人操作\n");
 6     dolist();
 7     printf("请输入要删除的联系人编号:\n");
 8     
 9     scanf("%d", &inputnum);
10     if (validateinput(inputnum, 1, telcount)){
11         //非法输入则返回
12         return;
13     } else{
14         printf("数据删除后将不可恢复,您是否确认要删除\"%s\"的信息? 1.确认  0.取消\n",
15                contacts[inputnum - 1].telname);
16         scanf("%d", &flag);
17         if (flag) {
18             if (inputnum == telcount){ //要删除的是最后一个元素
19                 telcount--;
20             } else{ //不是最后一个元素,则要移动数组元素的位置
21                 for (int i = inputnum; i < telcount; i++){
22                     contacts[inputnum - 1] = contacts[inputnum];
23                     telcount--; //联系人-1
24                 }
25             }
26             //写入文件
27             writefile();
28         }
29     }
30     
31 }

 

3)修改联系人模块

 1 /**
 2  *  编辑联系人
 3  */
 4 void doedit(){
 5     printf("您选择了修改联系人操作\n");
 6     
 7     dolist();
 8     printf("请输入要修改的联系人的编号:\n");
 9     scanf("%d", &inputnum);
10     
11     //定义临时数组保存新联系人的姓名和电话,不直接修改数组
12     char tempname[namelen];
13     char temptelnum[numlen];
14     if (validateinput(inputnum, 1, telcount)) {
15         return;
16     } else{
17         printf("您是否确认要修改联系人\"%s\"的信息? 1.确认 0.取消",
18                contacts[inputnum - 1].telname);
19         scanf("%d", &flag);
20         
21         if (flag) {
22             printf("请输入新的联系人姓名:(*注意姓名中间不能有空格)\n");
23             scanf("%s", tempname);
24             printf("请输入新的联系人电话号码:(*注意电话号码中间不能有空格)\n");
25             scanf("%s", temptelnum);
26             
27             //更新数组信息
28             strcpy(contacts[inputnum - 1].telname, tempname);
29             strcpy(contacts[inputnum - 1].telnum, temptelnum);
30             
31             //保存入文件
32             writefile();
33             
34         }
35     }
36     
37 }

 

4)查看联系人模块

 1 /**
 2  *  显示联系人
 3  */
 4 void dolist(){
 5     if (telcount == 0) {
 6         printf("您的当前的联系人为空,请先添加小伙伴哟~~\n");
 7         return;
 8     }
 9     printf("当前联系人列表:\n");
10     for (int i = 0; i < telcount; i++) {
11         printf("编号%d 姓名: %s, 电话号码: %s\n", i + 1, contacts[i].telname, contacts[i].telnum);
12     }
13 }

 

5)搜索联系人模块

 1 /**
 2  *  搜索联系人
 3  */
 4 void dosearch(){
 5     printf("您当前选择的是搜索联系人操作\n");
 6     
 7     dolist();
 8     char tempname[namelen];  //临时数组
 9     printf("请输入要查找的联系人姓名:\n");
10     scanf("%s",tempname);
11     
12     int i;
13     for (i = 0; i < telcount; i++) {
14         if (strcmp(tempname, contacts[i].telname) == 0){
15             printf("您搜索的联系人\"%s\"的电话号码是%s\n", contacts[i].telname, contacts[i].telnum);
16             break; //找到则循环终止
17         }
18     }
19     //循环一遍还没有找到
20     if (i == telcount){
21         printf("抱歉!没有找到\"%s\"的记录信息\n", tempname);
22     }
23 }

 

6)自定义校验非法数值及写入文件函数

/**
 *  将数组和联系人个数写入文件
 *
 *  @return 1 异常 0 正常
 */
int writefile(){
    //打开文件
    file *fp = fopen(telbook, "wb"); //以二进制写入
    if (fp != null) {
        //将联系人个数写入文件
        fwrite(&telcount, sizeof(telcount), 1, fp);
        //数组写入文件
        for (int i = 0; i < telcount; i++) {
            fwrite(&contacts[i], sizeof(person), 1, fp);
        }
        printf("数据更新成功!\n");
        
    } else{
        printf("数据写入失败!\n");
        return 1;
    }
    
    //关闭指针
    fclose(fp);
    return 0;
}

/**
 *  验证输入是否合法
 *
 *  @param num 待验证的整数
 *  @param min 最小值
 *  @param max 最大值
 *
 *  @return 0.合法  1.非法
 */
int validateinput(int num, int min, int max){
    if (num >= min && num <= max) {
        return 0;
    } else{
        printf("非法输入!\n");
        return 1;
    }
}

分析:

此处为什么一定要将联系人的个数telcount持久化?

因为如果联系人个数如果不持久化,那么每次程序重启后都读取不到联系人了,因为这里使用的是变量数组的形式。所以注意此处一定要持久化个数。

 

7)自定义初始化函数

/**
 初始化
 从文件读取联系人和数组
 */
void init(){

    file *fp = fopen(telbook, "r"); //打开文件
    if (fp != null) {
        //从文件中读取联系人
        fread(&telcount, sizeof(telcount), 1, fp);
        //读取数组
        for (int i = 0; i < telcount; i++) {
            fread(&contacts[i], sizeof(person), 1, fp);
        }
    } else{ //如果没有文件,则创建
        file *fp = fopen(telbook, "wr");
        fwrite(telbook, sizeof(person), 1, fp);
        printf("通讯录创建成功~\n");
    }
    
    //关闭指针
    fclose(fp);
    printf("通讯录初始化成功!~~\n");
    
}

分析:

为什么要有一个初始化的方法?

因为每次系统启动时都必须从文件中读取联系人数组和联系人个数,所以,要有一个初始化方法。

 

8)主界面和主函数

/**
 *  主界面
 */
void startview(){
    printf("********************************\n");
    printf("********  欢迎使用c通讯录   ******\n");
    printf("********  1、添加联系人     ******\n");
    printf("********  2、删除联系人     ******\n");
    printf("********  3、修改联系人     ******\n");
    printf("********  4、查看所有联系人  ******\n");
    printf("********  5、搜索联系人     ******\n");
    printf("********  6、退出系统       ******\n");
    printf("********************************\n");
    printf("请选择1-6之间您要进行的操作\n");
}

/**
 *  主函数
 *
 *  @param argc
 *  @param argv
 *
 *  @return 0 程序正常退出
 */
int main(int argc, const char * argv[]) {
    init();
    while (1) {
        startview();
        scanf("%d", &inputnum);
        switch (inputnum) {
            case 1:
                doadd();
                break;
            case 2:
                dodel();
                break;
            case 3:
                doedit();
                break;
            case 4:
                dolist();
                break;
            case 5:
                dosearch();
                break;
            case 6:
                printf("系统正在退出...\n");
                printf("系统安全退出,感谢您再次使用\n");
                return 0;
            default:
                break;
        }
    }
    return 0;
}