C语言实现随机点名器

news2024/11/29 11:44:01

目录

1、程序描述

2、程序功能

3、功能详细实现过程

学生结构体声明和定义

菜单(menu)函数

文件读取和保存函数

查询函数

点名函数

rand函数

点名函数实现

点名次数归零函数

字体颜色变化函数

4、运行效果

5、源码分享


1、程序描述

只使用C语言,制作一个命令行运行的点名程序,该程序运行时用指定txt文件作为“班级”花名册,运行后再界面上显示随机抽取名字的过程,速度由快到慢,逐渐定格到某一个名字上,保存到文件中,程序结束。

2、程序功能

  • 文件形式保存和读取
  • 显示所有同学点名情况
  • 查询单个同学点名情况
  • 开始多个名字点名
  • 开始单个名字点名
  • 保存点名
  • 点名次数归零
  • 字体颜色变化

3、功能详细实现过程

学生结构体声明和定义

“班级花名册”上记录的都是一个同学的信息,在随机点名器这个程序中,我们就需要定义一个结构体保存每个同学的信息,在这里,我们就需要同学名字,点名次数和同学编号,这样就可以定义出下面这样的一个结构体:

#define TOTAL 15    //学生人数

struct Student
{
    char name[30];  //学生姓名
    int num;        //学生编号
    int frequency;  //点名次数
} stu[TOTAL];       //整个班级的学生信息数组

班级的人数是可变的,这里就定义一个宏定义TOTAL来表示班级的人数,然后利用结构体数组来存放所有学生的信息。

菜单(menu)函数

定义完结构体之后,就需要开始进行整个程序的框架搭建,就可以写出一个菜单(menu)函数,方便我们使用程序和单个功能的测试:

//菜单函数
void menu()
{
    printf("********************************************\n");
    printf("********************************************\n");
    printf("***********欢迎使用上课随机点名程序*********\n");
    printf("*****     输入a : 显示所有同学点名情况 *****\n");
    printf("*****     输入b : 查询单个同学点名情况 *****\n");
    printf("*****     输入c : 开始单个名字点名     *****\n");
    printf("*****     输入d : 开始多个名字点名     *****\n");
    printf("*****     输入e : 保存点名             *****\n");
    printf("*****     输入f : 点名次数归零         *****\n");
    printf("*****     输入q : 退出                 *****\n");
    printf("********************************************\n");
    printf("********************************************\n");
}

文件读取和保存函数

完成菜单函数的实现后,就可以进行单个功能函数的实现,显示所有同学点名情况功能和查询单个同学点名情况功能实现之前,我们是不是少了什么东西?是不是少了文件读取和保存?不然怎么知道“班级”同学的信息?所以我们先写出txt文件读取和保存的功能函数出来:

//读取文件函数
void readFile()
{
    FILE * fp = fopen("studentname.txt", "rb");
    if (fp == NULL)
    {
        printf("打开文件失败\n");
        exit(1);
    }
    else
    {
        for (int i = 0; i < TOTAL; i++)
        {
            fscanf(fp, "%d %s %d\n", &stu[i].num, stu[i].name, &stu[i].frequency);
        }
    }
    fclose(fp);
}

//保存文件函数
void saveFile()
{
    FILE* fp = fopen("studentname.txt", "wb");
    if (fp == NULL)
    {
        printf("\n写入文件失败\n");
        return;
    }
    else
    {
        for (int i = 0; i < TOTAL; i++)
        {
            fprintf(fp, "%d %s %d\n", stu[i].num, stu[i].name, stu[i].frequency);
        }
    }
    fclose(fp);
    printf("\n保存成功!\n");
    printf("\n");
}

 这里用到了文件操作的内容,对此感到不是很熟悉的读者可以查看我的这篇博客:

C语言入门篇——文件操作篇_sakura0908的博客-CSDN博客,里面有比较详细的文件操作函数的讲解,对以上的函数就可以理解地比较好了。

查询函数

读取了“班级”文件之后,我们就可以获取所有的学生信息了,就可以实现查询所有同学情况和单个同学点名情况,这两个功能函数是非常容易实现的:

