【问题标题】:Append Random Text without Repetition for File (C)附加随机文本而不重复文件 (C)
【发布时间】:2015-10-27 07:14:24
【问题描述】:

我有 5 个名字列表

char *name[] = {"a","b","c","d","e"};

我有 3 个文件

char path1[PATH_MAX+1]
snprintf(path1, PATH_MAX+1, "%sfile1.txt",dirname);
FILES *filename1 = fopen(path1, "w")
.
.
.
char path3[PATH_MAX+1]
snprintf(path3, PATH_MAX+1, "%sfile3.txt",dirname);
FILES *filename3 = fopen(path3, "w")

我想要的是将 a,b,c,d,e(每个文件一个)随机附加到其中三个文件中而不重复。

我现在拥有的是(其中一个例子)

srand(time(NULL));
int one = rand()%5;
char path1[PATH_MAX+1];
snprintf(path1, PATH_MAX+1, "%sfile1.txt",dirname);
FILES *filename1 = fopen(path1, "w");
fputs(name[one],filename1);
fclose(filename1);

但是,有时我的 file1.txtfile3.txt 仍然可能包含 b (相同的字母来自名字)

问题

我是否遗漏了一些东西来确保所有随机结果始终是唯一的?

使用 6 行代码来创建一个文件并在其中附加一个随机名称是否也很有效?我只是想知道我是否必须创建 20 个文件,我会写 120 行基本几乎相同,只是数量不同(文件名1 到文件名3

谢谢。

【问题讨论】:

  • 1.为什么rand() % 10 而你只有 5 个“名字”? 2. 我在您的代码中完全看不到任何内容以确保防止重复。 3. 你不追加,你覆盖你的文件的内容。
  • @Jongware 1) 我已经将它编辑为 5。 2)我猜 srand(time(NULL)) 没有帮助,是吗?抱歉,我对 C 编程有点陌生。
  • srand() 正在初始化随机生成器,time(NULL) 返回当前系统时间。这有助于确保随机生成器不会始终生成相同的数字序列。

标签: c file random


【解决方案1】:

要获得独特的字符序列,您可以从递减池中抽取它们。例如,在您选择了a 之后,它将从池中删除。当然,池必须至少与您要打印的文件数一样大。

实现这种选择的一种简单方法是从池中选择一个字符,将池中的最后一个字符移动到所选择的字符所在的位置,然后将池大小减一。

如果您看到大量重复代码,特别是如果唯一的区别是变量名沿线 filename1filename2filename3 等应该敲响警钟,您应该使用数组:FILE *file[NFILE]。但请注意,您一次只能打开一定数量的文件。

在您的情况下,您想将单个字符写入文件。无需同时打开多个文件:打开一个文件,选择一个字符,将其写入文件,关闭 e 文件。然后处理下一个文件。

我认为下面的程序可以满足您的需求。

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#define NFILES 10

int main()
{
    char pool[] = "abcdefghij";     // Available chars as array
    int npool = sizeof(pool) - 1;   // Pool size minus terminating '\0'
    int i;

    if (npool < NFILES) {
        fprintf(stderr,
            "Not enough letters in pool for %d files.\n", NFILES);
        exit(1);
    }

    srand(time(NULL));

    for (i = 0; i < NFILES; i++) {
        int ipick = rand() % npool;    // position of pick
        char pick = pool[ipick];       // picked char

        char fname[20];
        FILE *f;

        pool[ipick] = pool[--npool];   // remove pick from pool

        snprintf(fname, sizeof(fname), "file-%03d.txt", i);

        f = fopen(fname, "w");
        if (f == NULL) {
            fprintf(stderr, "Could not create %s.\n", fname);
            exit(1);
        }

        fprintf(f, "%c\n", pick);
        fclose(f);
    }

    return 0;
}

【讨论】:

  • 与更改所有 var 相比,使用 for 循环更有意义。另外,我不认为我可以将位置移动到最后。我不再考虑删除它,因为我知道数组元素不能被删除。谢谢
  • 嗯,这个想法是把最后一个元素拿走,把它放在被挑选的项目所在的地方。数组sizeof(pool) 的大小是固定的,但有效大小npool 可以缩小。 (如果你将选取的元素与最后一个元素交换,你已经打乱了原始数组。)
  • 你可以。池数组中的数据可以是任何类型。当然你有const char *pick,你必须打印%s格式的字符串。你必须相应地计算npool
  • 我已经用我的代码调整了,但是为什么仍然有重复,而且有时文件包含像"connect:host@dfjlaskdfjasdf"这样的垃圾随机文件?
  • 不看代码很难回答。现在是学习调试代码的好时机。 npool 正确吗? ipick是一个合理的选择吗?上面的代码有效,但是当您的数组存储另一种数据类型的元素时需要调整。另外,请务必在编译时打开警告。
猜你喜欢
  • 2018-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-19
  • 1970-01-01
  • 1970-01-01
  • 2020-01-16
相关资源
最近更新 更多