2

I wrote this to generate a random password:

#include <iostream> #include <fstream> #include <string> #include <cstdlib> using namespace std; string read(string value) { //read value ifstream input; int olength; string line = "", output = ""; size_t pos; bool a = true; int i = 0; input.open("pg_options.txt"); if (!input.is_open()) { cout << "pg_options.txt missing."; return "error"; } while (getline(input, line)) { pos = line.find(value); if (pos != string::npos) { while (a == true) { if (line[i] == '=') { i++; break; } else { i++; } } olength = line.length() - value.length() - 1; for (int i2 = 0; i2 < olength; i2++) { output += line[i]; i++; } } } input.close(); return output; } char randupper() { //generate random upper case character char uppercase[26] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; int i = rand() % 26; return uppercase[i]; } char randlower() { //generate random lower case character char lowercase[26] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; int i = rand() % 26; return lowercase[i]; } char randspecial() { //generate random special character char special[7] = { '!', '#', '$', '%', '&', '*', '?' }; int i = rand() % 7; return special[i]; } char randnumbers() { //generate random number char numbers[10] = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' }; int i = rand() % 10; return numbers[i]; } void generate() { //generate the password string output = ""; int i1=0, digits = 0, upper = 0, lower = 0, special = 0, numbers = 0; digits = stoi(read("digits")); //get digits if (read("include_upper_case") == "true") { //determine number of upper case characters upper = rand() % (digits / 2) + 1; digits -= upper; } if (read("include_lower_case") == "true") { lower = rand() % (digits / 2) + 1; digits -= lower; } if (read("include_special_characters") == "true") { special = rand() % (digits / 2) + 1; digits -= special; } if (read("include_numbers") == "true") { numbers = digits; } else { //if numbers not included if (read("include_upper_case") == "true") { upper += digits; } else if (read("include_lower_case") == "true") { lower += digits; } else if (read("include_special_characters") == "true") { special += digits; } else { cout << "error generating, please check your options."; return; } } for (int i = 0; i < stoi(read("digits")); i++) { i1 = rand() % 4; if (i1 == 0) { //if uppercase if (upper > 0) { output += randupper(); upper--; } else { i--; } } else if (i1 == 1) { if (lower > 0) { output += randlower(); lower--; } else { i--; } } else if (i1 == 2) { if (special > 0) { output += randspecial(); special--; } else { i--; } } else if (i1 == 3) { if (numbers > 0) { output += randnumbers(); numbers--; } else { i--; } } } cout << output; } int main() { generate(); return 0; } 

pg_options.txt:

include_special_characters=true include_upper_case=true include_lower_case=true include_numbers=true digits=10 

However, it generates the same thing every time it runs, that is HM*nfx375g, so it has same sequence of random numbers. (in generate(), upper is always 2, lower is always 4, special is always 1, numbers is always 3...) Is there a function that can generate different random numbers every time?

2
  • This doesn't address the question, but get in the habit of initializing objects with meaningful values rather than default-initializing them and immediately overwriting the default value. In this case, that means changing ifstream input; ... input.open("pg_options.txt"); to ifstream input("pg_options.txt");. Also, your don't have to call input.close();. The destructor will do that. Commented Sep 4, 2021 at 14:42
  • The main power in the C++ community with interest in pseudo-random numbers is the Monte-Carlo physics simulation people, and they require reproducibility unless the opposite is explicitly requested. But in your case, typically you'd seed the random number generator with the output of an high-resolution clock, like explained here: SO-q34490599. Commented Sep 4, 2021 at 14:48

2 Answers 2

10

Random generators need to be seeded to have a random starting point. In your case, it needs to be done by calling srand() before using rand(), for example:

#include <cstdlib> #include <ctime> using namespace std; int main() { srand(time(0)); // <-- add this! generate(); return 0; } 

However, the preferred C++ way of generating random numbers is to use the functions and types available in the <random> header file. srand() and rand() are basically a leftover from C.

See this example:

#include <iostream> #include <vector> #include <string> #include <random> // get 'entropy' from device that generates random numbers itself // to seed a mersenne twister (pseudo) random generator static std::mt19937 generator(std::random_device{}()); char random_lowercase_char() { static std::uniform_int_distribution<std::size_t> distribution('a', 'z'); return static_cast<char>(distribution(generator)); } char random_uppercase_char() { static std::uniform_int_distribution<std::size_t> distribution('A', 'Z'); return static_cast<char>(distribution(generator)); } char random_number_char() { static std::uniform_int_distribution<std::size_t> distribution('0', '9'); return static_cast<char>(distribution(generator)); } char random_special_char() { static std::vector<char> specials{ '!', '#', '$', '%', '&', '*', '?' }; static std::uniform_int_distribution<std::size_t> distribution(0, specials.size()-1); auto index = (distribution(generator)); return specials[index]; } int main() { for (int i = 0; i < 40; i++) { std::cout << random_lowercase_char(); std::cout << random_uppercase_char(); std::cout << random_number_char(); std::cout << random_special_char(); std::cout << std::endl; } } 
Sign up to request clarification or add additional context in comments.

7 Comments

While this is a good solution, you did not explain why the OP's original code was not working to begin with. You should explain the problem before offering a fix, so the OP can learn from their mistake.
@RemyLebeau Fair enough :) I should have pointed out that random generators need to be seeded to be truly random ;) In this case it is done by std::random_device(), or in his case should have been calling srand.
@RemyLebeau I'm happy with that :) thanks
The first two random_xxxx_char functions are misnamed. They are not guaranteed to produce only letters. There is at least one character encoding in which the uppercase letters are not contiguous and the lowercase letters are not contiguous. The code in the question handles that correctly.
@PeteBecker Interesting, never knew that. :) Even all the constexpr I've seen over the years happily use [a-z], [A-Z]. Should be an easy fix though.
|
3

First add the <ctime> library

Then use srand(time(NULL)); before generating any random numbers with rand().

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.