Reputation: 5
my first post here.
I'm trying to write a program in C, which generates a random password made of numbers, letters and capitals. The problem is that characters in password must NOT be repeated. I tried a few ways to prevent that, but nothing seemed to work.
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;
}
}}
I'll be glad if someone could tell me what to do next.
Upvotes: 0
Views: 516
Reputation: 12668
An easy way to force random numbers with no repeating letters can be implemented by using an array of elements, that will play the role of a card deck.
Each time you get a card, you get it from the rest of the deck (there's a point that differentiates cards that have been already xtracted with cards that are still to be output) You select a random number between 0 to n-1 where n-1 is the number of cards left in the deck. Once extracted, you switch the card extracted with the first of the group that is still to be extracted, and advance the point one position behind it, so it becomes already extracted and is not selected again.
A sample implementation is shown below, in the function extract
, which uses an array of cell
s to store the available objects to print (they can be anything, they are char
in the given implementation to be able to produce what you want ---random strings with non repeating characters):
#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 */
}
The program's usage is:
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.
A sample run is:
$ deck -s 123456
UKWOACYZLI
$ deck -s 123456 -n 26
UKWOACYZLITPJHQESVGMRBXFDN
$ _
As you see no character is repeated.
Upvotes: 0
Reputation: 74
Picking a random index of an array is the same as picking the values of a shuffled array sequentially. I used Fisher–Yates shuffle Algorithm for shuffling of the array. After generating a shuffled array, just pick the index of the next character from the shuffled array, and use symbols[]
to access the corresponding character from it. Also. I used srand(time(0))
to give a random seed for the random number generator. Include time.h
for using 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]);
}
}
Upvotes: 1
Reputation: 309
That's not a big deal, random seeds are similar for several runs in C.
You may need to set the random seed to time(0)
by adding something like this, first of your code:
srand(time(0));
You should import time.h
too.
#include <time.h>
Besides if you want to make a password consisting numbers and alphabets at the same time you may need to move selector
assignment into the loop.
Upvotes: 0