初學者常遇到「rand() 每次運行結果相同」的困惑。本文揭示偽隨機數本質,講解種子機制,演示正確使用 srand(time(NULL)) 初始化種子的完整代碼模式,並說明線程安全與高質量隨機數的進階方案。
rand() 不隨機?rand() 產生的是偽隨機數列:由確定性演算法根據「種子」計算得出。若種子固定(默認種子常為 1),輸出序列完全固定。種子不同 → 序列不同。
#include
#include
void generate_random(int *arr, int n) {
srand((unsigned)time(NULL)); // 僅在程序啟動時調用一次!
for (int i = 0; i < n; ++i)
arr[i] = rand();
}
關鍵點:
time(NULL) 返回當前秒級時間戳,天然變化,適合作為種子來源。srand() 全程序只需調用一次,放在 main() 開頭最佳。重複調用反而降低隨機性(若在同一秒內多次調用)。#include
#include
#include
void print_array(const int *a, int n) {
for (int i = 0; i < n; ++i) {
printf("%10d", a[i]);
if ((i+1)%5 == 0) putchar('\n');
}
}
int main(void) {
int arr1[10], arr2[10];
// 錯誤示範:無 srand,每次輸出相同
for (int i=0;i<10;++i) arr1[i]=rand();
printf("未設種子(固定序列):\n");
print_array(arr1, 10);
// 正確示範:時間種子
srand((unsigned)time(NULL));
for (int i=0;i<10;++i) arr2[i]=rand();
printf("\n時間種子(每次不同):\n");
print_array(arr2, 10);
return 0;
}
| 誤區 | 後果 | 正確做法 |
|---|---|---|
循環中反覆 srand(time(NULL)) | 同一秒內種子相同,產生重複序列 | 程序啟動一次 srand |
多線程共用 rand() | 數據競爭,序列交錯不可預期 | 使用 rand_r() 或 C11 thread_local 種子 |
加密/安全場景用 rand() | 可預測,極不安全 | 使用 /dev/urandom、CryptGenRandom、getrandom()、OpenSSL RAND_bytes |
| 需高統計質量(蒙特卡洛等) | 週期短、相關性強 | 採用 Mersenne Twister (mt19937)、PCG、Xoshiro256** 等現代演算法 |
<random.h>(C23 引入)現代 C 標準趨向提供更高級的隨機數設施,但目前廣泛部署環境仍以 rand/srand 為主。跨平台項目建議封裝統一介面,底層按平台選擇最佳熵源。
掌握種子機制,避開常見坑點,即可在 C 語言中正確、高效地使用偽隨機數滿足大多數工程需求。