//查询所有学生的点名信息
void all_print()
{
    //显示所有同学点名情况
    printf("\n点名情况\n");
    for (int i = 0; i < TOTAL; i++)
    {
        printf("%-8d\t%-8s\t被点名%d次\n", stu[i].num, stu[i].name, stu[i].frequency);
    }
    printf("\n");
}

//查询单个学生的点名信息
void single_print(int num)
{
    for (int i = 0; i < TOTAL; i++)
    {
        if (stu[i].num == num)
        {
            printf("%-8d\t%-8s\t被点名%d次\n", stu[i].num, stu[i].name, stu[i].frequency);
            printf("\n");
            break;
        }
    }
}

查询所有同学情况直接使用for循环对整个结构体数组遍历打印就可以实现;查询单个同学点名情况就比较复杂一点点,传入要查询同学的编号,遍历结构体数组之后,通过比结构体中的学生编号返回对应的结构体数组的下标。

点名函数

点名函数是这个随机点名器中最核心的功能了,在实现这个功能之前,我们先来了解一下rand这个函数,因为在点名函数中就用到了rand函数,不会使用该函数的话会出现一些读者意想不到的错误运行结果,

rand函数

rand函数,C语言中用来产生一个随机数的函数。

rand函数界限:stdlib.h头文件中有宏#define RAND_MAX 0x7fff
                        rand产生一个0-0x7fff的随机数,即最大是32767的一个数

rand函数头文件:
#include <stdlib.h>

rand函数原型:
int rand(void);

rand()函数每次调用前都会查询是否调用过srand(seed),是否给seed设定了一个值,如果有那么它会自动调用srand(seed)一次来初始化它的起始值;若之前没有调用srand(seed),那么系统会自动给seed赋初始值,即srand(1)自动调用它一次

srand函数:srand函数是随机数发生器的初始化函数

srand函数头文件:
#include <stdlib.h>

srand函数原型:
void srand(unsigned int seed);

这个函数需要提供一个种子,如srand(1),用1来初始化种子。rand()产生随机数时,如果用srand(seed)播下种子之后,一旦种子相同,产生的随机数将是相同的。当然很多时候刻意让rand()产生的随机数随机化,用时间作种子 srand(time(NULL)),这样每次运行程序的时间肯定是不相同的,产生的随机数肯定就不一样了。
我们常常使用系统时间来初始化,使用time函数来获取系统时间,得到的值是一个时间戳,即2023年5月15日13点到现在时间的秒数,然后将得到的time_t类型数据转化为(unsigned int)的数,然后再传给srand函数

srand((unsigned int)time(NULL));//我们在使用rand和srand时,主要使用的就是这一种初始化方法!!

如果仍然觉得时间间隔太小,可以在(unsigned)time(0)或者(unsigned)time(NULL)后面乘上某个合适的整数。 
time的参数传NULL表示不需要经过参数获得到的time_t数据,time函数原型如下

time函数头文件:
#include <time.h>

time函数原型:
time_t time(time_t *tloc);//time_t类型被定义为一个长整型

还有另外一种初始化种子的方式如下,用进程的pid作为种子值seed,在同一个程序中,这样的种子的值是相同的

srand((unsigned int)getpid());

rand函数的使用,如果想要表示一个数是从0开始到最大值的,比如说,想要产生一个0-99之间的随机数,那么用法如下:

int num = rand() % 100;

如果想要产生一个数是从1开始到最大值的,比如说,想要产生一个1-100之间的随机数,那么用法如下:

int num = rand() % 100 + 1;

需要注意最后+1和不+1的区别,+1的最小值是1,不+1的最小值是0

点名函数实现

在随机点名的时候需要实现名字闪烁的功能,就需要用到\r这个转义字符,它的作用,是将光标移动到行首,但不换行,此时如果输出信息,那么这些信息就会覆盖原有的内容。重复这个过程,妥善处理一行内容长短不一的问题,就可以在同一样中不断闪现不同的名字。单个同学点名函数如下:

