这是另一个解决方案,仍然受RAND_MAX 的限制,不需要读取每一行直到所选行。这个想法是使用一个二进制文件,将每个单词存储在相同的字节数中,因此可以使用fseek() 和fread() 访问任何单词。文件中的第一个条目是一个long 值,用于存储文件中的字数。添加单词时,此值会更新。
这是一个查找名为wordlist.txt 的普通文本文件的实现,该文件每行有一个单词。如果找到,程序会更新(或创建,如有必要)名为wordlist.fmt 的文件。更新函数从文本文件中读取每个单词,跳过空行,并将其以固定字节数存储在二进制文件中。读完所有单词后,更新字数。使用文本文件运行程序一次后,您应该删除文本文件,否则下一次运行将再次添加单词。 .fmt 文件应该保留,如果你想添加更多的话,只需在包含可执行文件的目录中放置一个新的文本文件,然后再次运行。
打印五个随机词的循环生成一个随机数,使用该数字移动到包含一个词的文件位置,将该词读入一个数组,然后打印它。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define RAW_WORDS "wordlist.txt"
#define FMT_WORDS "wordlist.fmt"
#define OFFSET_SZ (sizeof(long))
#define MAXWORD 30
void update_words(FILE *fp_fmt, FILE *fp_raw);
void strip(char *str);
int main(void)
{
FILE *raw_words, *formatted_words;
char word[MAXWORD];
long wordcount;
int i;
int wpos;
raw_words = fopen(RAW_WORDS, "r");
/* Try to open existing file for update, otherwise open new file */
if ((formatted_words = fopen(FMT_WORDS, "r+b")) == NULL){
if ((formatted_words = fopen(FMT_WORDS, "w+b")) == NULL) {
fprintf(stderr, "Unable to open file %s\n", FMT_WORDS);
exit(EXIT_FAILURE);
} else { // initialize file wordcount
wordcount = 0L;
fwrite(&wordcount, OFFSET_SZ, 1, formatted_words);
fflush(formatted_words);
}
}
/* Update FMT_WORDS file if RAW_WORDS is present */
if (raw_words != NULL)
update_words(formatted_words, raw_words);
/* Get 5 random words and print them */
srand((unsigned)time(NULL));
rewind(formatted_words);
fread(&wordcount, OFFSET_SZ, 1, formatted_words);
printf("Five random words from %s:\n", FMT_WORDS);
for (i = 0; i < 5; i++) {
wpos = rand() % wordcount;
fseek(formatted_words, wpos * MAXWORD + OFFSET_SZ, SEEK_SET);
fread(word, MAXWORD, 1, formatted_words);
puts(word);
}
if (raw_words && (fclose(raw_words) != 0))
fprintf(stderr, "Unable to close file %s\n", RAW_WORDS);
if (fclose(formatted_words) != 0)
fprintf(stderr, "Unable to close file %s\n", FMT_WORDS);
return 0;
}
void update_words(FILE *fp_fmt, FILE *fp_raw)
{
char word[MAXWORD];
long wordcount;
/* Read in wordcount and move to end of file */
rewind(fp_fmt);
fread(&wordcount, OFFSET_SZ, 1, fp_fmt);
fseek(fp_fmt, wordcount * MAXWORD, SEEK_CUR);
/* Write formatted words, skipping blank lines */
while (fgets(word, MAXWORD, fp_raw) != NULL) {
if (word[0] != '\n') {
strip(word);
if (fwrite(word, MAXWORD, 1, fp_fmt) != 1) {
fprintf(stderr, "Error writing to %s\n", FMT_WORDS);
exit(EXIT_FAILURE);
}
++wordcount;
}
}
/* Update wordcount in file and flush output */
rewind(fp_fmt);
fwrite(&wordcount, OFFSET_SZ, 1, fp_fmt);
fflush(fp_fmt);
}
void strip(char *str)
{
while (*str != '\n' && *str != '\0')
str++;
*str = '\0';
}