如何在C中生成非重复数字?
How to generate non-repeating numbers in C?
我的第一个 post 在这里。
我正在尝试用 C 编写一个程序,它生成一个由数字、字母和大写字母组成的随机密码。问题是密码中的字符不能重复。我尝试了几种方法来防止这种情况发生,但似乎没有任何效果。
void createPassword() {
char password[LENGTH];
char nums[] = "0123456789";
char letters[] = "abcdefghijklmnopqrstuvwxyz";
char caps[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int selector = rand() % 3; //random choice of character type
int i;
printf("Vytvorene heslo: ");
for(i = 0;i < LENGTH;i++) {
if(selector == 1) { //if selector == 1, add number to password etc.
password[i] = nums[rand() % 10];
printf("%c", password[i]);
selector = rand() % 3;
}
else if(selector == 2) {
password[i] = letters[rand() % 26];
printf("%c", password[i]);
selector = rand() % 3;
}
else {
password[i] = caps[rand() % 26];
printf("%c", password[i]);
selector = rand() % 3;
}
}}
如果有人能告诉我下一步该怎么做,我会很高兴。
这没什么大不了的,随机种子在 C 中的几次运行中都是相似的。
您可能需要通过添加如下内容将随机种子设置为 time(0)
,首先是您的代码:
srand(time(0));
你也应该导入 time.h
。
#include <time.h>
此外,如果您想同时创建一个由数字和字母组成的密码,您可能需要将 selector
赋值移动到循环中。
选择数组的随机索引与顺序选择随机排列的数组的值相同。我使用 Fisher–Yates shuffle Algorithm 对数组进行洗牌。生成混排后的数组后,只需从混排后的数组中取出下一个字符的索引,并使用 symbols[]
从中访问相应的字符。还。我使用 srand(time(0))
为随机数生成器提供随机种子。包括 time.h
以使用 time(0)
.
void createPassword() {
char password[LENGTH];
int total = 10+26+26;
char symbols[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
int i;
int ar[total];
for(i = 0; i < total; i++){
ar[i] = i;
}
srand(time(0));
for (i = total-1; i >= 1; i--){
// get random 0 <= temp <= i
int temp = rand() % (i+1);
// Swap ar[temp] and ar[i]
int temp2 = ar[i];
ar[i] = ar[temp];
ar[temp] = temp2;
}
printf("Vytvorene heslo: ");
for(i = 0;i < LENGTH;i++) {
password[i] = symbols[ar[i]];
printf("%c", password[i]);
}
}
可以通过使用元素数组来实现没有重复字母的强制随机数的简单方法,这将起到卡片组的作用。
每次你得到一张牌,你从牌组的其余部分得到它(有一个点可以区分已经抽取的牌和仍然要输出的牌)你select随机0 到 n-1 之间的数字,其中 n-1 是一副牌中剩余的牌数。提取后,将提取的卡与仍要提取的组中的第一张交换,并将点推进到它后面的位置,因此它已经提取并且不会再次被select编辑。
下面显示了一个示例实现,在函数 extract
中,它使用 cell
的数组来存储要打印的可用对象(它们可以是任何东西,它们是 char
在给定的实现中能够产生你想要的---具有非重复字符的随机字符串):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
typedef char cell;
/* cell is a type (the above definition allows to be generic)
* array is the array of cards still to be output, n is its size.
* which is the card we select from the array, so it must be in
* range 0..n-1. */
cell extract(cell *array, size_t n, int which)
{
if (which) {
/* exchange position n with position 0 */
cell temp = array[0];
array[0] = array[which];
array[which] = temp;
}
return array[0];
}
/* this is a simple main program to illustrate how to use the
* function above. */
int main(int argc, char **argv)
{
unsigned N = 10;
unsigned seed = 0;
/* we use an array, because we need to modify it. */
char alpha[1024] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int opt;
int show_seed = 0;
while ((opt = getopt(argc, argv, "n:s:a:S")) != EOF) {
switch (opt) {
case 'n': N = atoi(optarg); break;
case 's': seed = atoi(optarg); break;
case 'S': show_seed = 1; break;
case 'a': strncpy(alpha, optarg, sizeof alpha); break;
}
}
if (seed) srand(seed);
else {
sranddev();
srand(seed = (unsigned)rand());
if (show_seed) {
fprintf(stderr,
"seed = %u\n",
seed);
}
}
argc -= optind;
argv += optind;
int len;
cell *pos;
for (pos = alpha, len = strlen(alpha);
*pos && len && N--;
pos++, len--)
{
putchar(extract(pos, len, rand() % len));
}
puts(""); /* final \n */
}
程序的用法是:
deck [ -a string ][ -S ][ -s seed ][ -n N ]
where:
-a allows you to specify the string where characters will be taken from. Defaults to ABCDEF...XYZ
-S prints the seed used in the run, so you can specify it to initialize the random number generator.
-s specifies a seed from a previous run to generate the same sequence. Defaults to a random initialization based on sranddev() (FreeBSD)
-n specifies the number of characters to select from the string. Defaults to 10.
样本运行是:
$ deck -s 123456
UKWOACYZLI
$ deck -s 123456 -n 26
UKWOACYZLITPJHQESVGMRBXFDN
$ _
如您所见,没有重复字符。
我的第一个 post 在这里。
我正在尝试用 C 编写一个程序,它生成一个由数字、字母和大写字母组成的随机密码。问题是密码中的字符不能重复。我尝试了几种方法来防止这种情况发生,但似乎没有任何效果。
void createPassword() {
char password[LENGTH];
char nums[] = "0123456789";
char letters[] = "abcdefghijklmnopqrstuvwxyz";
char caps[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int selector = rand() % 3; //random choice of character type
int i;
printf("Vytvorene heslo: ");
for(i = 0;i < LENGTH;i++) {
if(selector == 1) { //if selector == 1, add number to password etc.
password[i] = nums[rand() % 10];
printf("%c", password[i]);
selector = rand() % 3;
}
else if(selector == 2) {
password[i] = letters[rand() % 26];
printf("%c", password[i]);
selector = rand() % 3;
}
else {
password[i] = caps[rand() % 26];
printf("%c", password[i]);
selector = rand() % 3;
}
}}
如果有人能告诉我下一步该怎么做,我会很高兴。
这没什么大不了的,随机种子在 C 中的几次运行中都是相似的。
您可能需要通过添加如下内容将随机种子设置为 time(0)
,首先是您的代码:
srand(time(0));
你也应该导入 time.h
。
#include <time.h>
此外,如果您想同时创建一个由数字和字母组成的密码,您可能需要将 selector
赋值移动到循环中。
选择数组的随机索引与顺序选择随机排列的数组的值相同。我使用 Fisher–Yates shuffle Algorithm 对数组进行洗牌。生成混排后的数组后,只需从混排后的数组中取出下一个字符的索引,并使用 symbols[]
从中访问相应的字符。还。我使用 srand(time(0))
为随机数生成器提供随机种子。包括 time.h
以使用 time(0)
.
void createPassword() {
char password[LENGTH];
int total = 10+26+26;
char symbols[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
int i;
int ar[total];
for(i = 0; i < total; i++){
ar[i] = i;
}
srand(time(0));
for (i = total-1; i >= 1; i--){
// get random 0 <= temp <= i
int temp = rand() % (i+1);
// Swap ar[temp] and ar[i]
int temp2 = ar[i];
ar[i] = ar[temp];
ar[temp] = temp2;
}
printf("Vytvorene heslo: ");
for(i = 0;i < LENGTH;i++) {
password[i] = symbols[ar[i]];
printf("%c", password[i]);
}
}
可以通过使用元素数组来实现没有重复字母的强制随机数的简单方法,这将起到卡片组的作用。
每次你得到一张牌,你从牌组的其余部分得到它(有一个点可以区分已经抽取的牌和仍然要输出的牌)你select随机0 到 n-1 之间的数字,其中 n-1 是一副牌中剩余的牌数。提取后,将提取的卡与仍要提取的组中的第一张交换,并将点推进到它后面的位置,因此它已经提取并且不会再次被select编辑。
下面显示了一个示例实现,在函数 extract
中,它使用 cell
的数组来存储要打印的可用对象(它们可以是任何东西,它们是 char
在给定的实现中能够产生你想要的---具有非重复字符的随机字符串):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
typedef char cell;
/* cell is a type (the above definition allows to be generic)
* array is the array of cards still to be output, n is its size.
* which is the card we select from the array, so it must be in
* range 0..n-1. */
cell extract(cell *array, size_t n, int which)
{
if (which) {
/* exchange position n with position 0 */
cell temp = array[0];
array[0] = array[which];
array[which] = temp;
}
return array[0];
}
/* this is a simple main program to illustrate how to use the
* function above. */
int main(int argc, char **argv)
{
unsigned N = 10;
unsigned seed = 0;
/* we use an array, because we need to modify it. */
char alpha[1024] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int opt;
int show_seed = 0;
while ((opt = getopt(argc, argv, "n:s:a:S")) != EOF) {
switch (opt) {
case 'n': N = atoi(optarg); break;
case 's': seed = atoi(optarg); break;
case 'S': show_seed = 1; break;
case 'a': strncpy(alpha, optarg, sizeof alpha); break;
}
}
if (seed) srand(seed);
else {
sranddev();
srand(seed = (unsigned)rand());
if (show_seed) {
fprintf(stderr,
"seed = %u\n",
seed);
}
}
argc -= optind;
argv += optind;
int len;
cell *pos;
for (pos = alpha, len = strlen(alpha);
*pos && len && N--;
pos++, len--)
{
putchar(extract(pos, len, rand() % len));
}
puts(""); /* final \n */
}
程序的用法是:
deck [ -a string ][ -S ][ -s seed ][ -n N ]
where:
-a allows you to specify the string where characters will be taken from. Defaults to ABCDEF...XYZ
-S prints the seed used in the run, so you can specify it to initialize the random number generator.
-s specifies a seed from a previous run to generate the same sequence. Defaults to a random initialization based on sranddev() (FreeBSD)
-n specifies the number of characters to select from the string. Defaults to 10.
样本运行是:
$ deck -s 123456
UKWOACYZLI
$ deck -s 123456 -n 26
UKWOACYZLITPJHQESVGMRBXFDN
$ _
如您所见,没有重复字符。