//单个学生点名函数
void Named()
{
    int id = -1;
    int t = 300;
    //为rand()配置随机数产生的“种子”系数,获取当前系统时间
    srand((unsigned)time(NULL));

    printf("\n开始点名\n");
    //循环15次随机点数功能
    for (int i = 0; i < 15; i++)
    {
        for (int j = 0; j < TOTAL; j++)
        {
            //求余取得名字对应的数组下标和其对应的内存地址
            id = rand() % 15;
            //实现名字闪烁的功能
            printf("\r                                   \r");
            printf("%s", stu[id].name);
            fflush(stdout);
        }
        //闪烁时间的慢慢增长
        Sleep(t);
        t += 60;
    }
    printf("\n幸运者是:%s\n", stu[id].name);

    //增加抽到同学的点名次数
    stu[id].frequency += 1;
    printf("\n");
}

 多个学生点名的函数值需要在单个同学点名的情况上稍加修改(增添点名学生个数)就可以实现了,升级版的点名函数为:

//学生点名函数
void Named(int num)
{
    int id = -1;
    int t = 300;
    //为rand()配置随机数产生的“种子”系数,获取当前系统时间
    srand((unsigned)time(NULL));

    printf("\n开始点名\n");
    //循环15次随机点数功能
    for (int k = 0; k < num; k++)
    {
        for (int i = 0; i < 15; i++)
        {
            for (int j = 0; j < TOTAL; j++)
            {
                //求余取得名字对应的数组下标和其对应的内存地址
                id = rand() % 15;
                //实现名字闪烁的功能
                printf("\r                                   \r");
                printf("%s", stu[id].name);
                fflush(stdout);
            }
            //闪烁时间的慢慢增长
            Sleep(t);
            t += 60;
        }
        printf("\n幸运者是:%s\n", stu[id].name);
        //增加抽到同学的点名次数
        stu[id].frequency += 1;
    }
    printf("\n");
}

点名次数归零函数

这个函数的功能顾名思义就知道是把学生的点名次数归零,实现步骤也很简单,遍历整个学生信息结构体数组,把每个学生的的结构体中的点名次数重新赋值为0就可以实现了:

//点名次数归零函数
void to_Zero()
{
    for (int i = 0; i < TOTAL; i++)
    {
        stu[i].frequency = 0;
    }
    printf("\n点名次数归零\n");
    printf("\n");
}

字体颜色变化函数

0=黑色 8=灰色  
1=蓝色 9=淡蓝色   
2=绿色 10=淡绿色   
3=蓝色 11=浅绿色
4=红色 12=淡红色  
5=紫色 13=淡紫色   
6=黄色 14=淡黄色   
7=白色 15=亮白色

int color_num = 0;

//字体颜色变化函数
void color(int x)
{
    if (x >= 0 && x <= 15)
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x);
    else//其他白色
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}

//前缀++运算符优先级比求模运算符优先级要高
color(++color_num % 16);

对上面的操作符优先级有问题的可以查看这篇博客里面的运算符优先级介绍:

C语言入门篇——操作符篇_sakura0908的博客-CSDN博客

4、运行效果

这里只提供部分运行效果截图

5、源码分享

功能函数上面写的差不多了,最后附上程序的主函数,有兴趣的读者可以copy下来自己运行一下这个有趣的程序:

