青年大学习自动名单核对程序

前言

  1. 作者使用的编辑器为Visual Studio 2019,版本号16.5.3(2020年4月12日最新版)。
  2. 本文篇幅会很长,我会将我自己编写这个程序和优化的过程全部写下来。其中涉及到的诸多函数,会在另外的一篇博文中解析。(去看看<—还没写好先别急,写好了会把链接放上(⊙ω⊙))有一定基础的同学阅读时间在15分钟左右,所以建议先收藏(✿◠‿◠)!
  3. 我会分阶段介绍编写程序和优化完善,我将函待解决的问题和可以实现的想法写在了每一段的最前面,本文对函数使用和结构介绍内容较少,如果有不懂的地方可以私信给我哦(⊙▽⊙)。
  4. 截止到本篇博文发表,我学习C/C++的时间还不到四个月,如有错误请多多指教!
  5. 详细使用教程:青年大学习自动名单核对程序(使用教程)
  6. 2021年6月更新:我写了一个窗口程序,用来实现本文的操作,提取码:mchx。
  7. 2021年7月更新:对于窗口程序的使用教程在这里。(目前还没有写好)

编写本程序的原因

这个小程序来自于一个很偶然的想法,我作为班级团支书,核对青年大学习的名单是一件既费时又费力还没有技术含量的事情。那为何不写一个能够自动核对名单的小程序呢?
在这里插入图片描述

构建程序

想法固然很简单,但是实现起来就很麻烦。基于C/C++最最最基础的内容,我目前也只能构建单机控制台程序(就是那个毫无美感的黑方块)。

但是不得不说,从一开始有这个想法,到开始编写的过程,是无比艰辛的。我对C语言还停留在字符串、循环等等最基本的概念上。本文也是在有一定C/C++基础上撰写的,我会尽量用基础论述问题。

第一阶段:构建主体

问题or想法:用程序实现对比功能,并将不符合某些要求的量输出到屏幕上。

首先我们知道:一个个名字都是由字符串构成的,而很多名字在一起就是字符串数组了。所以我们比较的其实是两个字符串数组(班级名单、青年大学习完成名单)之间不同的地方。所以我们可以得知整个程序的核心:

核心:比较字符串数组之间的不同。
方法:

  1. 字符串数组A中的一个元素与字符串数组B中的所有元素依次比较(班级名单中的一个人名与青年大学习完成名单作比较);
  2. 如果出现相同则证明这个元素在字符串数组B中存在(如果这个名字在青年大学习完成名单中有,则证明这名同学完成青年大学习)。

使用函数:extern int strcmp(const char *s1,const char *s2)【string compare“字符串比较”的缩写】

//略去头文件和主函数
char buf_1[8][],buf_2[8][];//分别代表班级名单、青年大学习完成名单
for (int i = 1; i < n; i++)//进行判断
    {
        while(strcmp(buf_2[i], buf_1[m]) != 0)
        {
            m++;
            if (m == 80)
            {
                printf("[%d]%s\t\t未完成", i, buf_2[i]);
                    break;
            }
        }
        if (strcmp(buf_2[i], buf_1[m]) == 0)
        {
                printf("[%d]%s\t\t已完成", i, buf_2[i]);
        }
        m = 1;
    }

第二阶段:输入输出

青年大学习每次都有不一样的名单,所以我们需要重新编辑字符串数组。那么总不能直接更改程序吧,所以我们需要从文件中读取相关信息并保存到程序中。查阅了很多大佬的项目之后,发现直接保存在文本文档是最简单的方法。

问题or想法:将文本文档里的数据读取到程序里的字符串数组。
方法:预读取文件,读取成功的话开始依次读取信息
使用函数:
FILE * fopen(const char *filename, const char *mode)【读取文本文件】
int fscanf(FILE * stream, const char * format, [argument…])【从输入流(stream)中读入数据,存储到argument中】

//略去头文件

