FILE* inp;
inp = fopen("wordlist.txt","r"); //filename of your data file
char arr[100][5]; //max word length 5
int i = 0;
while(1){
char r = (char)fgetc(inp);
int k = 0;
while(r!=',' && !feof(inp)){ //read till , or EOF
arr[i][k ] = r; //store in array
r = (char)fgetc(inp);
}
arr[i][k]=0; //make last character of string null
if(feof(inp)){ //check again for EOF
break;
}
i ;
}
我正在讀取檔案單詞并將它們存盤在陣列中。我的問題是:如何隨機選擇其中 7 個單詞并將它們存盤在陣列中?
輸入檔案有以下內容:
https://ibb.co/LkSJ1SV
meal
cheek
lady
debt
lab
math
basis
beer
bird
thing
mall
exam
user
news
poet
scene
truth
tea
way
tooth
cell
oven
uj5u.com熱心網友回復:
首先,您的程式存在以下問題:
- 在您發布的輸入中,一些單詞有 5 個字符長,但您的陣列只有 4 個字符加上終止空字符的空間。
- 您發布的輸入中的單詞由換行符分隔,而不是逗號。因此,您搜索輸入流是沒有意義的
','。
在您的代碼中修復這兩個問題并添加一個函式main和所有必要的標頭后,它應該如下所示:
#include <stdio.h>
int main( void )
{
FILE* inp;
inp = fopen("wordlist.txt","r"); //filename of your data file
char arr[100][6]; //max word length 5
int i = 0;
while(1) {
char r = (char)fgetc(inp);
int k = 0;
while(r!='\n' && !feof(inp)) { //read till , or EOF
arr[i][k ] = r; //store in array
r = (char)fgetc(inp);
}
arr[i][k]=0; //make last character of string null
if(feof(inp)){ //check again for EOF
break;
}
i ;
}
}
在 C 中,通常使用該函式rand來生成 和 之間的隨機0數RAND_MAX。宏常數RAND_MAX保證至少為32767.
為了得到一個和之間的亂數0(i不包括i它自己),你可以使用下面的運算式,它使用了取模運算子:
rand() % i
這不會為您提供亂數的均勻分布,但對于大多數常見目的來說已經足夠了。
因此,為了選擇并列印一個隨機單詞,可以使用以下陳述句:
printf( "%s\n", rand() % i );
如果要選擇并列印 7 個隨機單詞,則可以回圈運行此陳述句 7 次。但是,可能會多次隨機選擇同一個單詞。如果您想防止這種情況發生,那么您將不得不使用更復雜的演算法,例如Fisher-Yates shuffle。
但是,這將在您每次運行程式時列印相同的隨機單詞序列。如果您希望亂數生成器在每次運行程式時生成不同的亂數序列,那么您必須通過呼叫srand帶有一些隨機資料的函式來為亂數生成器播種。
最簡單的隨機性來源是當前時間。該函式time將回傳一個表示當前時間的整數,通常以秒為單位。
srand( (unsigned)time(NULL) );
但是,由于該函式time通常使用秒,這意味著如果您在同一秒內運行程式兩次,亂數生成器將以相同的值作為種子,因此它將生成相同的亂數序列。如果這是一個問題,那么您可能希望找到其他一些隨機性來源。
完成上述所有操作并添加必要的標頭后,您的程式應如下所示:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main( void )
{
FILE* inp;
inp = fopen("wordlist.txt","r"); //filename of your data file
char arr[100][6]; //max word length 5
srand( (unsigned)time(NULL) );
int i = 0;
while(1) {
char r = (char)fgetc(inp);
int k = 0;
while(r!='\n' && !feof(inp)) { //read till , or EOF
arr[i][k ] = r; //store in array
r = (char)fgetc(inp);
}
arr[i][k]=0; //make last character of string null
if(feof(inp)){ //check again for EOF
break;
}
i ;
}
//print 7 random words
for ( int j = 0; j < 7; j )
printf( "%s\n", arr[rand()%i] );
}
對于輸入
meal
cheek
lady
debt
lab
math
basis
beer
bird
thing
mall
exam
user
news
poet
scene
truth
tea
way
tooth
cell
oven
該程式給了我以下(隨機)輸出:
user
mall
poet
lab
cheek
lab
beer
如您所見,其中一個隨機單詞是重復的。
如前所述,如果您想防止同一個單詞被選擇兩次,您可以使用Fisher-Yates shuffle對陣列進行洗牌。改組陣列后,您可以簡單地選擇并列印陣列的前 7 個元素,如果這是您要選擇的單詞數:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main( void )
{
FILE* inp;
inp = fopen("wordlist.txt","r"); //filename of your data file
char arr[100][6]; //max word length 5
srand( (unsigned)time(NULL) );
int i = 0;
while(1) {
char r = (char)fgetc(inp);
int k = 0;
while(r!='\n' && !feof(inp)) { //read till , or EOF
arr[i][k ] = r; //store in array
r = (char)fgetc(inp);
}
arr[i][k]=0; //make last character of string null
if(feof(inp)){ //check again for EOF
break;
}
i ;
}
//perform a Fisher-Yates shuffle on the array
for ( int j = 0; j < i - 1; j )
{
char temp[6];
int k = rand() % ( i - j ) j;
if ( j != k )
{
//swap both array elements
strcpy( temp, arr[j] );
strcpy( arr[j], arr[k] );
strcpy( arr[k], temp );
}
}
//print first 7 elements of the shuffled array
for ( int j = 0; j < 7; j )
{
//NOTE: This code assumes that i > 7, otherwise
//it may crash.
printf( "%s\n", arr[j] );
}
}
現在,同一個詞不能再被選擇兩次:
meal
thing
news
user
mall
exam
tea
在上面的程式中,我對整個陣列進行了洗牌。但是,如果我只需要隨機化前 7 個單詞,那么在改組時只執行 7 次外回圈迭代就足夠了。
uj5u.com熱心網友回復:
重要的
該解決方案具有weak random distribution單詞選擇,但考慮any length了從檔案輸入的總單詞。
理念
- 為了簡單起見,每個單詞的字符數最多為 256(包括 \0),因此對于小示例來說我們是安全的。
- 要使用的陣列最終將具有您要保存的總字數的大小。那是因為不需要存盤所有單詞然后選擇7個。您可以在讀取檔案時隨機覆寫以前的單詞來選擇7個單詞。
- 第一個 while 回圈將確保填充陣列,因此沒有空單元格。
- 第二個 while 回圈將隨機覆寫以前的單元格。
解決方案
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define TOTAL_WORDS 7
#define CHARS_PER_WORD 256
void readWord(FILE* inp, char [TOTAL_WORDS][CHARS_PER_WORD], int i);
int main(int argc, char const *argv[]) {
srand(time(NULL));
char arr[TOTAL_WORDS][CHARS_PER_WORD] = { 0 };
FILE* inp;
inp = fopen("wordlist.txt","r");
// make sure file opening did not fail
if( inp == NULL ) {
printf("Could not open file.\n");
return 0;
}
int i = 0;
while( i < TOTAL_WORDS && !feof(inp) )
readWord(inp,arr,i );
while( !feof(inp) ) {
if( (rand()% 2) == 1 )
readWord(inp,arr,rand() % TOTAL_WORDS);
else // consume the word without saving it
while( fgetc(inp)!='\n' && !feof(inp) ) { }
}
for( int i = 0; i<TOTAL_WORDS; i )
printf("%d: %s\n", i, arr[i]);
return 0;
}
void readWord(FILE* inp, char arr[TOTAL_WORDS][CHARS_PER_WORD], int i) {
int k = 0;
char r = (char) fgetc(inp);
while( r!='\n' && !feof(inp) ){
arr[i][k ] = r;
r = (char) fgetc(inp);
}
arr[i][k]='\0';
}
輸入檔案wordlist.txt包含:
meal
cheek
lady
debt
lab
math
basis
beer
bird
thing
mall
exam
user
news
poet
scene
truth
tea
way
tooth
cell
oven
結果之一是:
0: scene
1: truth
2: tooth
3: oven
4: way
5: user
6: cell
添加/更改說明
包含函式的C 庫,srand()將用于隨機化內容。time()rand()
#include <stdlib.h>
#include <time.h>
定義我們想在最后保留多少單詞。如果我們想從更改為其他內容,這將很有用7。每次我們想要參考我們想要保留多少個單詞時,7我們都會使用它,而不是到處使用。TOTAL_WORDS在同一個注釋中定義每個單詞有多少個字符。
#define TOTAL_WORDS 7
#define CHARS_PER_WORD 256
初始化函式 rand() 的種子。你可以在這里閱讀更多關于它的資訊。
srand(time(NULL));
獲取我們陣列大小范圍內的數字。您可以在此處閱讀有關 rand() 函式的更多資訊。
rand() % TOTAL_WORDS
對于avoid repeating兩個 while 回圈中的同一件事,你read a word from the file被封裝在一個函式中的部分。這使得主代碼更易于閱讀和維護。
void readWord(FILE* inp, char arr[TOTAL_WORDS][CHARS_PER_WORD], int i) {
...
}
列印保存的單詞。
for( int i = 0; i<TOTAL_WORDS; i )
printf("%d: %s\n", i, arr[i]);
uj5u.com熱心網友回復:
此解決方案是我最初解決方案的更好版本。
解決方案
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define INPUT_FILE "wordlist.txt"
#define TOTAL_WORDS 7
#define CHARS_PER_WORD 256
#define DELIMETER '\n'
FILE* input;
char word[CHARS_PER_WORD];
char words[TOTAL_WORDS][CHARS_PER_WORD];
void openFile();
void readWord();
void saveWord(int position);
void pickWords();
void printWords();
int hasWordAt(int position);
int isFull();
int main(int argc, char const *argv[]) {
srand(time(NULL));
openFile();
pickWords();
printWords();
return 0;
}
void printWords() {
for( int i = 0; i<TOTAL_WORDS; i )
printf("%d: %s\n", i, words[i]);
}
void pickWords() {
int pos;
while( !feof(input) && !isFull() ) {
readWord();
do {
pos = rand() % TOTAL_WORDS;
} while( hasWordAt(pos) );
saveWord(pos);
}
while( !feof(input) ) {
readWord();
if( (rand() % 2) == 0 )
continue;
pos = rand() % TOTAL_WORDS;
saveWord(pos);
}
}
int hasWordAt(int position) {
return words[position][0] != '\0';
}
int isFull() {
for( int i = 0; i<TOTAL_WORDS; i )
if( words[i][0] == '\0' )
return 0;
return 1;
}
void saveWord(int position) {
strcpy(words[position],word);
}
void readWord() {
int i = 0;
char ch = (char) fgetc(input);
while( ch != DELIMETER && !feof(input) ){
word[i ] = ch;
ch = (char) fgetc(input);
}
word[i]='\0';
}
void openFile() {
input = fopen(INPUT_FILE,"r");
if( input == NULL ) {
printf("Couldn't open file.");
exit(0);
}
}
改進
- 第一個詞的分布
- 代碼結構
目前我沒有時間編輯完整的解釋,雖然大部分都在我的初始答案中進行了解釋,但更好地解釋了這個答案。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/467402.html
標籤:C
上一篇:C動態結構陣列
下一篇:如何實作數字河流?
