1

Hello I'm writing a program that would generate 10 random characters in order to form a word (it's for a game).

so here's my function:

void GenerateTen(int number)
{
    int i; 
    char abc[30]="abcdefghijklmnopqrstuvwxyz";
    char newabc[8];


    for (i = 0; i < number; ++i) {
        newabc[i] = abc[rand() % (sizeof(abc) - 1)];
        printf("%c ", newabc[i]);
    }

    newabc[number] = 0;

}

the number variable contains 10 and the output is supposed to simply print these 10 characters in the array. There's no error by the compiler however, the program generates the same set of characters. Thank you for your help! :-)

Erail
  • 169
  • 1
  • 8
  • program generates same set of characters - what does it mean? what is the actual problem here? – Wasi Ahmad Mar 03 '17 at 04:35
  • It should randomly generate different sets – Erail Mar 03 '17 at 04:36
  • 1
    You really want `newabc[i] = abc[rand() % strlen(abc)]` For efficiency, precompute: `len = strlen(abc)` before the loop and use `newabc[i] = abc[rand() % len]`. The `sizeof` would inject 0x00 at some points. And, if you get the same numbers, you may want to look up the `srand` function (e.g. `srand(time(NULL));` in `main` is the usual way) – Craig Estey Mar 03 '17 at 04:37
  • http://stackoverflow.com/questions/822323/how-to-generate-a-random-number-in-c – Rishi Mar 03 '17 at 04:39
  • 1
    `sizeof` will work here, but you are better off using `strlen` – Rishi Mar 03 '17 at 04:47
  • `sizeof(char[30])` could as well be `32` (and probably would if slightly optimized by the compiler) so I'm amazed that `rand() % sizeof(abc)` never gives one of the random char lying after `z` (or worse: the nul char...). – Matthieu Mar 03 '17 at 06:17
  • 1
    @matthieu:no, it can't. `size_of array` is always exactly the product of the element size and the number of elements. Only padding in an element is counted, and that is part of the element size. The compiler is free to place padding between the array and the next object in memory, but that padding is not part of any object and referencing it is undefined behaviour. – rici Mar 03 '17 at 07:14

3 Answers3

2

I got your problem. You have to seed it. Seeding it with the time is a good idea: srand()

rand() returns pseudo-random numbers. It generates numbers based on a given algorithm. The starting point of that algorithm is always the same, so you'll see the same sequence generated for each invocation.

You can set the "seed" of the random generator with the srand function(only call srand once in a program). One common way to get different sequences from the rand() generator is to set the seed to the current time or the id of the process:

srand(time(NULL)); or srand(getpid()); at the start of the program.

Reference: https://stackoverflow.com/a/1108810/5352399


You can update your code as follows.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
    srand(time(NULL));
    for(int i = 0; i < 5; i++){
        GenerateTen(8);
    }
    return 0;
}

void GenerateTen(int number) {
    int i; 
    char abc[26]="abcdefghijklmnopqrstuvwxyz";
    char newabc[8];
    for (i = 0; i < number; ++i) {
        newabc[i] = abc[rand() % (sizeof(abc) - 1)];
        printf("%c ", newabc[i]);
    }
    newabc[number] = 0;
}

It outputs:

r x r a f d a b 
f f t i x m l b 
r k j e p h d v 
s w a c p g v h 
e n j l r j n w
Community
  • 1
  • 1
Wasi Ahmad
  • 35,739
  • 32
  • 114
  • 161
1

You need to initialize the pseudo-random number generator using srand().

Just add this after your main().

srand(time(NULL));

What srand(time(NULL)) actually does is srand() generates pseudo-random numbers using a seed value, and time(NULL) returns the current calendar time.

So theoretically, your srand() function is guaranteed to get a different seed value on every runtime. Hence the values produced by rand() would be different each time.

shauryachats
  • 9,975
  • 4
  • 35
  • 48
0

Apart from calling srand(), you should be very careful that you're actually allocating an array of 8 elements (char newabc[8]) and indexing it up to number, so you should expect a buffer overflow when number >= 8). As you're not returning it you can remove it. If you plan on returning it you should allocate it beforehand: char* newabc = (char*)calloc(number+1, sizeof(char));

You can also remove the char abc[30] by realizing that abc[rand() % (sizeof(abc) - 1)] actually is 'a' + rand() % 26. Unless you want to use a custom dictionary with a subset of letter, in which case it would be better to keep it in global memory (outside of the function, or as static inside the function if you prefer to restrain its scope). And mind that sizeof(abc)might not be the same as strlen(abc) depending on your architecture.

So all in all you could end up with:

char* generate_random(int number) // Better C-style name
{
    int i; 
    char* newabc = (char*)calloc(number, sizeof(char));

    if (newabc == NULL)
        return NULL;

    for (i = 0; i < number; ++i) {
        newabc[i] = 'a' + (rand() % 26);
        // printf("%c ", newabc[i]); // Not needed anymore, except for debugging
    }
    // newabc[number] = 0; // Not needed because we used 'calloc()' which zeroes the allocated memory

    return newabc;
}
Matthieu
  • 2,736
  • 4
  • 57
  • 87