0

After compiling my program of Dice Roll, I got this error. What is wrong with the code?

Also before I was using gets() instead of scanf() command, but because of that I got this error - passing argument 1 of 'gets' makes pointer from integer without a cast So I removed the gets() command and used scanf and then there was no error regarding scanf().

What is the reason for getting these two errors?


Ok, so as per the answer I got to know how I should have used the gets() command and why I shouldn't use it instead should use scanf(). So, I made the changes. Though I have encountered two new errors, this time it's related to the delay() command that I used.

Errors: undefined reference to delay |error: ld returned 1 exit status|


OK so I solved my last errors by using Sleep() command from windows.h library instead of Delay() command. The programs was compiled. But still there is a runtime error in the program, it works well till getting the roll1 but then it just print the next two statement and terminated the programs without taking a input for the guess.

It skips all the code after printf("Will it be Higher/Lower or the same? (press H/L/S)\n"); and directly terminates the program.


Ok So I solved above problem adding a whitespace before the "%c" in scanf(" %c", &nextGuess); statement. (Little things xD) Now only problem is that my toupper() command is not working.

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <windows.h>


int main()
{
    int i, roll1=0, roll2=0, NumberOfRolls, RandomNUM1[50], RandomNUM2[50];
    char nextGuess;

    puts("Welcome to the Dice Roll Game");
    puts("How many times do you want to roll a dice?");
    scanf("%d", &NumberOfRolls);

    for( i=1; i<=NumberOfRolls; i++ ) {
        RandomNUM1[i] = ( rand()%6 ) + 1;
        roll1 += RandomNUM1[i];
    }

    printf("\nYou Got %d in your first roll!\n", roll1);
    Sleep(3000);
    printf("\nLet's see if you can guess the value of next roll.\n");
    printf("Will it be Higher/Lower or the same? (press H/L/S)\n");
    scanf(" %c", &nextGuess);
    toupper(nextGuess);

        for( i=1; i<=NumberOfRolls; i++ ) {
        RandomNUM2[i] = ( rand()%6 ) + 1;
        roll2 += RandomNUM2[i];
    }

    if(nextGuess=='H'){
        if(roll1<roll2){
            printf("You are such a player, you guessed it right! It's %d", roll2);
        }
        else if(roll1>roll2){
            printf("Uh-Oh! Bad Luck! First roll was higher, It's %d", roll2);
        }
        else if(roll1==roll2){
            printf("Uh-Oh! Bad Luck! Both the rolls are same, It's %d", roll2);
        }

    }

    if(nextGuess=='L'){
        if(roll1>roll2){
            printf("You are such a player, you guessed it right! It's %d", roll2);
        }
        else if(roll1<roll2){
            printf("Uh-Oh! Bad Luck! First roll was lower, It's %d", roll2);
        }
        else if(roll1==roll2){
            printf("Uh-Oh! Bad Luck! Both the rolls are same, It's %d", roll2);
        }

    }

    if(nextGuess=='S'){
        if(roll1==roll2){
            printf("You are such a player, you guessed it right! It's %d", roll2);
        }
        else if(roll1>roll2){
            printf("Uh-Oh! Bad Luck! First roll was higher, It's %d", roll2);
        }
        else if(roll1<roll2){
            printf("Uh-Oh! Bad Luck! Second roll is higher, It's %d", roll2);
        }

    }

        return 0;
}
Srijan Singh
  • 37
  • 1
  • 2
  • 11
  • 1
    if you ever check the documentation of `gets`, it says clearly, `warning: unsafe (see fgets instead)`. – WhiteSword Jul 16 '17 at 11:02
  • @ManjinderSinghHanjra I surely look into it. Didn't know that thanks! – Srijan Singh Jul 16 '17 at 12:22
  • @xing Yeah thanks for pointing it out, I got stuck with these errors didn't notice it. Thanks! – Srijan Singh Jul 16 '17 at 12:23
  • ["Can you give me a reference when one should use `gets()` and `puts()` command and when the `printf` or `scanf` ones."](https://stackoverflow.com/questions/45127682/error-expected-declaration-specifiers-or-before-string-constant-puts-a#comment77226777_45127752)-- You should _never_ use the unsafe `gets()`, which was deprecated in C99 and removed from C11. Instead, use `fgets()`. `scanf()` is also a problematic function, frequently misused. Consider using `fgets()` and `sscanf()` together when `scanf()` functionality is needed. – ad absurdum Jul 16 '17 at 13:34
  • @DavidBowling Thanks man! Can you tell me why my program is skipping all codes after printf("Will it be Higher/Lower or the same? (press H/L/S)\n"); and directly terminating the program. – Srijan Singh Jul 16 '17 at 13:53
  • Ok, i understood the mistake I made. I didn't put a whitespace before "%c" in `scanf(" %c", &nextGuess);` but I don't know the logic behind putting that whitespace, can you tell me.. Also my toupper() is not working I don't know why. – Srijan Singh Jul 16 '17 at 14:05
  • You should be checking the values returned by calls to `scanf()` to validate input. Note that `scanf()` returns an `int` that is the number of successful assignments made. Posted code did not appear to match your comments; I see that is now changed. Using `%d` with character input was a mistake that would cause `scanf()` to fail, returning 0. But, `" %c"`, with leading whitespace works because this tells `scanf()` to skip over leading whitespace characters. Previous calls to `scanf()` leave a `\n` (which is a whitespace character) in the input stream that must be dealt with. – ad absurdum Jul 16 '17 at 14:09
  • @DavidBowling Yes right, I did just update my whole code and the description above. – Srijan Singh Jul 16 '17 at 14:13
  • Good, then my previous comment should make sense. Without the leading whitespace character in `" %c"`, `scanf()` picks up the first character it encounters, which is the `\n` left behind by the previous call: `scanf("%d", &NumberOfRolls);`. – ad absurdum Jul 16 '17 at 14:15
  • @DavidBowling Yeah I get it know. Thanks buddy! My last problem is that the toupper() command is not working in the program while running it. If I type a lower case letter in `nextGuess` it is not converting it to uppercase. – Srijan Singh Jul 16 '17 at 14:18
  • It can be tricky working with `scanf()`, and you should not combine `scanf()` with, e.g., `fgets()` or `getchar()`. This is why I suggested earlier to use `fgets()`, then `sscanf()`. `fgets()` does _not_ leave the `\n` in the input stream (if the input buffer is large enough), and `sscanf()` gives the parsing capabilities of `scanf()`, repeatably. – ad absurdum Jul 16 '17 at 14:20
  • `toupper()` does not change the value of the input variable, it returns a new value. Try `nextGuess = toupper(nextGuess);`. – ad absurdum Jul 16 '17 at 14:22
  • @DavidBowling it did work, thanks again. But still, there is a fault in the program. I think it's not producing random numbers. Every time, I use 5 as `NumberOfRolls`, it outputs number 28, each and every time. `for( i=1; i<=NumberOfRolls; i++ ) { RandomNUM1[i] = ( rand()%6 ) + 1; roll1 += RandomNUM1[i];` is this right? – Srijan Singh Jul 16 '17 at 17:22
  • `rand()` generates pseudo-random `int` values, based on a seed value set by `srand()`. Given the same seed value, the same pseudo-random sequence is generated every time. It is typical to `#include ` and set the seed value with `srand(time(NULL));`, once at the beginning of `main()`, before the first call to `rand()`. [You may want to read more here](https://stackoverflow.com/questions/822323/how-to-generate-a-random-number-in-c). – ad absurdum Jul 16 '17 at 18:43
  • @DavidBowling Seems like I can't call the rand() more than 1 time, but for this program, I have coded it like that I have to call it two times. What could be the alternative? – Srijan Singh Jul 17 '17 at 16:29
  • @SrijanSingh-- you can call `rand()` as many times as you like. [Here is an Ideone link](http://ideone.com/KyMrg3) to a version of your code that works. There are some comments there for you to study; note that I have removed some Windows-specific features for my convenience. – ad absurdum Jul 17 '17 at 17:11
  • @DavidBowling Thanks a lot for taking out the time and writing it, especially with the comments. Apart from this program, Isn't it bad to use the same type of variable seed for the same kind of pseudorandom number generating algorithm? – Srijan Singh Jul 17 '17 at 17:51
  • The sequence of pseudo-random numbers generated by `rand()` from one seed value is deterministic, but suitable for simple applications (like most games). There is no need to seed more than once, since the sequence simulates a random sequence. Two seed values that are close can generate wildly different sequences. Using `time()` to seed `rand()` means that each game uses a different sequence. But, `rand()` is not suitable for, e.g., secure encryption algorithms, or for high-quality monte-carlo methods. When better random-numbers are needed, better random-number sources should be found. – ad absurdum Jul 17 '17 at 18:09
  • 1
    @DavidBowling Thanks a lot man, you helped me gain a ton of knowledge! Really appreciated! Looking forward to this bright and interesting journey. – Srijan Singh Jul 17 '17 at 18:31

2 Answers2

0

The gets function reads a string (till the next newline character) from stdin, therefore it asks for a char pointer (char*) to an area of memory where it can put all the characters read including string terminator. The mistake you made is to pass to that function a pointer to int, therefore not only you get a compiler error because you tried to pass an int pointer to gets (for which there are none implicit conversions), but even if it compiled, it would not have worked as you expected because it would put all the characters (which have a size of one byte - most of the times) in that area of memory encoded as chars. That means that when you try to dereference one using a pointer to int, the characters are "read like they were an int"!

There is an example (supposing 1-byte chars, 4-bytes int and a little endian machine and that there is an implicit cast from int* to char* which does not exist and hopefully will never exist):

int num
gets(&num);

if I input 123 in stdin, the memory area pointer by num is large enough to contain the string, but it would contain (exadecimal representation):

0x31|0x32|0x33|0x00

because the string is 3 characters long, ASCII code for '1' is 0x31, for '2' is 0x32, and for '3' is 0x33 and terminates with '\0'!! Then, when you try to dereference it you get this int (binary representation - supposing a little endian machine):

00000000|00110001|00110010|00110011

which is not the int value 123 but instead ‭3224115‬. Which is not what you wanted to get.

When you use the scanf function, you pass to that function a format string which tells it how to interpret the next arguments passed to it and performs the appropriate conversions between the string read to the right type you specified. That means that you should still pay attention to what you tell to the scanf function while you write the format string (if you tell it to read a string and pass to it a pointer to int, the program will probably crash), but it performs the appropriate conversions for you, if you write the format string correctly.

That's why with scanf everything works perfectly (you're reading an int and you specified "%d" as format string), whereas with gets it does not compile to avoid serious mistakes.

I also would like to remark some points of this answer:

  • The example is just for didactic purposes and the code provided does not work indeeed. The fact that I supposed that it compiles is for didactic purposes; obviously, the code provided in that example does not compile
  • If, in that example, we input a string larger than 3 characters (which are four if we include the null terminator) or the int (char) type contains less (more) than 4 (1) byte, the program would have crashed because we corrupted other areas of memory
  • The reference is more expert than me in techincal stuff, so here are the links to the gets function and the scanf function: gets, scanf (and the ASCII Table is useful too)
  • You could use the gets function together with the atoi function to parse the string read from gets (using a char pointer to a free area of memory large enough to contain the string, which is pretty hard to allocate (*)) to an int, but scanf is the best approach.

(*) Remember: if you allocate an area of memory that contains 20 chars, the user will input 21 chars. The atoi function fails, but the worst thing is that you have a buffer overflow (and can be a high security issue if your program runs under root permissions).

LuxGiammi
  • 631
  • 6
  • 20
0

You have a stray ,

At the 2nd line of your main, you declare char nextGuess, instead of char nextGuess;

The compiler tells you it expects specifiers or ... after , so either you add these, or you end the line properly with;.

And for the other problem you mention:

passing argument 1 of 'gets' makes pointer from integer without a cast

Since gets argument should be char *str and you didn't provide it.

You can fix that by, for example:

char tmp_NumberOfRolls[10];
gets(tmp_NumberOfRolls);  
NumberOfRolls = atoi(tmp_NumberOfRolls);

but I prefer the scanf solution

PS: (in a now edited version of the code) ***//Error Line*** is not a comment (at least, not all of it) since the *** is still counted as part of the code and will cause an error. Either move the // a bit to the left or enclose that whole part with /* ... */

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
CIsForCookies
  • 12,097
  • 11
  • 59
  • 124
  • I also prefer the scanf solution because if you try to guess that the maximum size of input string is 10 chars, believe me, the user would try to input 20. This way, not only the `atoi` function fails, but we would have a buffer overflow in tmp_NumberOfRolls, which is *not* so good. – LuxGiammi Jul 16 '17 at 11:27
  • @LuxGiammi That was just a proof of concept to show using gets that way will not cause the problem OP had. Of course buffer overflow is hazardous and should be taken into account. – CIsForCookies Jul 16 '17 at 11:38
  • @CIsForCookies Yes, what a silly mistake I did miss that semicolon, I was thinking about how to do the loop, missed the little thing. Thanks for the answer anyway. Also about the comment, I used the Bold & italic option in the editor that is why it's like that. Also can you please explain what is that 'atoi' in the code you mentioned. Thanks! – Srijan Singh Jul 16 '17 at 12:27
  • @LuxGiammi Can you give me a reference when one should use gets() and puts() command and when the printf or scanf ones. – Srijan Singh Jul 16 '17 at 12:29
  • Sure :) "The C library function int atoi(const char *str) converts the string argument str to an integer (type int)." quoted from (https://www.tutorialspoint.com/c_standard_library/c_function_atoi.htm). It basically takes a string such as "42" (for example) and turns it into a int with value 42 – CIsForCookies Jul 16 '17 at 12:29
  • 1
    @CIsForCookies Oh thanks, man! Sorry for the silly mistake, I am fairly new to this. – Srijan Singh Jul 16 '17 at 12:43