user2640115
user2640115

Reputation: 1

Using fgets and sscanf in C messed up the program after loop

I'm programming a tic tac toe game in C.

Everything seems to be going okay, but I like to implement error handling techniques for programs like this in case a user inputs bad data.

I ask the user to input a number between 1-9 to fill a slot on the tic tac toe graph. When I used fgets and sscanf together, it ran well during the first game. Then, when a user selected 'Y' or 'y' to continue playing a new game, it seemed as if none of the variable values refreshed, and it was basically causing chaos within the program.

Any tips?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
int printmatch(int array[3][3]);
int check(int array[3][3]);
char y;
char Y;
int complacer = 0;
int complacer2 = 0;

int main()
{
  do
  {

    int fill = 0;
    int j = 0;
    int slot = 0;
    int array[3][3];
    array[0][0] = 0;
    array[0][1] = 0;
    array[0][2] = 0;
    array[1][0] = 0;
    array[2][0] = 0;
    array[1][1] = 0;
    array[2][1] = 0;
    array[1][2] = 0;
    array[2][2] = 0;
    srand(time(NULL ));
    printmatch(array);
    char line[20];

    do
    {
      do
      {
        tryagain: printf("\nEnter Position 1-9(from left to right):");

        //I was using fgets and sscanf as an error handling technique incase user inputs incompatible data type, but after the 1st game is over, it seems this code messes up the functionality of the program
        //fgets(line,sizeof(line),stdin);
        //sscanf(line,"%d",&slot);

        //when I just use scanf for data input, all is fine, but limited error handling
        scanf("%d", &slot);
        if (slot > 9 || slot < 1)
        {
          printf("Incorrect data input! Try again. \n");
        }

      } while (!(slot > 0 && slot < 10));

      switch (slot)
      {
      case 1:
        if (array[0][0] == -1)
        {
          printf("\nWoops, try again!");
          goto tryagain;
        }
        array[0][0] = 1;
        check(array);
        break;
      case 2:
        if (array[1][0] == -1)
        {
          printf("\nWoops, try again!");
          goto tryagain;
        }
        array[1][0] = 1;
        check(array);
        break;
      case 3:
        if (array[2][0] == -1)
        {
          printf("\nWoops, try again!");
          goto tryagain;
        }
        array[2][0] = 1;
        check(array);
        break;
      case 4:
        if (array[0][1] == -1)
        {
          printf("\nWoops, try again!");
          goto tryagain;
        }
        array[0][1] = 1;
        check(array);
        break;
      case 5:
        if (array[1][1] == -1)
        {
          printf("\nWoops, try again!");
          goto tryagain;
        }
        array[1][1] = 1;
        check(array);
        break;
      case 6:
        if (array[2][1] == -1)
        {
          printf("\nWoops, try again!");
          goto tryagain;
        }
        array[2][1] = 1;
        check(array);
        break;
      case 7:
        if (array[0][2] == -1)
        {
          printf("\nWoops, try again!");
          goto tryagain;
        }
        array[0][2] = 1;
        check(array);
        break;
      case 8:
        if (array[1][2] == -1)
        {
          printf("\nWoops, try again!");
          goto tryagain;
        }
        array[1][2] = 1;
        check(array);
        break;
      case 9:
        if (array[2][2] == -1)
        {
          printf("\nWoops, try again!");
          goto tryagain;
        }
        array[2][2] = 1;
        check(array);
        break;

      }

      if (array[0][0] != 0 && array[0][1] != 0 && array[0][2] != 0
          && array[1][0] != 0 && array[2][0] != 0 && array[1][1] != 0
          && array[2][1] != 0 && array[1][2] != 0 && array[2][2] != 0)
      {
        check(array);

        if (check(array) == 1)
        {
          printf("The user wins!\n");
        }

        else if (check(array) == -1)
        {
          printf("The computer wins.\n");
        }

        else
        {
          printmatch(array);
          printf("It's a draw!\n");
        }

        goto done;
      }
      ++fill;
      label:

      complacer = rand() % 3;
      complacer2 = rand() % 3;

      if (array[complacer][complacer2] == 0)
      {
        array[complacer][complacer2] = -1;
        check(array);
      }

      else
        goto label;

      ++fill;

      printmatch(array);
      int fullcheck = check(array);
      if (fullcheck == 1)
      {
        printf("The user wins!");
        break;
      }

      if (fullcheck == -1)
      {
        printf("The computer wins.");
        break;
      }

      if (fill > 9)
        break;
    } while (fill < 10);
    done: printf("\nDo you want to continue? Y/N\n");
    scanf("%c %c", &y, &Y);
  } while ((Y == 'Y' || Y == 'y'));
  getchar();
  return 0;

}
int printmatch(int array[3][3])
{

  int i;
  int j;
  for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 3; j++)
    {
      printf("%d\t", array[j][i]);
    }

    printf("\n");

  }
}

