Thread: How to generate a random chars in C programming

  1. #1
    Banned
    Join Date
    Apr 2015
    Posts
    596

    How to generate a random chars in C programming

    Hi, How can I generate a function that's printing a random characters of CODE ACII from A-Z uppercase! ?? is there a specific command from printing a random characters?
    In every attempt the input must be changed automatically (not stuck on specific character!)


    thanks
    Last edited by RyanC; 11-05-2015 at 04:45 PM.

  2. #2
    Registered User
    Join Date
    Aug 2015
    Posts
    26
    Do something like this
    Code:
    srand(time(NULL)); //only do this once
    (rand()%(90-65))+65; //65 is ASCII for capital A, 90 is ASCII for capital Z
    
    See this
    Last edited by YayIguess; 11-05-2015 at 04:54 PM.

  3. #3
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    See this

  4. #4
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Here's an example that doesn't even rely on ASCII or even 'A' to 'Z' being consecutive numbers each increasing by one

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
     
    int main(void)
    {
        static const char ucase[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        const size_t ucase_count = sizeof(ucase) - 1; // ucase includes terminating '\0'
        size_t i, j;
    
        srand(time(NULL));
    
        for(i = 0; i < 10; i++) {
            for(j = 0; j < ucase_count; j++) {
                char random_char;
                int random_index = (double)rand() / RAND_MAX * ucase_count;
                
                random_char = ucase[random_index];
                printf("%c", random_char);
            }
            printf("\n");
        }
    
        return 0;
    }
    I leave it as an exercise for the reader to guess why I might have used the strange way of calculating random_index instead of just rand() % ucase_count (Edit: and even if it matters for this use case)
    Last edited by Hodor; 11-05-2015 at 05:30 PM.

  5. #5
    Registered User
    Join Date
    Aug 2015
    Posts
    26
    Quote Originally Posted by Hodor View Post
    See this
    You don't need to have the ASCII codes memorized, I looked it up (which took a total of 10 seconds). It certainly isn't harmful to know what some characters are though.

  6. #6
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Hodor's point is you don't need the ASCII (or insert-your-character-set-here) codes at all -- neither memorized or looked up. While it's extremely unlikely nowadays, it is possible that some computers use character sets that are not ASCII compatible. Such character sets, as Hodor pointed out, may not have A..Z as consecutive elements, and their numeric representation very well may not be from 65..90. See EBCDIC for an example.

    It takes very little effort to make code that works around this (like Hodor did), and it's much safer/more portable. Plus, it's easier to read (no need for explanatory comments or to look up ASCII/whatever charts). Put this in your little library of helper functions, and you only have to write it once, then reuse it as many times and places as you want.

    Note, the only guarantee that the C standard gives is that the characters '0' through '9' can be treated as though they exist sequentially, so '9' - '3' will equal 6 (note lack of quotes on the 6 -- that is the number 6, not the character '6', which may have a different value). And IIRC, it's not required that the input character set (what you write your program in) actually has the digits sequentially, just that the compiler act as though it does.

  7. #7
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Quote Originally Posted by YayIguess View Post
    You don't need to have the ASCII codes memorized, I looked it up (which took a total of 10 seconds). It certainly isn't harmful to know what some characters are though.
    I didn't mean to imply that knowing them was harmful to one's health. But wouldn't typing rand % ('Z' - 'A' + 1) + 'A' have been quicker than looking them up and typing the comment to explain the magic numbers?

  8. #8
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> int random_index = (double)rand() / RAND_MAX * ucase_count;
    I think you're missing a +1 in there.

    >> I leave it as an exercise ...
    Not using % avoids using just lower order bits from rand(), or something like that.
    However, division/multiplication doesn't help with distribution: Preserving RNG distribution on int cast (Nominal Animal has a cool implementation in post #10 as well)

    gg

  9. #9
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Quote Originally Posted by Codeplug View Post
    >> int random_index = (double)rand() / RAND_MAX * ucase_count;
    I think you're missing a +1 in there.
    The bug is worse than that (I am missing a -1) but the problem is more that rand() does not produce RAND_MAX very often at all and the "target range" is so small. So I would need to do two things: a) add the -1 where it's required; and b) think about the distribution of rand() a bit more

    Edit:
    In Nominal Animal's post he says "Again, none of this aliasing occurs if you just use min + (int)((double)interval * prng())." but this is not the answer here and after looking at the horrible distribution of C's rand() function (glibc actually) it's not a solution either

    Edit 2: Oh I see where you got that I was missing a +1 from, but nah, in the case of the code above I'm missing a -1 because the range is [0, RAND_MAX] and I'm not calculating max - min + 1 as in post #10 of your link (which is why the sign reversal is necessary and I should be multiplying by (ucase_count - 1)
    Last edited by Hodor; 11-05-2015 at 07:56 PM.

  10. #10
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Until I figure out a way to get around rand()'s distribution problem maybe just amend the example to

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    int main(void)
    {
        static const char ucase[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        const size_t ucase_count = sizeof(ucase) - 1; // ucase includes terminating '\0'
        size_t i, j;
    
        srand(time(NULL));
    
        for(i = 0; i < 10; i++) {
            for(j = 0; j < ucase_count; j++) {
                char random_char;
                int random_index = rand() % ucase_count;
    
                random_char = ucase[random_index];
                printf("%c", random_char);
            }
            printf("\n");
        }
    
        return 0;
    }

  11. #11
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> In Nominal Animal's post he says "Again, none of this aliasing occurs if you just use min + (int)((double)interval * prng())."
    I'm assuming that's a brain fart.

    If you look at the end of post #10, the same formula is presented with:
    >> Yes, this way will have some aliasing, too ...

    This is the "+1" that I was thinking of:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    int rand26_A()
    {
        return (int)((double)rand() / RAND_MAX * 26.0);
    }
    
    int rand26_B()
    {
        return (int)((double)rand() / (RAND_MAX + 1) * 26.0);
        //                                        ^
        //                                       here
    }
    
    void test(int (*rand26)())
    {
        int table[26] = {0};
        int n;
        for (n = 0; n < 100000; ++n)
        {
            int i = rand26();
            if (i < 0 || i > 25)
                printf("Uh Oh\n");
            else
                ++table[i];
        }
    
        for (n = 0; n < 26; ++n)
            printf("%d\n", table[n]);
        printf("\n\n");
    }
    
    int main()
    {
        printf("rand26_A:\n");
        srand(26);
        test(&rand26_A);
    
        printf("rand26_B:\n");
        srand(26);
        test(&rand26_B);
    
        return 0;
    }
    Code:
    rand26_A:
    Uh Oh
    Uh Oh
    Uh Oh
    Uh Oh
    Uh Oh
    Uh Oh
    Uh Oh
    3860
    3788
    3914
    3830
    3958
    3893
    3918
    3825
    3747
    3788
    3845
    3830
    3830
    3892
    3886
    3827
    3851
    3731
    3885
    3930
    3877
    3761
    3730
    3862
    3808
    3927
    
    rand26_B:
    3860
    3788
    3914
    3830
    3958
    3893
    3919
    3824
    3747
    3788
    3847
    3828
    3830
    3895
    3883
    3827
    3854
    3735
    3878
    3932
    3878
    3763
    3727
    3862
    3808
    3932
    >> Until I figure out a way to get around rand()'s distribution problem
    The best you can do to preserve rand's distribution is to use "exclusion method" in post #13 (which is from "Accelerated C++").

    gg

  12. #12
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Quote Originally Posted by Codeplug View Post
    >> In Nominal Animal's post he says "Again, none of this aliasing occurs if you just use min + (int)((double)interval * prng())."

    I'm assuming that's a brain fart.
    Yes, it probably was. I had a similar fart so it's understandable.

    Quote Originally Posted by Codeplug View Post

    This is the "+1" that I was thinking of:
    Code:
    int rand26_B()
    {
        return (int)((double)rand() / (RAND_MAX + 1) * 26.0);
        //                                        ^
        //                                       here
    }
    Yes. I just wasn't thinking when I wrote the code and after you mentioned the bug, dividing by RAND_MAX+1 also entered my mind, but then I decided against it because I *guessed* (shoot me! ) that RAND_MAX might be equivalent to INT_MAX (turns out that on my system, at least, that it is) and I didn't want to deal with potential overflow so I changed my mind and went with subtracting 1 from the required max-value (26) instead.

    Getting RAND_MAX to actually be returned by rand() seems to be highly dependent upon the seed used. (based on my admittedly superficial investigation)

    Quote Originally Posted by Codeplug View Post
    The best you can do to preserve rand's distribution is to use "exclusion method" in post #13 (which is from "Accelerated C++").
    Oh I think the best way for me to preserve its distribution is to just not use rand() Quite honestly I haven't used rand() in a long, long time.


    Edit: Actually your example does rely on integer overflow. Is that intentional? It certainly helps with the distribution
    Last edited by Hodor; 11-05-2015 at 09:41 PM. Reason: fixed quote tags

  13. #13
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Umm, I see what I should have done now (and why... "partitioning" resulting from integer division).

    Code:
    int random_index = (double)rand() / (RAND_MAX + 1L) * ucase_count;
    Pfft

  14. #14
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Codeplug: your example doesn't work for me

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    int rand26_A()
    {
        return (int)((double)rand() / RAND_MAX * 26.0);
    }
    
    int rand26_B()
    {
        return (int)((double)rand() / (RAND_MAX + 1) * 26.0);
        //                                        ^
        //                                       here
    }
    
    void test(int (*rand26)())
    {
        int table[26] = {0};
        int n;
        for (n = 0; n < 100000; ++n)
        {
            int i = rand26();
            if (i < 0 || i > 25)
                ; //printf("Uh Oh\n");
            else
                ++table[i];
        }
    
        for (n = 0; n < 26; ++n)
            printf("%d\n", table[n]);
        printf("\n\n");
    }
    
    int main()
    {
        printf("rand26_A:\n");
        srand(26);
        test(&rand26_A);
    
        printf("rand26_B:\n");
        srand(26);
        test(&rand26_B);
    
        return 0;
    }
    Code:
    $ gcc -Wall t2.c
    t2.c: In function ‘rand26_B’:
    t2.c:12:45: warning: integer overflow in expression [-Woverflow]
         return (int)((double)rand() / (RAND_MAX + 1) * 26.0);
                                                 ^
    [hodor@hodorshouse tmp]$ ./a.out 
    rand26_A:
    3771
    3963
    3868
    3921
    3873
    3834
    3822
    3841
    3859
    3845
    3847
    3792
    3872
    3846
    3929
    3855
    3817
    3750
    3903
    3868
    3807
    3879
    3850
    3800
    3818
    3770
    
    
    rand26_B:
    3771
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0

  15. #15
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Yeah. I think the right way to do the non-mod formula is:
    Code:
    int rand26_B()
    {
        return (int)((double)rand() / (RAND_MAX / 26.0 + 1));
    }
    gg

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Generate Random Number
    By peacealida in forum C++ Programming
    Replies: 10
    Last Post: 04-06-2008, 08:57 AM
  2. Is it possible to generate random text?
    By FingerPrint in forum C++ Programming
    Replies: 6
    Last Post: 07-19-2006, 03:10 PM
  3. generate a random password
    By mabufo in forum C++ Programming
    Replies: 17
    Last Post: 02-23-2006, 05:57 PM
  4. generate a random number
    By waxydock in forum C++ Programming
    Replies: 5
    Last Post: 06-05-2005, 07:43 PM
  5. generate random letters
    By Unregistered in forum C++ Programming
    Replies: 2
    Last Post: 05-19-2002, 02:22 AM