mxwawaawxm 发表于 2021-6-21 15:53

c语言生成随机数

本帖最后由 mxwawaawxm 于 2021-7-14 22:05 编辑

# 功能需求
挺无聊的功能,而且自己代码写得太杂乱了
用户编辑配置文件random_config.ini里的参数,如随机数的最小值和最大值、生成随机数的个数、不生成的随机数

读取random_config.ini里参数的值,并生成不重复的随机数

# 源代码

```c
/*
1、尝试读取配置文件random_config.ini的信息
    失败,说明缺少配置文件
    成功,读取配置文件里的min_num、max_num、times
            定义标志数组int flags,依次存放是否正确读取参数值min_num、max_num、times、blacklist_num的标志
            只有正确读取min_num,才尝试读取max_num。其余一样

            读取blacklist_num
                先存储进字符串blacklist_num_str
                再切分转化成数字,存储进数组blacklist_num
                同时统计数组blacklist_num元素的个数

2、依据min_num、max_num、times、blacklist_num,生成随机数
    检查min_num会否大于max_num
    检查times会否超过min_num和max_num的差值
      确保随机数不重复
      确保随机数不是blacklist_num的数字
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

#define CONFIG "random_config.ini"
#define MIN_NUM "min_num"
#define MAX_NUM "max_num"
#define TIMES "times"
#define BLACKLIST_NUM "blacklist_num"
#define BLACKLIST_LEN 20
#define BLACKLIST_STR_LEN 100

int file_exist(const char *file_name);
void read_info(const char *file_name, int *min_num, int *max_num, int *times, char *blacklist_num_str, int *flags);
void read_info_num(FILE *fp, const char *info, int *num_info, int *flag);
void read_info_blacklist(FILE *fp, const char *info, char *blacklist_num_str, int *flag);
void split_blacklist_num_str(char *blacklist_num_str, int *blacklist_num, int *blacklist_num_real);
void print_blacklist_num(int *blacklist_num, int blacklist_num_real);
void generate_rand_num(int min_num, int max_num, int times, int *blacklist_num, int blacklist_num_real);
void chk_num(int num, int *rand_num_array, int *idx, int *blacklist_num, int blacklist_num_real);
void ignore_comment(FILE *fp);

int main(int argc, const char *argv[])
{
    // 可能的最小数字、最大数字、最多生成多少个数字
    int min_num, max_num, times;
    // 存放读取min_num、max_num、times、blacklist_num的标志
    int flags = {0};
    // 不生成的数字序列数组,最多20个
    int blacklist_num;
    // 不生成的数字序列数组有效个数
    int blacklist_num_real=0;
    // 不生成的数字序列字符串
    char blacklist_num_str;

    // 文件存在
    if (file_exist(CONFIG)==0) {
      // 读取配置文件信息
      read_info(CONFIG, &min_num, &max_num, ×, blacklist_num_str, flags);
      // 把字符串blacklist_num_str依次切分,并转化为数字
      // 并存储进数组blacklist_num
      split_blacklist_num_str(blacklist_num_str, blacklist_num, &blacklist_num_real);

      // 打印转化成数字后的数组blacklist_num,测试用途,非必需
      // print_blacklist_num(blacklist_num, blacklist_num_real);

      // 检查min_num、max_num、times是否正确读取
      if ((*flags) * *(flags+1) * *(flags+2)==1) {
            generate_rand_num(min_num, max_num, times, blacklist_num, blacklist_num_real);
      }
    } else {
      printf("%s%s", CONFIG, "不存在");
    }
   
    return 0;
}

/* 判断配置文件是否存在 */
int file_exist(const char *file_name)
{
    // F_OK=0,文件存在
    return access(file_name, F_OK);
}

/* 读取配置文件信息 */
void read_info(const char *file_name, int *min_num, int *max_num, int *times, char *blacklist_num_str, int *flags)
{
    FILE *fp = fopen(file_name, "r");

    if (fp==NULL) {
      printf("读取配置%s文件失败\n", file_name);
    } else {
      // 读取随机数可能的最小数字min_num
      read_info_num(fp, MIN_NUM, min_num, flags);
      
      if (*flags==1) {
            // 读取随机数可能的最大数字max_num
            read_info_num(fp, MAX_NUM, max_num, flags+1);
      }
      
      if (*(flags+1)==1) {
            // 读取随机数最多生成多少个数字times
            read_info_num(fp, TIMES, times, flags+2);
      }
      
      if (*(flags+2)==1) {
            // 读取随机数不生成的数字
            // 并存储进字符串blacklist_num_str
            read_info_blacklist(fp, BLACKLIST_NUM, blacklist_num_str, flags+3);
      }
    }

    fclose(fp);
}

/* 跳过ini配置文件的注释 */
void ignore_comment(FILE *fp)
{
    int character = fgetc(fp);

    while (!feof(fp) && (character==';' || character!='\n')) {
      character = fgetc(fp);
    }      
}

/* 读取配置文件里min_num、max_num、times */
void read_info_num(FILE *fp, const char *info, int *num_info, int *flag)
{
    // =%d\n\0,总共5个字符
    char *format_char = (char *)malloc((strlen(info)+5)*sizeof(char));
    // 生成格式化字符串
    sprintf(format_char, "%s=%%d\n", info);
    // printf("%s\n", format_char);

    // 跳过ini配置文件的注释
    ignore_comment(fp);
    if ((fscanf(fp, format_char, num_info))==1) {
      printf(format_char, *num_info);
      *flag = 1;
    } else {
      printf("读取%s出错,请检查参数值是否填写错误\n", info);
    }
    // 清空缓存
    fflush(stdin);
    fflush(stdout);
    // 释放动态分配的内存空间
    free(format_char);
}

/* 读取配置文件里参数blacklist_num
   并存储进字符串blacklist_num_str */
void read_info_blacklist(FILE *fp, const char *info, char *blacklist_num_str, int *flag)
{
    // =%d\n\0,总共5个字符
    char *format_char = (char *)malloc((strlen(info)+5)*sizeof(char));
    // 生成格式化字符串
    sprintf(format_char, "%s=", info);
    // printf("%s\n", format_char);

    // 跳过ini配置文件的注释
    ignore_comment(fp);
    // 读取掉前面的参数blacklist_num=
    fscanf(fp, format_char);

    if ((fgets(blacklist_num_str, BLACKLIST_STR_LEN, fp))!=NULL) {
      printf("%s%s\n", format_char, blacklist_num_str);
      // printf(format_char, blacklist_num_str);
      *flag = 1;
    } else {
      printf("读取%s出错,参数数值可能为空或者填写错误\n", info);
    }
    // 清空缓存
    fflush(stdin);
    fflush(stdout);
    // 释放动态分配的内存空间
    free(format_char);
}

/* 把字符串blacklist_num_str依次切分,并转化为数字
   并存储进数组blacklist_num */
void split_blacklist_num_str(char *blacklist_num_str, int *blacklist_num, int *blacklist_num_real)
{
    const char *delim = ", /n";
    char *saveptr = NULL;
    char *token;

    token = strtok_s(blacklist_num_str, delim, &saveptr);

    while (token!=NULL && *blacklist_num_real<BLACKLIST_LEN) {
      // printf("%s\n", token);
      *(blacklist_num++) = atoi(token);
      (*blacklist_num_real)++;
      token = strtok_r(NULL, delim, &saveptr);
    }
}

/* 打印转化成数字后的数组blacklist_num,测试用途,非必需 */
void print_blacklist_num(int *blacklist_num, int blacklist_num_real)
{
    for (int i=0;i<blacklist_num_real;i++) {
      printf("%d ", *(blacklist_num+i));
    }
    printf("\n");
}

/* 生成随机数 */
void generate_rand_num(int min_num, int max_num, int times, int *blacklist_num, int blacklist_num_real)
{
    srand(time(NULL));

    // 检查min_num会否大于max_num
    if (min_num>max_num) {
      fprintf(stdout, "随机数的最小值大于最大值,请检查配置文件参数值是否正确\n");
    // 检查times会否超过min_num和max_num的差值
    } else if (times>=max_num-min_num) {
      fprintf(stdout, "生成数字的个数超过最大值和最小值的差值\n");
    } else {
      int idx, num;
      // printf("%d\n", times);
      int *rand_num_array = (int *)malloc(sizeof(int)*times);

      printf("\n\n==========================================\n生成的随机数是\n");
      for (idx=0;idx<times;) {
            num = rand()%(max_num-min_num+1)+min_num;
            chk_num(num, rand_num_array, &idx, blacklist_num, blacklist_num_real);
      }
      for (idx=0;idx<times;idx++) {
            printf("%d\n", *(rand_num_array+idx));
      }
      printf("==========================================\n");
      free(rand_num_array);
    }
}

/* 检查随机数是否有效 */
void chk_num(int num, int *rand_num_array, int *idx, int *blacklist_num, int blacklist_num_real)
{
    int i, flag_dup=1, flag_blacklist=1;

    // 检查生成的随机数是否重复
    for (i=0;i<*idx;i++) {
      if (num==*(rand_num_array+i)) {
            flag_dup=0;
            break;
      }
    }

    // 检查生成的随机数是否是黑名单数字
    if (flag_dup==1) {
      for (i=0;i<blacklist_num_real;i++) {
            if (num==*(blacklist_num+i)) {
                flag_blacklist=0;
                break;
            }
      }
    }

    // 随机数有效,存入rand_num_array,并将索引递增
    if (flag_dup==1 && flag_blacklist==1) {
      *(rand_num_array+*idx) = num;
      (*idx)++;
    }
}
```

