Why do I get the same number when using rand/srand in a function before main?

Why am I getting a different random number each time I run my code in main, but when I run it in a function I am getting a static number?

(1) Random number in Main…

int main()
{
    srand(time(0));
    int loot = 1+(rand()%9);
    cout << loot;
    return 0;
}

(2) Random Number in a function outside of main…

using namespace std;

void lootTable(){
    srand(time(0));
    int loot = 1+(rand()%9);
    cout << loot;
}

int main()
{

    cout << lootTable;
    return 0;
}

Answer

Right off the bat, you should know what the line std::cout << lootTable; does in your original code. It is equivalent to std::cout << <address of lootTable function>;, which is a non-zero value, which gets converted to a bool, which then results in printing 1. When compiling, it is highly recommended to enable warnings, with at least -Wall -Wextra. You would have been warned about this issue right off the bat.

To call a function, you must always use the parameter list, (), even if it’s empty.

srand() should only be called once in a program. It seeds your PRNG (Pseudo Random Number Generator), and we only seed a PRNG once. Easiest way is at the beginning of main().

#include <cstdlib>
#include <ctime>
#include <iostream>

int lootTable() { return 1 + std::rand() % 9; }

int main() {
  std::srand(std::time(0));
  for (int i = 0; i < 10; ++i) {
    std::cout << lootTable() << ' ';
  }
  std::cout << 'n';
}

Output of two separate runs:

~/tmp 
❯ ./a.out 
5 5 3 8 1 2 1 9 8 8 

~/tmp 
❯ ./a.out 
6 5 5 7 8 7 5 6 8 4

Let’s look at looTable(). I have used the signature from your attempt at answering your own question. Let’s look at it piece by piece.

int lootTable()

This one’s pretty straightforward. The first part, int, means that the function returns an integer. So your function must have at least one return statement. Your initial version had a void return type, meaning the function wouldn’t return a value. That was likely not correct for your intended use.

Then, in your attempted answer, you got the return type fixed, but then failed to actually return anything, hence the downvotes.

The second part is the name, which you seem to have down, there were no issues calling the function.

The third part is the parameter list, which is empty in your case. Again, there doesn’t appear to be an issue here.


What you should be doing instead of using srand()/rand() is utilizing <random>. It’s randomness is less deterministic, and it separates the PRNG from the type of distribution that you want. The code below uses a std::uniform_int_distribution, which means every value has an equal chance of appearing. For a loot table, you might prefer a std::normal_distribution or std::lognormal_distribution or whatever floats your boat if you have different categories of loot.

Below is a short example program:

#include <iostream>
#include <random>

int lootTable() {
  static std::mt19937 prng(std::random_device{}());
  static std::uniform_int_distribution<int> values(1, 9);

  return values(prng);
}

int main() {
  for (int i = 0; i < 10; ++i) {
    std::cout << lootTable() << ' ';
  }
  std::cout << 'n';
}

Output of two separate runs:

~/tmp 
❯ ./a.out 
2 6 7 8 2 1 8 7 8 5 

~/tmp 
❯ ./a.out 
9 5 7 8 4 5 8 8 1 7

The static keyword allows the PRNG and distribution objects to persist between function calls. In other words, they won’t be re-created every time the function is called. This allows them to behave optimally for the duration of your program.

SLIGHT TANGENT:
Seeding std::mt19937 with a single 32-bit value is less than ideal, but it suffices for the purposes of a small program. Proper seeding would require enough extra work that wrapping std::mt19937 with a class to ensure full seeding would be ideal. But given the contention that showing <random> was already too far off topic, I will not demonstrate any code. But here’s a link if you’re curious: https://kristerw.blogspot.com/2017/05/seeding-stdmt19937-random-number-engine.html