int check(int array[3][3])
{
  int settle;

  if (array[0][0] == 1 && array[1][1] == 1 && array[2][2] == 1)
  {
    settle = 1;

  }

  else if (array[0][0] == -1 && array[1][1] == -1 && array[2][2] == -1)
  {

    settle = -1;

  }

  if (array[0][0] == 1 && array[0][1] == 1 && array[0][2] == 1)
  {
    settle = 1;

  }
  else if (array[0][0] == -1 && array[0][1] == -1 && array[0][2] == -1)
  {

    settle = -1;

  }

  if (array[0][2] == 1 && array[1][2] == 1 && array[2][2] == 1)
  {
    settle = 1;

  }
  else if (array[0][2] == -1 && array[1][2] == -1 && array[2][2] == -1)
  {

    settle = -1;

  }

  if (array[0][1] == 1 && array[1][1] == 1 && array[2][1] == 1)
  {
    settle = 1;

  }
  else if (array[0][1] == -1 && array[1][1] == -1 && array[2][1] == -1)
  {

    settle = -1;

  }

  if (array[1][0] == 1 && array[1][1] == 1 && array[1][2] == 1)
  {
    settle = 1;

  }
  else if (array[1][0] == -1 && array[1][1] == -1 && array[1][2] == -1)
  {
    settle = -1;

  }

  if (array[0][0] == 1 && array[1][0] == 1 && array[2][0] == 1)
  {
    settle = 1;

  }
  else if (array[1][0] == -1 && array[1][1] == -1 && array[1][2] == -1)
  {
    settle = -1;

  }

  if (array[2][0] == 1 && array[1][1] == 1 && array[0][2] == 1)
  {
    settle = 1;

  }
  else if (array[1][0] == -1 && array[1][1] == -1 && array[1][2] == -1)
  {
    settle = -1;

  }
  if (array[2][0] == 1 && array[2][1] == 1 && array[2][2] == 1)
  {
    settle = 1;

  }

  else if (array[2][0] == -1 && array[2][1] == -1 && array[2][2] == 1)
  {
    settle = -1;

  }
  return settle;
}

Upvotes: 0

Views: 1188

Answers (1)

chux
chux

Reputation: 153498

User input is evil. When you want a number, someone types 'A'. You want a 'y' or 'n' and you get a input of dozens of letters. Kudos for trying to improve your coding with defensive error handling.

When using sscanf() or scanf(), etc., be sure to check the results

int result;  
result = sscanf(buffer, "%this %that ...", &var1);  
if (result != ExpectedResult) // handle error

Mixing fgets() with getchar() and scanf() is likely to confuse the issue. Recommend not using fgets() with those 2. fgets() is line orientated, scanf() often stops before consuming the new-line.

Its fun to only type a 'Y' or 'y' to continue, but using a "letter & enter_key" combo is not so bad and it is easier to sort out at first.

The fgets() sscanf() pair may have caused a hiccup, but in the end it easier to sort out. Recommend returning to that style and checking the result of the sscanf().

Example

scanf("%d", &slot);

Here you do not know if the user typed any number before pressing 'Enter'. Even is the user did type a number, your scanf() consumes the leading spaces and the digits, but leaves the 'Enter' for the next input function. Instead:

int ScanCount;
const char *prompt = "\nEnter Position 1-9(from left to right):";
do {
  fputs(prompt, stdout);
  prompt = "Incorrect data input! Try again. \n"; // For the maybe next time around
  if (fgets(line, sizeof(line), stdin) == NULL) {
    // Standard input is closed or some grievous I/O error, let's go home.
    return 0;
  }
  ScanCount = sscanf(line,"%d",&slot);
} while ((ScanCount != 1) || (slot < 1) || slot > 9));

BTW: Here is a little trick to test if extra text was entered after a number like "9z". Replace ScanCount = ... slot > 9)); with

char c;
ScanCount = sscanf(line,"%d%[^\n]",&slot, &c);
} while ((ScanCount != 1) || (slot < 1) || slot > 9));  // still ScanCount != 1

Upvotes: 1

Related Questions