void File_search(FILE* n,const char* a)//尝试打开文件,注意文件保存格式为(ANSL)防止出现错漏(下同)
{
    if ((n = fopen(a, "r")) == NULL)
    {
        printf("fail to read & %s", a);//如果不存在,输出fail to read +文件名,并结束程序
        exit(1);
    }
}

int main()
{
    File_search(fp, "new.txt");//检测文件“new.txt”是否存在
    File_search(fg, "date.txt");//检测文件“date.txt”是否存在

    for (int i = 1; fscanf(fp, "%s%s", buf_1[i], buf_11[i]) != EOF; i++);//将学习名单写入数组buf_1
    for (int i = 1; fscanf(fg, "%s%s", buf_2[i], buf_22[i]) != EOF; i++);//将班级名单写入数组buf_2
}

第三阶段:构建完整程序

这就没啥废话可以说了,直接亮代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>

#define MAX_LINE 80//全局常量

void File_search(FILE* n,const char* a)//尝试打开文件,注意文件保存格式为(ANSL)防止出现错漏(下同)
{
    if ((n = fopen(a, "r")) == NULL)
    {
        printf("fail to read & %s", a);
        exit(1);
    }
}

int main()
{
    FILE* fp = fopen("new.txt","r");// new  文件指针
    FILE* fg = fopen("date.txt","r");// date 文件指针

    char buf_1 [MAX_LINE][25] = { 0 };//学习情况名单数组
    char buf_11[MAX_LINE][25] = { 0 };//承接无用字符
    char buf_2 [MAX_LINE][25] = { 0 };//班级学生名单数组
    char buf_22[MAX_LINE][25] = { 0 };//承接组别字符
    int Class_size = 80;//班级总人数

    File_search(fp, "new.txt");//检测文件“new.txt”是否存在
    File_search(fg, "date.txt");//检测文件“date.txt”是否存在

    for (int i = 1; fscanf(fp, "%s%s", buf_1[i], buf_11[i]) != EOF; i++);    //将学习名单写入数组buf_1
    for (int i = 1; fscanf(fg, "%s%s", buf_2[i], buf_22[i]) != EOF; i++);      //将班级名单写入数组buf_2

    for (int i = 1; i < Class_size; i++)      //进行判断
    {
        int m = 1;//循环变量
        while (strcmp(buf_2[i], buf_1[m]) != 0)
        {
            m++;
            if (m == MAX_LINE)
            {
                printf("[%d]%s\t未完成", i, buf_2[i]);
                printf("\t%s\n", buf_22[i]);
                break;
            }
        }
        if (strcmp(buf_2[i], buf_1[m]) == 0)
        {
            printf("[%d]%s\t已完成", i, buf_2[i]);
            printf("\t%s\n", buf_22[i]);
        }
    }
    Sleep(10000);
    return 0;
}

第四阶段:优化程序

有的同学跟我提出,能不能选择性输出,就比如说只输出未完成的同学姓名,选择性输出组别。

可以啊!

问题or想法:在程序最开始选择输出模式(输入“是”或“否”)
方法:编写新的输出控制函数,通过不同的返回值控制主函数输出方式的不同
使用函数:
char * gets_s(char * buffer,size_t sizeInCharacters)【从键盘上读取输入的字符放到字符串数组里】
extern int strcmp(const char * s1,const char * s2)【string compare“字符串比较”的缩写】

输出控制函数:

int Output(const char* a)//通用输出引擎
{
    char d[8] = { "是" };//是字符串
    char f[8] = { 0 };

    printf(a);
    gets_s(f, 3);

    if (strcmp(d, f) == 0)
        return 1;
    else
        return 0;
}

主函数引用:

Output_1 = Output("请问是否需要只输出未完成(填写‘是’或‘否’):");//第一个输出设置返回值引入
Output_2 = Output("请问是否需要输出组别(填写‘是’或‘否’):");//第二个输出设置返回值引入

