Kesalahan Format Membingungkan Program C fscanf

Saya membuat game connect 4 di C dan sebagian dari game tersebut sedang memuat dan menyimpan status game.. cara menyimpannya adalah melalui potongan kode di bawah ini

      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" mengacu pada input pengguna yang biasanya berupa nomor kolom yang diinginkan pemain untuk meletakkan bidaknya; namun, jika mereka memasukkan "simpan", potongan kode ini akan dieksekusi dan membuat file seperti ini

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

5 5 4 mengacu pada baris kolom dan panjang untuk menang, dan array 2D di bawahnya (yang dipisahkan oleh dua \n) adalah representasi karakter papan (mereka memang karakter, bukan bilangan bulat). JADI masalah saya, adalah saya menggunakan potongan kode di bawah ini untuk memuat data simpanan di tengah permainan

  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);
  }

ini berhasil memuat pengaturan permainan (baris, kolom, dan panjang untuk menang); namun, baris kode yang seharusnya memuat status permainan sebenarnya (di bawah)

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

memberi saya peringatan, khususnya salurannya

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

peringatannya adalah

"peringatan: format menentukan tipe 'char *' tetapi argumennya memiliki tipe 'int' [-Wformat]"

ini membingungkan... karena pada dasarnya baris kodenya sama persis dengan yang digunakan di blok penyimpanan

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

dan itu tidak memberi saya masalah apa pun... Adakah pemikiran tentang apa yang sebenarnya terjadi? Jika Anda ingin menjalankannya sendiri, cukup beri komentar pada kode pemuatan yang dimaksudkan untuk menarik status permainan yang sebenarnya. Kode lengkapnya ada di bawah ini:

#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;
}

person Pig_Mug    schedule 06.03.2017    source sumber
comment
Ubah fscanf(fp, "%c ", aPtr[r][c]); menjadi fscanf(fp, " %c", &aPtr[r][c]); -- beri spasi sebelum %c dan Anda perlu memberi penunjuk ke fscanf().   -  person Barmar    schedule 06.03.2017
comment
@Barmar ahh, begitu. Terima kasih atas penemuannya.   -  person Pig_Mug    schedule 06.03.2017


Jawaban (1)


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

seharusnya:

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

Beri spasi sebelum %c sehingga Anda melewati baris baru dan spasi lainnya sebelum membaca karakter. Dan Anda harus memberikan pointer ke elemen array untuk disimpan.

person Barmar    schedule 06.03.2017