0

My code doesn't work, for some reason it skips a "fgets" instruction, and I've been relentlessly trying to fix this problem but I can't. I was in the middle of making a simple C game about rolling 3 dices and giving the result, the player would than guess if the next result would be higher, lower or the same as the last one.

Here's the code:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

int main(int argc, char *args[]) {
    printf("__________________________OPEN THE GAME!_________________________\n");
    printf("\tThe rules are simple,\n\twe are gonna roll 3 dices and\n\tgive you the result.\n\tYou're then going to guess if\n\tthe next roll is gonna be\n\thigher(h), lower(l) or same(s)!\n");
    //char ready[3];
    //printf("\t\t\tAre you ready? ");
    //fgets(ready, 2, stdin);

    int roll1;

    int roll2;

    int roll3;

    char enter[] = "y";

    while(strcmp(enter, "n")) 
    {
        roll1 = rand()%6 + 1;
        roll2 = rand()%6 + 1;
        roll3 = rand()%6 + 1;
        printf("First roll!\n%d\n\n", roll1);
        printf("Second roll!\n%d\n\n", roll2);
        printf("Third roll!\n%d\n\n", roll3);

        int firstResult = roll1 + roll2 + roll3;
        printf("Result: %d\n", firstResult);

        char guess[2];
        printf("\t\t\tWill the next one be h/l/s? ");
        fgets(guess, 2, stdin);

        int result = (rand()%6 + 1) + (rand()%6 + 1) + (rand()%6 + 1);

        if (((result == firstResult) && (strcmp(guess,"s"))) || ((result > firstResult) && (strcmp(guess,"h"))) || ((result < firstResult) && (strcmp(guess,"l"))))
        {
            printf("°°°°°°°°°°°Correct, you win!°°°°°°°°°°°\n");
            printf("      The result was: %d\n", result);
        }
        else
        {
            printf("\tI'm sorry, the new roll is %d :(\n", result);
        }

        printf("\tTry again?(y/n)");
        fgets(enter, 2, stdin);

        firstResult = result;
    }
    printf("\t\t\tGG, come back when you want to test your luck B)\n");
    return 0;
}

the fgets instruction that it's being skipped it's at the bottom, after the try again. Can someone explain me what am I missing? Even with scanfs it wouldn't work or using char instead of strings.

