C语言不重复随机点名提问且保存之前记录
继续之前一篇 C语言读取文件方式实现不重复的随机点名程序,在 方式2 的实现上更新点内容,增加文件中空行处理;基于读写文件方式,保存之前点名记录,下一次点名排除掉之前名单,继续不重复随机点名,使得可以公平公正的点到每一位学生,满足每个学生的课堂参与感。
增加部分代码
printf("请输入之前记录的已点过txt学生名单文件: "); // 注意:文件名不支持中文,且文件内容一行一名字
scanf("%s", rfile); // usedStudentsNames.txt
lines = getFileLines(file, arrName);
printf("名单总人数:%d\n", lines);
rlines = getFileLines(rfile, usedArrName);
printf("之前已经点过的名单人数:%d\n", rlines);
// 更新之前已点的人数以及对应名单里行号
for(int m=0; m<rlines; m++)
{
for(int n=0; n<lines; n++)
{
if(strcmp(usedArrName[m],arrName[n])==0)
{
// printf("---names[%d]:%s", n,usedArrName[m]);
index[i] = n;
i++;
}
}
}
完整代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <stdbool.h>
// 读取文件返回文件行数,即总人数,同时将行号对应名字存放到二维数组中
int getFileLines(char *filePath, char arrName[][20])
{
FILE *fp = NULL;
int count = 0;
char StrLine[20] = {0}; // 每行最大读取的字符数 20,
if ((fp = fopen(filePath, "r")) == NULL)
{
fprintf(stderr, "open file error! %s\n", strerror(errno));
}
while (!feof(fp))
{
strcpy(StrLine, "");
fgets(StrLine, 20, fp); // 读取一行,并定位到下一行
if (strcmp(StrLine, "\n") != 0 && strcmp(StrLine, "") != 0)
{
strcpy(arrName[count], StrLine);
// printf("names[%d]:%s", count,arrName[count]);
count++;
}
}
// puts("\n");
fclose(fp);
return count;
}
// 判断某个数是否在数组中重复
bool isContainsNum(int num, int *nums, int numsSize)
{
if (numsSize <= 0)
return false;
for (int i = 0; i < numsSize; i++)
{
if (num == nums[i])
return true;
}
return false;
}
int main(int argc, char *argv[])
{
FILE *wfp = NULL;
char file[50] = {0}, rfile[50] = {0};
int lines = 0, rlines = 0;
int rand_num, nums = 0;
char usedArrName[1000][20] = {0}; // 初始化二维数组,记录已经点过的名单
char arrName[1000][20] = {0}; // 初始化二维数组,存放名字,限制最多点名人数
int i = 0, index[1000] = {0}; // i:记录已点人数;index:记录不重复行号,限制最多点名人数
printf("请输入之前记录的已点过txt学生名单文件: "); // 注意:文件名不支持中文,且文件内容一行一名字
scanf("%s", rfile); // usedStudentsNames.txt
printf("请输入txt学生名单文件: "); // 注意:文件名不支持中文,且文件内容一行一名字
scanf("%s", file); // studentsNames.txt
printf("请输入要点的人数:");
scanf("%d", &nums);
lines = getFileLines(file, arrName);
printf("名单总人数:%d\n", lines);
rlines = getFileLines(rfile, usedArrName);
printf("之前已经点过的名单人数:%d\n", rlines);
if (nums > lines)
{
printf("点名人数大于总人数,请重试!");
return -1;
}
// 更新之前已点的人数以及对应名单里行号
for (int m = 0; m < rlines; m++)
{
for (int n = 0; n < lines; n++)
{
if (strcmp(usedArrName[m], arrName[n]) == 0)
{
// printf("---names[%d]:%s", n,usedArrName[m]);
index[i] = n;
i++;
}
}
}
srand((unsigned)time(NULL)); // 随机数种子
while (true)
{
rand_num = rand() % lines; //[0,lines) => [0,lines-1]
// printf("%d ",n);
if (!isContainsNum(rand_num, index, i))
{ // 没有重复出现则添加到记录中
index[i] = rand_num;
i++;
}
if (i == lines) // 名单已点完一轮
break;
if (i - rlines == nums) // 点的人数够了
break;
}
if ((wfp = fopen(rfile, "a+")) == NULL)
{
fprintf(stderr, "open file error! %s\n", strerror(errno));
}
// for (int l = 0; l < i; l++)
// {
// printf("%d,", index[l]);
// }
puts("\n随机点中的名单:");
for (int l = rlines; l < i; l++)
{
// printf("arrName[%d]=%s",index[i],arrName[index[i]]);
printf("%s", arrName[index[l]]);
fputs(arrName[index[l]], wfp); // 按行追加写入记录文件中
}
if (i == lines)
{
printf("\n学生名单已点完一轮,这次还要重新点%d人,请清空文件继续点", nums - (i - rlines));
}
fclose(wfp);
return 0;
}
执行示例: