0
votes

I am trying to create a random password generator. When I call the function multiple times it returns the same character value. QQpQ;7Q7pQ;p

I have tried adding srand(time(0)); or srand((unsigned int) time(NULL)); in my main function.

Looking at other stack over flow posts I see that srand helps create different characters each time I run the program. However it still returns multiples of the same character.

How can I change srand() seed during run time to get different random numbers?

#include <string>
#include <iostream>
#include <time.h>

using namespace std;

string randomGenerator(int numberOfCharacters);
char randomCapitalCharacter();
char randomLowerCharacter();
char randomSpecialCharacter();
char randomInt();

int main(){
    srand((unsigned int) time(NULL));
    int passwordLength = 12;
    string password = randomGenerator(passwordLength);
    cout << password << endl;
    return 0;
}

string randomGenerator(int numberOfCharacters){
    char randomCharacterTypes[4] = {randomLowerCharacter(),randomInt(), randomCapitalCharacter(), randomSpecialCharacter()};
    std::string password;

    while (numberOfCharacters > 0){
        int random = rand()%4;
        password += randomCharacterTypes[random];
        numberOfCharacters--;
    }
    return password;
}
char randomInt(){
    std::string numberAsString = to_string(std::rand()% 10);
    char randomNumberChar = numberAsString.at(0);
    return randomNumberChar;
}
char randomLowerCharacter(){
    return 97 + rand()%26; //97 = a
}
char randomCapitalCharacter(){
    return 65 + rand()%26; //65 = A
}
char randomSpecialCharacter(){
    /** Special characters are split by numbers so we pick a random from one of the 2 groups.*/
    return (rand()%2) ? char(33 + rand()%14) : char(58 + rand()%8); 
}
2
randomCharacterTypes[4] only contains 4 different characters, did you mean to create an array of function pointers?Alan Birtles
When I run your code, the first time it prints RReR>>eReR6e and the second time it prints g>g>7gTgg>>T Is it because you are running it more than once in the same second? That would give the same values because time(NULL) returns an integer number seconds - so if you run it more than once in the same second time(NULL) would return the same value.Jerry Jeremiah
Since you are using c++11, you should stop using srand in favour of the new random number generators: stackoverflow.com/a/66850447/1294207Fantastic Mr Fox
@AlanBirtles Oh I see yes I am trying to use function pointers. I see that if I just call the randomLowerCharacter(); that it does return a random character value. I will look up how to implement function pointers. Thank you!!!mfischercodes
You can avoid the need for comments like //97 = a if you write 'a' instead of 97 in the code (and similar for other characters)..molbdnilo

2 Answers

2
votes

randomCharacterTypes is an array of 4 characters, for each character class you'll always get the same character. If you want to generate a new character each time you could use function pointers instead:

string randomGenerator(int numberOfCharacters){
    char (*randomCharacterTypes[])() = {randomLowerCharacter,randomInt, randomCapitalCharacter, randomSpecialCharacter};
    std::string password;

    while (numberOfCharacters > 0){
        int random = rand()%4;
        password += randomCharacterTypes[random]();
        numberOfCharacters--;
    }
    return password;
}

randomInt can be simplified to return a character between '0' and '9' the same as your other functions:

char randomInt(){
    return '0' + rand() % 10;
}

Your other functions are more readable if you use character rather than numbers which you then have to add a comment to remind you which character they represent:

char randomLowerCharacter(){
    return 'a' + rand()%26;
}
char randomCapitalCharacter(){
    return 'A' + rand()%26;
}
char randomSpecialCharacter(){
    /** Special characters are split by numbers so we pick a random from one of the 2 groups.*/
    return (rand()%2) ? char('!' + rand()%14) : char(':' + rand()%8); 
}

note that rand() % x is not a good random number generator and you should use the standard library random functions instead (especially if you are using these passwords for anything important).

Your code could possibly be further simplified using strings to contain your character classes:

#include <string>
#include <string_view>
#include <iostream>
#include <random>
#include <array>

class PasswordGenerator
{
public:
    PasswordGenerator()
    {
        for (size_t i = 0; i < characterTypes.size(); i++)
        {
            characterTypeDistributions[i] = std::uniform_int_distribution<int>(0, characterTypes[i].size() - 1);
        }
    }

    static constexpr std::array<std::string_view, 4> characterTypes = {
            "abcdefghijklmnopqrstuvwxyz",
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
            "0123456789",
            "!\"#$%&'()*+,-./:;<=>?@"
        };
    std::array<std::uniform_int_distribution<int>, characterTypes.size()> characterTypeDistributions;
    std::uniform_int_distribution<int> typeDistribution{0, characterTypes.size() - 1};
    std::mt19937 eng{std::random_device{}()};

    std::string generate(int numberOfCharacters){
        std::uniform_int_distribution<int> dist{0, 5};
        std::string password;
        password.reserve(numberOfCharacters);
        for (int i = 0; i < numberOfCharacters; i++)
        {
            auto type = typeDistribution(eng);
            password += characterTypes[type][characterTypeDistributions[type](eng)];
        }
        return password;
    }
};

int main(){
    int passwordLength = 12;
    PasswordGenerator gen;
    std::string password = gen.generate(passwordLength);
    std::cout << password << "\n";
    return 0;
}

Note that this code may still not meet high security standards for generating passwords.

2
votes

Thank you to @RetiredNinja for pointing out that the problem wasn't with srand() but rather with the improper calling of functions in my array. Using a switch statement to call the functions properly fixed the issue.

//improper calling of functions in an array. Resolved with switch statement below
//char randomCharacterTypes[4] = {randomLowerCharacter(),randomInt(), randomCapitalCharacter(), randomSpecialCharacter()};

while (numberOfCharacters > 0){
    int random = rand()%4;
    switch(random){
    case 0:
        password += randomLowerCharacter();
        break;
    case 1:
        password += randomInt();
        break;
    case 2:
        password += randomCapitalCharacter();
        break;
    case 3:
        password += randomSpecialCharacter();
        break;
    }
    numberOfCharacters--;
}