B.Castarunza
  • 135
  • 12
  • 1
    I'd use a much bigger buffer than just 3 — I'd start at 4096 and go up. Sure, you won't often get a single line of input that large, but you'll handle long lines better than if you do it two characters at a time, and you'll be better able to deal with people who type long lines of input. Users are ornery critters; they do things you don't expect or want, like type "of course I want you to do it, you silly computer" where you expected them to type `y`. – Jonathan Leffler May 02 '20 at 18:41
  • OT: regarding: `int main(int argc, char *args[])` Since those parameters are not used, the compiler will output two warnings messages about unused parameters. Suggest using the other valid signature for `main()`: `int main( void )` – user3629249 May 02 '20 at 20:01
  • OT: regarding: `printf("\tThe rules are simple,\n\twe are gonna roll 3 dices and\n\tgive you the result.\n\tYou're then going to guess if\n\tthe next roll is gonna be\n\thigher(h), lower(l) or same(s)!\n");` It is better to honor the right page margin. Suggest: `printf("\tThe rules are simple,\n" newline "\twe are gonna roll 3 dices and\n" newline "\tgive you the result.\n" newline "\tYou're then going to guess if\n" newline "\tthe next roll is gonna be\n" newline "\thigher(h), lower(l) or same(s)!\n");` Note: newline is just your hitting 'return' on your keyboard – user3629249 May 02 '20 at 20:26
  • regarding: `roll1 = rand()%6 + 1;` Before the very first call to `rand()` need to call `srand()` (only once) to 'seed' the random number generator. Suggest: `#include ` and `srand( (unsigned)time( NULL ) );` – user3629249 May 02 '20 at 21:11
  • Okay, thank you everybody! I applied every change suggested in both comments and answer and now everything works! Except . . . whenever I input "s" on the keyboard, the strcmp returns 0 when it compares it with the string "s", even more mind-boggling when it's compared with the string "h"/"l", it give back a positive, how come? – B.Castarunza May 03 '20 at 13:06
  • P.S. if I use a buffer too big won't that be a loss of memory if they just input 'y'? The other blocks aren't going to be used and stay empty forever, unless I do something about it, right? – B.Castarunza May 03 '20 at 13:07
  • @B.Castarunza "whenever I input "s" on the keyboard, the strcmp returns 0 when it compares it with the string "s"," --> what do you see as wrong with that? – chux - Reinstate Monica May 03 '20 at 15:48
  • Doesn't 0 in an if statement mean False? Shouldn't strcmp give you back a not-zero number(True) when the 2 strings are the same? – B.Castarunza May 03 '20 at 16:28
  • @B.Castarunza Review [strcmp, strncmp - compare two strings](http://man7.org/linux/man-pages/man3/strcmp.3.html) – chux - Reinstate Monica May 03 '20 at 17:03
  • Thank you so much, it all makes sense now! I've been so accustumed to Java and Python that this notion must have passed me by. – B.Castarunza May 03 '20 at 18:49

1 Answers1

1

fgets() buffer too small.

Entering "h\n" needs at least 3 to save completely as a string.

Use a larger buffer.


After reading with fgets(), lop off the potential '\n' to make the following strcmp(guess,"s") work.

    char guess[100];
    printf("\t\t\tWill the next one be h/l/s? ");
    fgets(guess, sizeof guess, stdin);
    guess[strcspn(guess, "\n")] = '\0';

Similar changes needed for fgets(enter...

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • I thought that \n, like \0 was seen as a single special character. Now I'm starting to wonder if \0 would be seen as a single character too. – B.Castarunza May 03 '20 at 12:35
  • @B.Castarunza When reading a _line_, `'\0'` has no special meaning. `'\n'` is special. Reading a null character is like any other character. Within a _string_, `'\n'` has no special meaning. `'\0'` is special. – chux - Reinstate Monica May 03 '20 at 15:18
  • Then fgets() is the "within a _string_" case since that would leave '\n' with no special meaning, ergo it will be seen as 2 separate characters instead of 1 ( which I assume would be the case with '\0'). May I ask you an example with read _line_ where the roles would be reversed('\0' not special, '\n' special)? – B.Castarunza May 03 '20 at 15:39
  • "Then fgets() is the "within a string" case since that would leave '\n' with no special meaning" --> No. `fgets()` reads a _line_ , `'\n'` is special (it signals to stop reading), not a _string_. `fgets()` then forms a _string_ by appending a _null character_ to the characters read and saved. – chux - Reinstate Monica May 03 '20 at 15:44
  • Ok, let me clarify my question. Is there a case where '\0' is read as a single character? What about ' \n '? – B.Castarunza May 03 '20 at 16:35
  • @B.Castarunza When `fgets(guess, ...)` only reads a `'\n'`, that is saved and reading stops. A `'\0'` is appended. `guess[0] == '\n'` and `guess[1] == '\0'`. – chux - Reinstate Monica May 03 '20 at 17:05
  • @B.Castarunza "Is there a case where '\0' is read as a single character?" --> No. When `fgets(guess, ...)` reads a `'\0'` (to read a `'\0'` is uncommon, yet possible) , it continues on just like any other non-`'\n'` character. – chux - Reinstate Monica May 03 '20 at 17:06
  • Now I'm more confused, you just told me that ' \0 ' can't be read as a single character, but in the previous response you wrote guess[1] == '\0'; If it wasn't read as a single character, then shouldn't it be: guess[1] = '\' guess[2] = '0' ? – B.Castarunza May 03 '20 at 18:39
  • @B.Castarunza `'\0'` is the _null character_. The `'\0'` in `guess[1]` is not something that was _read_. It was appended by `fgets()` to the lone `'\n'` that was read. One character read `'\n'`, that an an extra `'\0'` written to `guess[]` thus forming a _string_. – chux - Reinstate Monica May 03 '20 at 21:38