3
\$\begingroup\$

This is just a little number guessing game. I know it's simple but I am a newbie in C and I think such a little example can be enough for finding simple design flaws that can than be eliminated.

If you know how parts of the code can be written more beautiful and more safe, please let me know!

/*
 * In this program the user has to guess a number between 1 and 99.
 * He has six tries.
 */

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

int generate_random_number(int lower_range, int upper_range) 
{
    srand(time(0));
    return (rand() % (upper_range - lower_range + 1)) + lower_range; 
}

// this function stops the program until useless input is entered 
void pause()
{
    int useless;
    scanf("%i", &useless);
}

int main()
{   
    // generate random number
    const int lower_range = 1;
    const int upper_range = 99;
    const int random_number = generate_random_number(lower_range, upper_range);

    // start of game
    printf("You have to guess a number between 1 and 99.\n");
    printf("You have six tries.\n");
    const int tries = 6;
    for (int i = 0; i < tries; i++)
    {
        printf("> ");
        int guess;
        scanf("%i", &guess);

        if (guess > random_number)
        {
            printf("The secret number is smaller.\n");
        }
        else if (guess < random_number)
        {
            printf("The secret number is higher\n");
        }
        else if (guess == random_number)
        {
            printf("You found the secret number!\n");
            pause();
            return 0;
        }
    }

    printf("You haven't found the secret number.\n");
    printf("The secret number was %i.\n", random_number);
    pause();
}
\$\endgroup\$
  • 1
    \$\begingroup\$ This is a great exercise btw. In trying to get as few guesses as possible, you as a human will (hopefully) end up using what's known as "binary search", splitting the range of possible candidate numbers in 2 over and over until finding the number. This happens to be the most efficient way of searching and you'll encounter this again when studying algorithm theory later on. This example helps one understand why it is the most efficient. \$\endgroup\$ – Lundin Apr 2 at 9:37
2
\$\begingroup\$

This looks quite good code. You've avoided many of the common mistakes.

Here are the things I spotted as I walked through. Most of them are quite minor; the only serious issue is the handling of invalid user input.


srand(time(0));

Don't do this every time you want a random number - a random number generator is intended to be seeded just once. So move the srand() call to the beginning of `main().

(Yes, I know this program calls generate_random_number() only once. But we shouldn't need to have that knowledge, and we might want to change that behaviour, or to re-use this function in another program.)


// this function stops the program until useless input is entered

What's the point? That just annoys the user, who would naturally expect to be returned to their shell after executing a program. This just makes it look like the program is not responding. Also, the useless variable is unnecessary - add the * modifier to the %i conversion to inhibit assignment.


int main()

This says that main() can be called with an unspecified number of arguments. Instead, prefer to explicitly declare that it takes no arguments:

int main(void)

printf("You have to guess a number between 1 and 99.\n");

When the output is a fixed string ending in newline, we can use puts() instead of printf().


    int guess;
    scanf("%i", &guess);

If something that's not a number is entered, then scanf() will fail and guess will be uninitialized (that's Undefined Behaviour, which is Not A Good Thing). We really, really need to check that scanf() successfully converts 1 input, and take some recovery action if not:

int status;
while ((status == scanf("%i", &guess)) != 1) {
    if (status == EOF) {
        fprintf(stderr, "Read error!\n");
        exit 1;
    }
    scanf("%*[^\n]");  // discard input
    printf("? >");
}

Correctly handling input (and, in particular, unexpected input) is difficult in C!


    else if (guess == random_number)

The if is redundant here, as we've eliminated all other possibilities. So that can be simply else.

\$\endgroup\$
2
\$\begingroup\$

Overall pretty decent beginner-level program. It is good that you use const variables for numeric constants instead of just "hard-coding" them into the source.

  • void pause() and int main() etc with empty parenthesis is obsolete style. In C this means "take any parameter" (unlike C++ where it is equivalent to (void)). Never use this form in C, use void pause(void).
  • Your pause function should take accept any keystroke and not just integers. Just replace it with getchar().
  • In general you should only call srand once from your program. That's ok in this case, but for the future, be careful not to hide it inside a function that is called repetively. See https://stackoverflow.com/questions/7343833/srand-why-call-it-only-once.
  • Multiple returns from a program can be hard to read, especially when done from inner blocks. Consider just breaking the loop, then handle the results separately and return only once, at the end of main(). Example below.

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

int generate_random_number(int lower_range, int upper_range) 
{
    srand(time(0));
    return (rand() % (upper_range - lower_range + 1)) + lower_range; 
}


int main (void)
{   
    // generate random number
    const int lower_range = 1;
    const int upper_range = 99;
    const int random_number = generate_random_number(lower_range, upper_range);

    // start of game
    printf("You have to guess a number between 1 and 99.\n");
    printf("You have six tries.\n");
    const int tries = 6;
    bool found=false;
    for (int i = 0; i < tries; i++)
    {
        printf("> ");
        int guess;
        scanf("%i", &guess);

        if (guess > random_number)
        {
            printf("The secret number is smaller.\n");
        }
        else if (guess < random_number)
        {
            printf("The secret number is higher\n");
        }
        else if (guess == random_number)
        {
            found = true;
            break;
        }
    }

    if(found)
    {
      printf("You found the secret number!\n");
    }
    else
    {
      printf("You haven't found the secret number.\n");
    }
    printf("The secret number was %i.\n", random_number);
    getchar();
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.