Trying to learn C, but I'm running into weird bugs (to me at least)

I'm trying to learn C on my own, I have some previous experience in Matlab and Python. I'm trying to create a simple guessing game where you give a number, the computer guesses a number and you have to tell it if it's higher or lower. I've written some code, but it just doesn't work (try inputting 30, for example). The code is ugly, but I'm just trying to understand what's going on.

I've tried writing it using the case statement, but same results there.

Also, what is going on when you answer the y/n question with yy? The numbers go way up all of a sudden?

#include "stdio.h"
#include "stdlib.h"

int main(void) {
    int a;
    int i = 1;
    int b = 50;
    int temp;
    int last = 0;
    char ans = ' ';
    printf("Enter value for computer to guess (0-100): ");
    scanf("%d", &a);

    while (a - b) {
        printf("Is the number larger than %i (y/n): ", b);
        scanf("%s", &ans);
        if (ans == 'y') {
            temp = b;
            b = b + ((b + last) / 2);
            last = temp;
        } else {
            temp = b;
            b = b - ((b + last) / 2);
            last = temp;
        }
        i++;
    }
    printf("Your number was: %i. Number of guesses was: %i \n", b, i);
    return 0;
}

Answers


In your code

 scanf("%s",&ans);

invokes undefined behavior as you're overrunning the allocated memory.

To use %s format specifier, you'll need an array as the argument (pointer to the first element of the array, to be specific).

However, in your case, changing

 scanf("%s",&ans);

to

scanf(" %c",&ans);  // note the space

is likely to solve the issue. Optionally, to handle the extra input, (like yyy), you can consider clearing the input buffer after reading each input, like

while (getchar() != '\n');

or likewise.


You probably want the computer to binary search for the answer and get there efficiently. You'll need to keep track of the upper and lower boundaries where you're searching. Try something like this;

int main(void){
    int a;
    int i = 1;
    int b = 50;
    int lower = 0;
    int upper = 100;
    char ans[256] = {0};
    printf("Enter value for computer to guess (0-100): ");
    scanf("%d", &a);

    while (a-b) {
      printf("Is the number larger than %i (y/n): ",b);
      scanf("%s",ans);
      if (ans[0] == 'y') {
        lower = b;
        b = b + ((upper-lower)/2);
        printf("Last: %d - %d\n",lower, upper);
      }
      else {
        upper = b;
        b = b - ((upper-lower)/2);
        printf("Last: %d - %d\n",lower, upper);
      }
      i++;
    }
    printf("Your number was: %i. Number of guesses was: %i \n",b,i);
    return 0;
}

This is the problem.

char ans = ' ';
...
scanf("%s",&ans);

ans has only a single byte of memory, but you've asked scanf for a whole string. So it dutifully stuffs the whole string into the single byte of ans. Since this includes a null byte, even the input y or n will write an extra byte. yy writes three bytes.

This causes ans to silently overflow its memory wrecking havoc on adjacent variables. This is why yy messes with things, you're putting 3 bytes (2 characters plus a null byte) into 1 allocated byte overflowing by 2 bytes. It overwrites last with the character y which is the number 121. You can see this with a few debugging printfs.

    printf("b = %d, last = %d\n", b, last);
    printf("Is the number larger than %i (y/n): ",b);
    scanf("%s",&ans);
    printf("b = %d, last = %d\n", b, last);

Enter value for computer to guess (0-100): 30
b = 50, last = 0
Is the number larger than 50 (y/n): yy
b = 50, last = 121

Instead you want to use %c to read a single character. But that has its own problems, scanf("%d", &a) is leaving a newline on STDIN and scanf("%c", &ans) will read that newline first.

This is why scanf is a problem and should be avoided, it can leave unexpected input in the stream. There's lots of answers here on SO recommending against scanf. Instead use fgets or getline to read the whole line and then use sscanf to read the string. I prefer getline because it handles allocating line memory for you.

Here's a sketch of what to do.

char *line = NULL;
size_t linelen = 0;

printf("Enter value for computer to guess (0-100): ");
getline(&line, &linelen, stdin);
sscanf(line, "%d", &a);
printf("You entered %d\n", a);

printf("Is the number larger than %i (y/n): ",b);
getline(&line, &linelen, stdin);
sscanf(line, "%c", &ans);

switch(ans) {
    case 'y':
        ...
        break;
    case 'n':
        ...
        break;
    default:
        printf("I don't understand '%c', try again.\n", ans);
}

free(line);

Need Your Help

git lfs "objects" taking a lot of disk space

git github git-lfs

I have a project with a lot of binaries (mostly pdfs) that I'm using git-lfs with. The project is about 60mb but I found that my .git/lfs/objects director is about 500mb. I presume these are cached

How to create editable cart items

javascript angularjs shopping-cart javascript-objects

I'm building a shopping cart. My display object below is the data available to the shopper. The cart object is the representation of the shoppers selection in the cart. The problem I'm having is...