输出模式引用:

    for (int i = 1; i < Class_size; i++)      //进行判断
    {
        int m = 1;//循环变量
        while (strcmp(buf_2[i], buf_1[m]) != 0)
        {
            m++;
            if (m == MAX_LINE)
            {
                printf("[%d]%s\t未完成", i, buf_2[i]);
                if (Output_2 == 1)//是否输出组别
                    printf("\t%s", buf_22[i]);
                printf("\n");
                break;
            }
        }
        if (strcmp(buf_2[i], buf_1[m]) == 0)
        {
            if (Output_1 == 0)
            {
                printf("[%d]%s\t已完成", i, buf_2[i]);
                if (Output_2 == 1)//是否输出组别
                    printf("\t%s", buf_22[i]);
                printf("\n");
            }
        }
    }

PS:为何要写通用输出控制函数呢?
这样写的好处:以后如果需要增加控制模式,可以直接在主函数调用本控制函数,最多增加4-5行即可完成控制变量增加。

最后我们不妨再优化一下,加入未完成人数统计。这样这个程序就完整的写出来啦!

程序实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>

#define MAX_LINE 80//全局常量

int Output(const char* a)//通用输出引擎
{
    char d[8] = { "是" };//是字符串
    char f[8] = { 0 };

    printf(a);
    gets_s(f, 3);

    if (strcmp(d, f) == 0)
        return 1;
    else
        return 0;
}

void File_search(FILE* n,const char* a)//尝试打开文件,注意文件保存格式为(ANSL)防止出现错漏(下同)
{
    if ((n = fopen(a, "r")) == NULL)
    {
        printf("fail to read & %s", a);
        exit(1);
    }
}

int main()
{
    char buf_1[MAX_LINE][25] = { 0 };//学习情况名单数组
    char buf_11[MAX_LINE][25] = { 0 };//承接无用字符
    char buf_2[MAX_LINE][25] = { 0 };//班级学生名单数组
    char buf_22[MAX_LINE][25] = { 0 };//承接组别字符

    FILE* fp = fopen("new.txt","r");// new  文件指针
    FILE* fg = fopen("date.txt","r");// date 文件指针

    int Class_size = 80;//班级总人数
    int Output_1 = 0;//输出设置1返回值
    int Output_2 = 0;//输出设置2返回值
    int Unfinished_student = 0;//未完成学生人数

    Output_1 = Output("请问是否需要只输出未完成(填写‘是’或‘否’):");//第一个输出设置返回值引入
    Output_2 = Output("请问是否需要输出组别(填写‘是’或‘否’):");//第二个输出设置返回值引入

    File_search(fp, "new.txt");//检测文件“new.txt”是否存在
    File_search(fg, "date.txt");//检测文件“date.txt”是否存在

    for (int i = 1; fscanf(fp, "%s%s", buf_1[i], buf_11[i]) != EOF; i++);    //将学习名单写入数组buf_1
    for (int i = 1; fscanf(fg, "%s%s", buf_2[i], buf_22[i]) != EOF; i++);      //将班级名单写入数组buf_2

    for (int i = 1; i < Class_size; i++)      //进行判断
    {
        int m = 1;//循环变量
        while (strcmp(buf_2[i], buf_1[m]) != 0)
        {
            m++;
            if (m == MAX_LINE)
            {
                printf("[%d]%s\t未完成", i, buf_2[i]);
                if (Output_2 == 1)//是否输出组别
                    printf("\t%s", buf_22[i]);
                printf("\n");
                Unfinished_student++;//未完成人数统计
                break;
            }
        }
        if (strcmp(buf_2[i], buf_1[m]) == 0)
        {
            if (Output_1 == 0)
            {
                printf("[%d]%s\t已完成", i, buf_2[i]);
                if (Output_2 == 1)//是否输出组别
                    printf("\t%s", buf_22[i]);
                printf("\n");
            }
        }
    }
    printf("\n\t我班共有%d人未完成", Unfinished_student);//显示未完成人数
    Sleep(10000);
    return 0;
}
  • 10
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值