# 编译后的文件

打开后运行cmd文件,需要编辑参数,就在random_config.ini里编辑参数的值



mxwawaawxm 发表于 2021-7-10 06:40

xub66sh 发表于 2021-7-9 15:24
你用srand(time(0))函数避免随机数重复,然后求模运算%68+1,结果跟你不需要的数字对比,一样的话重新 ...

/* 检查随机数是否有效 */
void chk_num(int num, int *rand_num_array, int *idx, int *blacklist_num, int blacklist_num_real)

我写的 检测随机数是否有效,是检测两方面,检测随机数会否跟生成的数字重复以及随机数会否跟 不需要的数字 相同

mxwawaawxm 发表于 2021-7-14 21:31

c03xp 发表于 2021-7-13 10:52
既然用到ini格式了,就没必要自己解析了。使用GetProfileString系列

查了下,是不是应该用GetPrivateProfileInt、GetPrivateProfileString函数
而且ini格式里,还能写注释吗
而且是不是要得严格按这样的格式写ini文件

key=name

sergin 发表于 2021-6-21 19:02

谢谢楼主分享!支持!

nappywu 发表于 2021-6-23 15:23

学习了,这个我们也研究过

intel286 发表于 2021-6-24 06:14

不错,想过几次没有思路

zjtwxws 发表于 2021-6-27 18:47

