简体   繁体   中英

Confusing Format Error C Program fscanf

I'm creating a connect 4 game in C and part of the game is loading and saving game state.. the way that it is saved is through the chunk of code below

      if (strncmp (temp, "save", 5) == 0){

      int r, c;

      // this writes the game settings to a file
      int *rows = &num_rows;
      int *cols = &num_columns;
      int *len = &length_to_win;
      FILE *fp = fopen("gameSave.txt", "w+");
      fprintf(fp, "%d ", *rows);
      fprintf(fp, "%d ", *cols);
      fprintf(fp, "%d ", *len);
      fprintf(fp, "\n\n");

      for (r = 0; r < num_rows; r++) {
        for (c = 0; c < num_columns; c++) {
          fprintf(fp, "%c ", aPtr[r][c]);
          }
        fprintf(fp, "\n");
      }

      printf("Game Saved\n");
      fclose(fp);

  }

"temp" refers to user-input that normally is the column number that a player wishes to place their piece; however, if they enter "save," then it will execute this chunk of code and create a file that looks like this

cat gameSave.txt 
5 5 4 

0 1 0 1 0 
1 0 1 0 1 
0 1 0 1 0 
9 9 9 9 9 
9 9 9 9 9

the 5 5 4 refers to rows columns and length to win, and the 2D-array below it (which is separated by two \\n's) is the character representation of the board (they are indeed characters, not integers). SO my issue, is that I'm using this chunk of code below to load the save data mid-game

  if (strncmp (temp, "load", 5) == 0){

    int r, c;

    // this loads the game settings into game
    FILE *fp = fopen("gameSave.txt", "r");
    fscanf(fp, "%d %d %d", &num_rows, &num_columns, &length_to_win);
    fscanf(fp, "\n\n");

    aPtr = malloc(num_rows * sizeof(char*));

    for (i = 0; i < num_rows; i++){
        aPtr[i] = malloc(num_columns * sizeof (char));
    }

    for (r = 0; r < num_rows; r++) {
      for (c = 0; c < num_columns; c++) {
        fscanf(fp, "%c ", aPtr[r][c]);
      }
        fscanf(fp, "\n");
      }

    printf("Game Loaded\n");
    fclose(fp);
  }

this successfully loads the game-settings (rows, columns, and length to win); however, the lines of code that are supposed to load the actual game-state (below)

for (r = 0; r < num_rows; r++) {
  for (c = 0; c < num_columns; c++) {
    fscanf(fp, "%c ", aPtr[r][c]);
  }
    fscanf(fp, "\n");
  }

are giving me a warning, specifically the line

fscanf(fp, "%c ", aPtr[r][c]);

the warning is

"warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]"

this is confusing... because its essentially the exact same line of code used in the save block

fprintf(fp, "%c ", aPtr[r][c]);

and that doesn't give me any kind of problems... Any thoughts on what exactly is going on? If you care to run it yourself just comment out that load-code which is purposed to pull in the actual game-state. The full code is below:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>



void initialize(int num_rows, int num_cols, char **aPtr) {
    int i, r, c;


    for (r = 0; r < num_rows; r++) {
        for (c = 0; c < num_cols; c++) {
            aPtr[r][c] = '9';
        }
    }
}
// end of initialize


void printBoard(int num_rows, int num_columns, char **aPtr) {
    int row, col; 
  int r, c;

  for (r = 0; r < num_rows; r++) {
    for (c = 0; c < num_columns; c++) {
      printf("%c ", aPtr[r][c]);
    }
    printf("\n");
}

    printf("\n");
    puts("------ Connect *Four ------");
    puts("Connect X Command Line Game");

    // for fancy top of board frame
    printf("&&");
    for(col = 1; col < num_columns; col++) {
        printf("====");
    }
    printf("===");
    printf("&&\n");

    // for the rows/columns of the board
    for(row = num_rows - 1; row >= 0; row--){
        printf("|");
        for(col = 0; col < num_columns; col++){
            if(aPtr[row][col] == '0') {
                printf("| X ");
            }
            else if(aPtr[row][col] == '1') {
                printf("| O ");
            }
            else {
                printf("|   ");
            }      
        }
        puts("||");
    }

   // for fancy bottom of board frame
    printf("&&");
    for(col = 1; col < num_columns; col++) {
        printf("====");
    }
    printf("===");
    printf("&&\n");
    printf("  ");
    if (col < 100){
        for(col = 0; col < num_columns; col++) {
            if (col < 10) {
                printf(" %d  ", col + 1);
            }
            else {
                printf("%d  ", col + 1);
            }
        }
        puts("\n");
    }
}
// end of printBoard


/*Global var to hold the current winner value*/
char winnerVal = '0';

int checkFullBoard(int num_rows, int num_columns, char **aPtr) {
  for (int i = 0; i < num_columns; i++) {
    if (aPtr[num_rows - 1][i] == '9') {
      return 0;
    }
  }
  return 1;
}


/* 
 * Checks for the first avalible cell to insert token in given column.
 * NOTE: This fuction is designed based on row 0 being the bottom (lowest row of the board)
 * This means that tokens are inserted from row 0 upward. Based on your tests, this should not cause
 * any problems.
*/
int checkForColHeight(int num_rows, int num_columns, int column, char **aPtr) {
  for (int i = 0; i < num_rows; i++) {
    if (aPtr[i][column] == '9') {
      return i;
    }     
  }
  return -1;
}


int place_token(char player, int column, int num_rows, int num_columns, char **aPtr) {

  /*Check for invalid Parameters*/
  if(column > (num_columns - 1) || column < 0 || (player != '1' && player != '0') 
    || num_columns <= 0 || num_rows <= 0) {;
    return -1;
  } 

  int firstOpenRow = checkForColHeight(num_rows, num_columns, column, aPtr);
  if (firstOpenRow == -1) { 
    return -1;
  }else {
    aPtr[firstOpenRow][column] = player;
    return 1;
  }
}


char checkForSeries(int direction, int num_rows, int num_columns, int length_to_win, int r, int c, char **aPtr) {
  switch (direction) {
    /*Horizontal*/
    case 0:           
      for (int i = 1; i < length_to_win; i++) {
        if (aPtr[r][c] == '9' ) {
          return '2';
        }else if (aPtr[r][c] != aPtr[r][c + i] ) {
          return '2';
        }
      }
      return aPtr[r][c];
      break;      
    /*Vertical*/
    case 1: 
      for (int i = 1; i < length_to_win; i++) {
        if (aPtr[r][c] == '9' ) {
          return '2';
        }else if (aPtr[r][c] != aPtr[r + i][c] ) {
          return '2';
        }
      }
      return aPtr[r][c];     
      break;
    /*Left Diag*/
    case 2:
      for (int i = 1; i < length_to_win; i++) {
        if (aPtr[r][c] == '9' ) {
          return '2';
        }else if (aPtr[r][c] != aPtr[r + i][c - i] ) {
          return '2';
        }
      }
      return aPtr[r][c]; 
      break;
    /*Right Diag*/
    case 3:
      for (int i = 1; i < length_to_win; i++) {
        if (aPtr[r][c] == '9' ) {
          return '2';
        }else if (aPtr[r][c] != aPtr[r + i][c + i] ) {
          return '2';
        }
      }
      return aPtr[r][c]; 
      break;    
    return '2';
  }
  return '0';
}


/*Interate over each row and column. For each cell in the row, check for series of tokens*/
int checkHorizontal(int num_rows, int num_columns, int length_to_win, char **aPtr){  
  int r, c;
  for (r = 0; r < num_rows; r++) {    
    for(c = 0; c < num_columns - (length_to_win - 1); c++) {      
      char winner = checkForSeries(0, num_rows, num_columns, length_to_win, r, c, aPtr);
      if(winner != '2') {
        winnerVal = winner;       
        return 1;
      }     
    }
  }
  return 0;
}

/*Interate over each row and column. For each cell in the row, check for series of tokens*/
int checkVertical(int num_rows, int num_columns, int length_to_win, char **aPtr){  
  int r, c;
  for (c = 0; c < num_columns; c++) {   
    for(r = 0; r < num_rows - (length_to_win - 1); r++) {     
      char winner = checkForSeries(1, num_rows, num_columns, length_to_win, r, c, aPtr);
      if(winner != '2') {
        winnerVal = winner;       
        return 1;
      }     
    }
  }
  return 0;
}

/*Interate over each row and column. For each cell in the row, check for series of tokens*/
int checkDiagLeft(int num_rows, int num_columns, int length_to_win, char **aPtr){  
  int r, c;
  for (r = 0; r < num_rows - (length_to_win - 1); r++) {    
    for(c = num_columns - 1; c > (length_to_win - 2); c--) {      
      char winner = checkForSeries(2, num_rows, num_columns, length_to_win, r, c, aPtr);
      if(winner != '2') {
        winnerVal = winner;       
        return 1;
      }     
    }
  }
  return 0;
}

/*Interate over each row and column. For each cell in the row, check for series of tokens*/
int checkDiagRight(int num_rows, int num_columns, int length_to_win, char **aPtr){
  // printf("%s\n", "Check Right Diag: ");
  int r, c;
  for (r = 0; r < num_rows - (length_to_win - 1); r++) {
    // printf("%s", "Row #: ");
    // printf("%d\n", r);
    for(c = 0; c < num_columns - (length_to_win - 1); c++) {
      // printf("%s", "Col #: ");
      // printf("%d\n", c);
      char winner = checkForSeries(3, num_rows, num_columns, length_to_win, r, c, aPtr);
      if(winner != '2') {
        winnerVal = winner;
        // printf("%s", "Row Location: ");
        // printf("%d\n", r);
        // printf("%s", "Col Location: ");
        // printf("%d\n", c);
        return 1;
      }     
    }
  }
  return 0;
}


/*Return the integer representation of the winning player, -1 if a tie or error*/
char winner(int num_rows, int num_columns, int length_to_win, char **aPtr) {

  /*Check for invalid Parameters*/
  if (length_to_win <= 0 || length_to_win > num_columns || num_columns <= 0 || num_rows <= 0) {
    return '2';
  } 
  if (checkHorizontal(num_rows, num_columns, length_to_win, aPtr) 
    || checkVertical(num_rows, num_columns, length_to_win, aPtr)
    || checkDiagLeft(num_rows, num_columns, length_to_win, aPtr)
    || checkDiagRight(num_rows, num_columns, length_to_win, aPtr)
    ) {
    return winnerVal; 
  }
  if(checkFullBoard(num_rows, num_columns, aPtr)) {
    return '2';
  }
  return '2';
}


// *******************************************************************************************************
// *******************************************************************************************************

int main (int argc, char *argv[]) {

    setvbuf(stdout, NULL, _IONBF, 0);
    int num_rows = 7;
    int num_columns = 7;
    int length_to_win = 4;
    int i;
    int index;
    char **aPtr;
  // FILE *fp = fopen("test.txt", "r");

    printf("Starting Game\n");  



    // this loop checks for command line arguments and sets game variables accordingly.
    for(index = 0; index < argc; ++index) {

        if ( strncmp( argv[index], "-h", 5) == 0 ) {
            num_rows =atoi(argv[index + 1]);
        }
        if ( strncmp( argv[index], "-height", 5) == 0 ) {
            num_rows =atoi(argv[index + 1]);
        }
        if ( strncmp( argv[index], "-w", 5) == 0 ) {
            num_columns = atoi(argv[index + 1]);
        }
        if ( strncmp( argv[index], "-width", 5) == 0 ) {
            num_columns = atoi(argv[index + 1]);
        }
        if ( strncmp( argv[index], "-s", 5) == 0 ) {
            num_rows = atoi(argv[index + 1]);
            num_columns = atoi(argv[index + 1]);
        }
        if ( strncmp( argv[index], "-square", 5) == 0 ) {
            num_rows = atoi(argv[index + 1]);
            num_columns = atoi(argv[index + 1]);
        }
        if ( strncmp( argv[index], "-c", 5) == 0 ) {
            length_to_win = atoi(argv[index + 1]);
        }
        if ( strncmp( argv[index], "-connect", 5) == 0 ) {
            length_to_win = atoi(argv[index + 1]);
        }
    }


    // these conditionals check for valid board size
    if (num_rows <= 0 || num_columns <= 0 ){
        printf("%s\n","You entered a width or length that was invalid." );
    }
    if (length_to_win <= 0 || length_to_win > (num_rows - 1)) {
        printf("%s\n","You entered a winning length that was invalid." );
    }



    // create the space for the board
    aPtr = malloc(num_rows * sizeof(char*));

    for (i = 0; i < num_rows; i++){
        aPtr[i] = malloc(num_columns * sizeof (char));
    }

    initialize(num_rows, num_columns, aPtr);
  int answer;
  int attmpt;
  char player = '0';

  printf("%s\n", "*********************");
  printf("%s\n", "   Starting Board   ");
  printf("%s\n", "*********************");
  puts("\n");
  printBoard(num_rows, num_columns, aPtr);
  printf("Player: %cs Turn\n", player + 1); 
  puts("\n");



  /*Start game loop*/
  while(1) {       

      // prompts the user to select which column they want their piece to be placed
      // -1 on the temp because the first column is technically 0 so if a player
      // wants to place their piece in column "1", it'll be placed at index[0] accordingly
      printf("%s\n", "Enter Column # To Place Token"); 
      int column;
      char temp[20];
      char temp2[20];       
      scanf("%s", temp); 

      if (strncmp (temp, "save", 5) == 0){

          int r, c;

          // this writes the game settings to a file
          int *rows = &num_rows;
          int *cols = &num_columns;
          int *len = &length_to_win;
          FILE *fp = fopen("gameSave.txt", "w+");
          fprintf(fp, "%d ", *rows);
          fprintf(fp, "%d ", *cols);
          fprintf(fp, "%d ", *len);
          fprintf(fp, "\n\n");

          for (r = 0; r < num_rows; r++) {
            for (c = 0; c < num_columns; c++) {
              fprintf(fp, "%c ", aPtr[r][c]);
              }
            fprintf(fp, "\n");
          }

          printf("Game Saved\n");
          fclose(fp);

      }

      if (strncmp (temp, "load", 5) == 0){

        int r, c;

        // this loads the game settings into game
        FILE *fp = fopen("gameSave.txt", "r");
        fscanf(fp, "%d %d %d", &num_rows, &num_columns, &length_to_win);
        fscanf(fp, "\n\n");

        aPtr = malloc(num_rows * sizeof(char*));

        for (i = 0; i < num_rows; i++){
            aPtr[i] = malloc(num_columns * sizeof (char));
        }

        for (r = 0; r < num_rows; r++) {
          for (c = 0; c < num_columns; c++) {
            fscanf(fp, "%c ", aPtr[r][c]);
          }
            fscanf(fp, "\n");
          }

        printf("Game Loaded\n");
        fclose(fp);
      }


      column = atoi(temp) - 1;
      attmpt = place_token(player, column, num_rows, num_columns, aPtr);

      if ((column < 0 || column > (num_columns - 1)) && (strncmp (temp, "save", 5) != 0) && (strncmp (temp, "load", 5) != 0)) {
          printf("%s\n","You entered a column that was invalid. Please try again." );
          continue;
      }

      if (attmpt != 1 && (strncmp (temp, "save", 5) != 0) && (strncmp (temp, "load", 5) != 0)) {
          printf("%s\n","This row is already full. Please try again." );
          continue;
      }

      printf("%s\n", "************************");
      printf("%s\n", "      Board Updated     ");
      printf("%s\n", "************************");  
      puts("\n");  
      printBoard(num_rows, num_columns, aPtr);
      puts("\n");



      if ((strncmp (temp, "save", 5) != 0) && (strncmp (temp, "load", 5) != 0)) {
          if (checkFullBoard(num_rows, num_columns, aPtr)) {
              printf("%s\n","This game is a tie. Thanks for Playing.\n");
              return 0;
            }
      }

      // this if-statement will constantly be run while the game progresses, 
      // meaning that winner will be called at every turn and 
      // all of the win conditions will be checked until a winner is found
      char isWin = winner(num_rows, num_columns, length_to_win, aPtr);
      if(isWin != '2') {
          printf("Player: %c is the winner! Thanks for Playing.\n", isWin + 1);
          printf("Play again? (enter 'y' to continue)\n");
          scanf("%s", temp2);

          if (strncmp (temp2, "y", 5) == 0){
            initialize(num_rows, num_columns, aPtr);
            printBoard(num_rows, num_columns, aPtr);
            puts("\n");
          }
          else {
            printf("Game over, goodbye!\n");
            return 0;
          }
      }

      // if a winner is not found then this if/else will continue to switch
      // between players at the end of each turn
      if ((strncmp (temp, "save", 5) != 0) && (strncmp (temp, "load", 5) != 0) && (strncmp (temp2, "y", 5) != 0)) {
          if (player == '1') {
            player = '0';
        }
          else {
              player = '1';
          }
      }
      memset(temp, 0, sizeof temp);
      memset(temp2, 0, sizeof temp2);

      printf("Player: %cs Turn\n", player +1);
  } // end of while loop


    return 0;
}
fscanf(fp, "%c ", aPtr[r][c]);

should be:

fscanf(fp, " %c", &aPtr[r][c]);

Put a space before %c so that you skip over the newline and any other whitespace before reading a character. And you have to give a pointer to the array element to store into.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM