如何在C语言中实现不重复随机数生成函数?VS2022报错C2057求解
在C语言中生成不重复随机数的实现方案
先解决你遇到的C2057错误
Visual Studio 2022的C编译器默认不支持C99标准的变长数组(VLA),所以int usedNumbers[numPeople]这种以变量作为数组长度的写法会触发编译错误。替代方案是用动态内存分配:
#include <stdlib.h> // 动态分配数组 int *usedNumbers = (int*)malloc(numPeople * sizeof(int)); if (usedNumbers == NULL) { // 处理内存分配失败,比如直接退出程序 exit(EXIT_FAILURE); } // 使用完后必须释放内存 free(usedNumbers);
生成不重复随机数的两种可行实现
方法1:标记法(适合小范围随机数场景)
原理是用数组记录已生成的数字,每次生成新随机数后检查是否重复,不重复则保留。
#include <stdio.h> #include <stdlib.h> #include <time.h> // 生成count个[min, max]范围内的不重复随机数,返回动态数组(需手动释放) int* generateUniqueRandoms(int count, int min, int max) { if (count > (max - min + 1)) { printf("错误:请求的随机数数量超过范围上限\n"); return NULL; } int *result = (int*)malloc(count * sizeof(int)); int *used = (int*)malloc((max - min + 1) * sizeof(int)); if (result == NULL || used == NULL) { free(result); free(used); return NULL; } // 初始化标记数组为0(表示未使用) for (int i = 0; i < max - min + 1; i++) { used[i] = 0; } srand((unsigned int)time(NULL)); // 初始化随机数种子 int index = 0; while (index < count) { int num = rand() % (max - min + 1) + min; if (!used[num - min]) { used[num - min] = 1; result[index++] = num; } } free(used); return result; } // 使用示例 int main() { int *nums = generateUniqueRandoms(5, 1, 10); if (nums != NULL) { for (int i = 0; i < 5; i++) { printf("%d ", nums[i]); } free(nums); } return 0; }
方法2:Fisher-Yates洗牌算法(高效,适合大范围或接近范围上限的场景)
原理是先创建包含所有可能数字的数组,打乱顺序后取前count个元素,避免重复检查的开销。
#include <stdio.h> #include <stdlib.h> #include <time.h> // 生成count个[min, max]范围内的不重复随机数,返回动态数组(需手动释放) int* generateUniqueRandoms(int count, int min, int max) { int range = max - min + 1; if (count > range) { printf("错误:请求的随机数数量超过范围上限\n"); return NULL; } // 创建包含所有可能数字的数组 int *pool = (int*)malloc(range * sizeof(int)); int *result = (int*)malloc(count * sizeof(int)); if (pool == NULL || result == NULL) { free(pool); free(result); return NULL; } for (int i = 0; i < range; i++) { pool[i] = min + i; } srand((unsigned int)time(NULL)); // 洗牌:从后往前交换元素 for (int i = range - 1; i >= range - count; i--) { int j = rand() % (i + 1); // 交换pool[i]和pool[j] int temp = pool[i]; pool[i] = pool[j]; pool[j] = temp; // 把选中的数存入结果数组 result[range - 1 - i] = pool[i]; } free(pool); return result; } // 使用示例 int main() { int *nums = generateUniqueRandoms(5, 1, 10); if (nums != NULL) { for (int i = 0; i < 5; i++) { printf("%d ", nums[i]); } free(nums); } return 0; }
注意事项
- 每次程序运行只需调用一次
srand((unsigned int)time(NULL)),不要在循环内重复调用,否则会导致随机数重复。 - 动态分配的内存必须用
free释放,避免内存泄漏。 - 若生成的随机数数量远小于范围,标记法更省内存;若数量接近范围上限,洗牌算法效率更高。
内容的提问来源于stack exchange,提问作者drru.zip
相关产品推荐
相关产品推荐