zjtwxws 发表于 2021-6-27 19:19

ajm3 发表于 2021-6-28 09:38

这么复杂
c#语言
Random n1 = new Random();
                string ran = (n1.Next(100000, 900000) * DateTime.Now.Millisecond + 99999).ToString().Substring(0, 6);
2句代码搞定

mxwawaawxm 发表于 2021-6-28 18:41

本帖最后由 mxwawaawxm 于 2021-6-28 18:43 编辑

我前面是写了功能需求的,不全是生成随机数@ajm3
用户编辑配置文件random_config.ini里的参数,如随机数的最小值和最大值、生成随机数的个数、不生成的随机数
读取random_config.ini里参数的值,并生成不重复的随机数

https://attach.52pojie.cn/forum/202106/21/155659vjv6w155qql11066.png

mxwawaawxm 发表于 2021-6-30 10:34

zjtwxws 发表于 2021-6-27 19:19
编译有错,请问有人遇到问题了吗?

gcc编译没问题
gcc -Wall "text.c" -finput-charset=UTF-8 -fexec-charset=GBK -o "1.exe"

zouyingsheng 发表于 2021-7-3 10:36

        srand( time(0) );//为生成随机数种种子,可以产生不同的随机数
用这个他不香吗,搞那复杂干嘛
页: [1] 2
查看完整版本: c语言生成随机数