int main()
{
    int num = 0;
    char c = '\0';

    while (1)
    {
        menu();
        readFile();
        while ((c = getchar()) != 'q')
        {
            color(++color_num % 16);
            printf("请输入你要选择的功能:");
            c = getchar();
            switch (c)
            {
                case 'a':
                    color(++color_num % 16);
                    all_print();
                    break;
                case 'b':
                    color(++color_num % 16);
                    printf("请输入你要查询学生的学生编号:");
                    scanf("%d", &num);
                    single_print(num);
                    break;
                case 'c':
                    color(++color_num % 16);
                    Named(1);
                    break;
                case 'd':
                    color(++color_num % 16);
                    printf("请输入你要点名的人数:");
                    scanf("%d", &num);
                    Named(num);
                    break;
                case 'e':
                    color(++color_num % 16);
                    saveFile();
                    break;
                case 'f'://点名次数归零  
                    color(++color_num % 16);
                    to_Zero();
                    break;
                case 'q':
                    printf("\n欢迎下次使用随机点名器!\n");
                    exit(0);
            }
        }
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/528243.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ANR实战案例 2 - 不同线程状态ANR示例

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 文章目录 系列文章目录前言一、Blocked状态示例1.启动初始化阻塞案例trace1.tx 2.ConcurrentHashMap分段锁优…

互联网营销之何谓真需求-想知道如何挖掘真需求看这篇就对了

互联网营销思维是以爆品为核心的迭代思维&#xff0c;本文结合“生日蛋糕”、“方便面”、“蜜雪冰城”几个小例子&#xff0c;以及我们具体的工作&#xff0c;展开聊聊什么是“真需求”。 1. 互联网营销和传统营销的区别 1.1 传统的营销思维&#xff1a; “定位4P&#xff0…

亚马逊云科技:使用Inf2实例运行大语言模型GPT-J-6B基础设施

在2019年的亚马逊云科技re:Invent上&#xff0c;亚马逊云科技发布了Inferentia芯片和Inf1实例这两个基础设施。Inferentia是一种高性能机器学习推理芯片&#xff0c;由亚马逊云科技定制设计&#xff0c;其目的是提供具有成本效益的大规模低延迟预测。时隔四年&#xff0c;2023年…

金融行业软件测试面试必备:答案详解与干货技巧

大家好&#xff0c;今天我要和大家分享的是我多年从事金融行业软件测试的心得体会。由于金融行业涉及到的数据量非常大&#xff0c;系统功能也十分复杂&#xff0c;因此在招聘软件测试人员时&#xff0c;往往会提出一些具有挑战性的问题。 作为一个资深面试官&#xff0c;我也…

Android aidl及binder基础知识巩固

作者&#xff1a;义华 1、什么是binder binder是android framework提供的&#xff0c;用于跨进程方法调用的机制&#xff0c;具有安全高效等特点。 我们知道&#xff0c;在 Android 系统中&#xff0c;每个应用程序都运行在一个独立的进程中&#xff0c;各个进程之间需要进行…

Logstash-grok表达式常用模式与正则使用与测试

Logstash 常用字符解释常用模式使用方式 使用正则表达式使用方式 测试用例 常用字符解释 \ 表示匹配 \s* 匹配空格&#xff08;可多个&#xff09; \w 匹配字符&#xff08;可多个&#xff09;常用模式 %{HOSTNAME}&#xff0c;匹配请求的主机名 %{TIMESTAMP_ISO8601:time…

探索智能化:TOOM解析未来稿件校验系统的技术进展与应用展望

在信息时代&#xff0c;随着大数据、人工智能和自然语言处理等技术的快速发展&#xff0c;稿件校验系统正朝着智能化的方向迈进。智能化的稿件校验系统能够更准确、高效地检测虚假信息、抄袭行为以及提升文章质量。本文将探讨智能化稿件校验系统的技术进展与应用展望&#xff0…

NC与单一窗口数据对接丨外贸软件

在国际贸易通关过程中&#xff0c;所涉及相关部门的信息管理&#xff0c;主要是以数字化流程系统为主&#xff0c;让每个部门业务的申请、办理、回复采用电子化和互联网化。由于每个环节部分的数据壁垒未打通&#xff0c;数据无法协同共享&#xff0c;导致在口岸通关的过程中&a…

Swoole定时器实现毫秒级任务调度

简介 Timer 毫秒精度的定时器&#xff0c;底层基于 epoll_wait 和 setitimer 实现&#xff0c;数据结构使用最小堆&#xff0c;可支持添加大量定时器&#xff0c;使用最小堆数据结构实现的定时器&#xff0c;类似 JavaScript 的 setInterval&#xff0c;Swoole 定时器的添加和…

I2C通信协议原理和MPU6050

一、串口通讯 只能在两个设备之间进行 若要三台设备两两通信&#xff0c;则每个设备得需要两组窗口&#xff0c;为3组相互独立的窗口通讯 为解决这个问题&#xff1a;设计了总线通讯&#xff0c;有多种&#xff0c;I2C为其中一种 二、I2C通信 &#xff08;1&#…

(java)异常 (详解)

目录 1. 异常的概念 1. 算术异常 2.空指针异常 3.数组越界异常 4.在编译时就发现了异常 2.异常的体系结构 总结&#xff1a; 3.异常的分类 4.异常的处理 1 .防御式编程 2.异常的抛出 3 .异常的捕获 3.1 .异常声明throws throw和throws的区别&#xff1f; …

【笔试强训选择题】Day13.习题(错题)解析

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;笔试强训选择题 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01; 文章目录…

昨天的测试岗面试,仅仅4个问题,轻松让面试者破防了

目录 引言 你看&#xff0c;一不小心&#xff0c;就要被虐&#xff01;&#xff01; 自动化测试到底该如何学&#xff1f; 一、Python编程学习内容 二、WEB自动化测试学习内容 三、APP自动化测试学习内容 四、Postman接口测试工具学习内容 五、接口自动化测试学习内容 …

微服务框架【Nacos配置管理-Feign远程调用-Gateway服务网关】

一、Nacos配置管理 1.统一配置管理 在Nacos中添加配置信息 填写配置信息 点击发布 完成配置的统一管理 配置获取的步骤&#xff1a; 项目启动->读取本地配置文件application.yml->创建spring容器->加载bean 但是现在多了一个nacos中的配置文件&#xff0c;我们…

IntelliJ IDEA 统一设置编码为utf-8编码 及 SpringBoot 打 jar 包运行 在windows 平台控制台和日志 乱码解决

文章目录 一、背景二、知识准备三、程序运行源代码历经处理阶段四、问题描述五、解决方法1.修改项目编码格式统一为UTF-82.将项目中的.idea文件夹中的encodings.xml文件中的编码格式改为uft-83.File->Settings->Build,Execution,Deployment -> Compiler -> Java Co…

架构师日记-从数据库发展历程到数据结构设计探析 | 京东云技术团队

作者&#xff1a;京东零售 刘慧卿 一、数据库发展史 起初&#xff0c;数据的管理方式是文件系统&#xff0c;数据存储在文件中&#xff0c;数据管理和维护都由程序员完成。后来发展出树形结构和网状结构的数据库&#xff0c;但都存在着难以扩展和维护的问题。直到七十年代&am…

分布式补充知识 02.AOP的重要注解@annotation ,使用添加缓存和清空缓存

01.在项目中创建一个包annotation包&#xff1a; 在创建新的java.class文件时候&#xff0c;选择annotation 写一个自定义的注解&#xff0c;名字叫做RequiredCache package com.cy.annotation;package com.cy.annotation;import java.lang.annotation.ElementType; import j…

企业远程工作安全及简化

员工远程面临哪些挑战 大多数企业已将远程工作模式作为其新常态&#xff0c;这使得保护远程端点成为比以往更高的优先级。然而&#xff0c;在寻求远程工作支持的安全性时&#xff0c;企业有时会忽视用户体验。过于严格的远程工作解决方案没有考虑到经常在工作场所和家庭的安全…

执行SQL响应比较慢,你有哪些排查思路?

如果执行SQL响应比较慢&#xff0c;我觉得可能有以下4个原因&#xff1a; 第1个原因&#xff1a;没有索引或者 导致索引失效。第2个原因&#xff1a;单表数据量数据过多&#xff0c;导致查询瓶颈第3个原因&#xff1a;网络原因或者机器负载过高。第4个原因&#xff1a;热点数据…

基于Canal实现Mysql数据实时同步到Elasticsearch(Docker版)

1、Canal简介 Canal主要用途是对MySQL数据库增量日志进行解析&#xff0c;提供增量数据的订阅和消费&#xff0c;简单说就是可以对MySQL的增量数据进行实时同步&#xff0c;支持同步到MySQL、Elasticsearch、HBase等数据存储中去。 Canal会模拟MySQL主库和从库的交互协议&#…