-1

So ive made a MAC Address generator. But the random part is very strange. It randomly generates a number that i use to choose something from an array. But each time you run the exe. It gens the same number. Here is my code

#include <random>
#include <string>
//Mac Addr example -> 82-F5-4D-72-C1-EA
//6 two char sets
//Dont include spaces/dashes/dots

std::string chars[] = { "A","B","C","D","E","F" };
int nums[] = { 0,1,2,3,4,5,6,7,8,9 };

std::string GenMacAddr()
{
    std::string final;
    std::string CharSet;
    int choice;
    for (int i = 0; i < 6; i++) {
        choice = 1 + rand() % 4;
        if (choice == 1) { //Char Set only int
            for (int x = 0; x < 2; x++) { //Makes action happen twice
                final += std::to_string(nums[rand()%10]);
            }
        }
        else if (choice == 2) { //Char set only str
            for (int x = 0; x < 2; x++) { //Makes action happen twice
                final += chars[rand() % 6];
            }
        }
        else if (choice == 3) {
            final += chars[rand() % 6];
            final += std::to_string(nums[rand() % 10]);
        }
        else if (choice == 4) {
            final += std::to_string(nums[rand() % 10]);
            final += chars[rand() % 6] ;
        }
    }
    
    return final;
}
  • 2
    You may get your answer [here](https://stackoverflow.com/questions/21273550/how-does-srand-relate-to-rand-function) – Damien Mar 05 '21 at 14:01
  • 2
    `rand()` isnt really random. It is a pseudo random generator and to get a different sequence of numbers you need to use a different seed. Do you call `srand()` somewhere? – 463035818_is_not_an_ai Mar 05 '21 at 14:02
  • https://en.cppreference.com/w/cpp/numeric/random/rand – 463035818_is_not_an_ai Mar 05 '21 at 14:03
  • In modern C++, you use . Example: https://gist.github.com/Bktero/70cbcece6f001cb63814b8db49326ad6 – Bktero Mar 05 '21 at 14:04
  • 1
    `#include ` and `rand()` have nothing to do with each other. `rand()` is from `cstdlib` header. – n. m. could be an AI Mar 05 '21 at 14:09
  • 2
    @Bktero That function is however not what I would recommend. Using `random_device` may be very slow since it's supposed to pick numbers from an entropy pool which may get depleated if you use it too much. You usually use `random_device` to seed a fast pseudo random number generator instead. – Ted Lyngmo Mar 05 '21 at 14:11
  • You need to call srand() one time in your `int main()` before using `rand()`. And I mean 1 time. Some users make the mistake of calling it every time then ask why all their "random" numbers are the same. – drescherjm Mar 05 '21 at 14:25
  • 1
    Btw I don't know if that's intentional, but your algorithm could be [way shorter](https://godbolt.org/z/nc4ce1). – m88 Mar 05 '21 at 14:40
  • 1
    @TedLyngmo thanks for this information, I am learning something! I have updated my gist. – Bktero Mar 08 '21 at 11:16

2 Answers2

5

rand() is a deterministic random number generator . In order to achieve actual pseudo-random results you should first seed it with something like srand(time(NULL)) .

If you look around this you will realize that this is a bad approach and you should instead give up rand() altogether , instead use <random> from C++11 . Stephan T. Lavavej has a really nice talk about it , you should see it here .

Here is also the code snippet he recommends from that talk .

#include <random>
#include <iostream>

int main() {
    std::random_device random_dev; // (Non?) deterministic random number generator
    std::mt19937 mers_t(random_dev()); // Seed mersenne twister with it .
    std::uniform_int_distribution<int> distribution(0, 100); // Bound the output.

    // Print a random integer in the range [0,100] ( included ) .
    std::cout << distribution(mers_t) << '\n';
}

EDIT: As François noted, std::random_device isn't required to be non-deterministic and it's actually implementation dependent. One indication to tell if it is or not is by checking the value of entropy() method call but then again some implementations return just a fixed value. In that case you might consider using std::chrono to generate a seed the way Ted describes.

fvalasiad
  • 173
  • 1
  • 10
3

rand() is a pseudo random number generator. It will generate numbers according to an algorithm designed to have a long period (before it starts repeating itself) - but it needs a starting point. This is called the seed. You seed rand() with the srand() function and you should only seed it once during the program's execution. Seeding is often done with time but since time commonly returns whole seconds (since the epoch) you risk using the same seed if you start the program more than once (within a second).

You could instead use std::random_device to generate the seed if it has entropy and use a time based seed only as a fallback.

Example:

#include <cstdlib>
#include <chrono>
#include <iostream>
#include <random>
#include <string>
#include <type_traits>

unsigned seed() { // a function to generate a seed
    std::random_device rd;
    if(rd.entropy() > 0.) return rd(); // if random_device has entropy, use it

    // fallback, use duration since the epoch
    auto dse = (std::chrono::steady_clock::now() -
                std::chrono::steady_clock::time_point{}).count();

    return static_cast<std::make_unsigned_t<decltype(dse)>>(dse);
}

std::string GenMacAddr() {
    static const char chars[] = {'0','1','2','3','4','5','6','7',
                                 '8','9','A','B','C','D','E','F'};

    std::string result(6 * 2, ' ');

    for(char& ch : result) ch = chars[std::rand() % std::size(chars)];
    
    return result;
}

int main() {
    std::srand(seed());   // seed rand()

    // generate 10 mac addresses
    for(int i = 0; i < 10; ++i) std::cout << GenMacAddr() << '\n';
}

That said, you could use one of the more modern pseudo random number generators, like std::mt19937, instead of rand() and use std::uniform_int_distribution instead of the modulus operation:

template<class PRNG = std::mt19937>
auto& prng() {
    // same seed() function as in the previous example:
    thread_local PRNG prng_instance(seed());
    return prng_instance;
}

std::string GenMacAddr() {
    static const char chars[] = {'0','1','2','3','4','5','6','7',
                                 '8','9','A','B','C','D','E','F'};
    thread_local std::uniform_int_distribution<unsigned> dist(0, std::size(chars) - 1);

    std::string result(6 * 2, ' ');

    for(char& ch : result) ch = chars[dist(prng())];
    
    return result;
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108