独立代码块有效,但函数调用 WITH/相同代码无效(C 程序)
Standalone Code-Block Works, But Function Call W/ Same Code Does Not (C Program)
我正在制作一个 connect 4 游戏。一切正常,当您在启动时使用
加载游戏
"./a.out -l"
如果下面的这段代码处于检查该标志的条件中
int r, c, i;
// this loads the game settings into game
FILE *fp = fopen("gameSave.txt", "r");
fscanf(fp, "%d %d %d %c", &num_rows, &num_columns, &length_to_win, &player);
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]);
printf("%c ", aPtr[r][c]);
}
fscanf(fp, "\n");
printf("\n");
}
printf("Game Loaded\n");
fclose(fp);
它工作得很好,在这个条件之后我调用函数 printBoard() 并得到以下输出
Starting Game
0 1 0 9 9 9 9
0 1 9 9 9 9 9
0 1 9 9 9 9 9
9 9 9 9 9 9 9
9 9 9 9 9 9 9
9 9 9 9 9 9 9
9 9 9 9 9 9 9
Game Loaded
*********************
Starting Board
*********************
------ Connect *Four ------
Connect X Command Line Game
&&===========================&&
|| | | | | | | ||
|| | | | | | | ||
|| | | | | | | ||
|| | | | | | | ||
|| X | O | | | | | ||
|| X | O | | | | | ||
|| X | O | X | | | | ||
&&===========================&&
1 2 3 4 5 6 7
Player: 2s Turn
Enter Column # To Place Token
然后我就可以按预期玩游戏并且一切正常。但是,如果我将相同的代码块放入如下函数中
void loadGame(int num_rows, int num_columns, int length_to_win, char player, char **aPtr){
int r, c, i;
// this loads the game settings into game
FILE *fp = fopen("gameSave.txt", "r");
fscanf(fp, "%d %d %d %c", &num_rows, &num_columns, &length_to_win, &player);
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]);
printf("%c ", aPtr[r][c]);
}
fscanf(fp, "\n");
printf("\n");
}
printf("Game Loaded\n");
printBoard(num_rows, num_columns, aPtr);
fclose(fp);
}
然后在条件语句中注释掉相同的代码,只留下以下内容
load = true;
loadGame(num_rows, num_columns, length_to_win, player, aPtr);
它给了我这个输出
Starting Game
0 1 0 9 9 9 9
0 1 9 9 9 9 9
0 1 9 9 9 9 9
9 9 9 9 9 9 9
9 9 9 9 9 9 9
9 9 9 9 9 9 9
9 9 9 9 9 9 9
Game Loaded
*********************
Starting Board
*********************
------ Connect *Four ------
Connect X Command Line Game
&&===========================&&
|| | | | | | | ||
|Segmentation fault: 11
我不确定为什么...这意味着在创建板可视化的 for 循环中存在某种问题...可能是范围问题(也许行数或列数)?创建板的函数如下所示
void printBoard(int num_rows, int num_columns, char **aPtr) {
int row, col;
int r, c;
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 the board is less than 100 columns,
// print the column number (for readability)
if (col < 100){
for(col = 0; col < num_columns; col++) {
if (col < 10) {
printf(" %d ", col + 1);
}
else {
printf("%d ", col + 1);
}
}
puts("\n");
}
}
任何关于为什么会发生这种情况的建议将不胜感激,如果您想 运行 自己的代码,所有代码都在下面
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <stdbool.h>
// This is where the default board gets created
// The reasoning behind setting all values = '9'
// is that when a player places their piece on the board
// the location of that piece will then become their
// player number, which is used accordingly when
// saving and loading the game
void initialize(int num_rows, int num_cols, char **aPtr) {
int r, c;
for (r = 0; r < num_rows; r++) {
for (c = 0; c < num_cols; c++) {
aPtr[r][c] = '9';
}
}
}
// end of initialize
// this is where the board gets printed according to its
// state (whether default-starting, game in progress, or
// loaded game). It looks at the values of the 2D array
// and depending on whether or not they are default 9's or
// player numbers, prints out the appropriate illustration
void printBoard(int num_rows, int num_columns, char **aPtr) {
int row, col;
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 the board is less than 100 columns,
// print the column number (for readability)
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
// This is a global variable used to signify the state of
// whether or not there is a winner
char winnerVal = '0';
// this checks if the board is full or not to check for a win or tie
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;
}
// this checks for the first available location within a column for players
// to place their pieces, if there is no available space in a column, it returns
// -1 which signals the player that they must adjust their placement
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;
}
// this is where a token is placed at an appropriate position if it is within the
// allowances of the game
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;
}
}
// this is where a check for a win occurs. Essentially until it finds a line long enough to win it'll return negative
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';
}
// end of checkForSeries
// checks for any horizontal wins
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;
}
// checks for any vertical wins
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;
}
// checks for any left-diagonal wins
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;
}
// checks for any right-diagonal wins
int checkDiagRight(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 = 0; c < num_columns - (length_to_win - 1); c++) {
char winner = checkForSeries(3, num_rows, num_columns, length_to_win, r, c, aPtr);
if(winner != '2') {
winnerVal = winner;
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) {
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';
}
char **loadGame(int num_rows, int num_columns, int length_to_win, char player, char **aPtr){
int r, c, i;
// this loads the game settings into game
FILE *fp = fopen("gameSave.txt", "r");
fscanf(fp, "%d %d %d %c", &num_rows, &num_columns, &length_to_win, &player);
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]);
printf("%c ", aPtr[r][c]);
}
fscanf(fp, "\n");
printf("\n");
}
return aPtr;
printf("Game Loaded\n");
fclose(fp);
}
// END OF FUNCTIONS
// *******************************************************************************************************
// *******************************************************************************************************
// START OF MAIN METHOD
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, index, attmpt;
char **aPtr;
char player = '0';
bool load = false;
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]);
}
if ( strncmp( argv[index], "-l", 5) == 0 ) {
load = true;
aPtr = loadGame(num_rows, num_columns, length_to_win, player, aPtr);
// int r, c;
// this loads the game settings into game
// FILE *fp = fopen("gameSave.txt", "r");
// fscanf(fp, "%d %d %d %c", &num_rows, &num_columns, &length_to_win, &player);
// 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]);
// printf("%c ", aPtr[r][c]);
// }
// fscanf(fp, "\n");
// printf("\n");
// }
// printf("Game Loaded\n");
// fclose(fp);
}
}
// these conditionals check for valid board size
if (num_rows <= 2 || num_columns <= 2 ){
printf("%s\n","You entered a width or length that was invalid." );
}
if (length_to_win <= 2 || length_to_win > (num_rows - 1)) {
printf("%s\n","You entered a winning length that was invalid." );
}
// if the game isn't loaded upon execution, the load it normally
if (load == false) {
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);
}
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");
// this is the loop that runs while the game is in progress
// it continually checks for winners, full boards, valid moves, etc.
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 called "gameSave.txt"
// if the file doesn't exist it just creates it
int *rows = &num_rows;
int *cols = &num_columns;
int *len = &length_to_win;
char *play = &player;
FILE *fp = fopen("gameSave.txt", "w+");
fprintf(fp, "%d ", *rows);
fprintf(fp, "%d ", *cols);
fprintf(fp, "%d ", *len);
fprintf(fp, "%c ", *play);
fprintf(fp, "\n\n");
// this loop saves the actual board state to the file
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 %c", &num_rows, &num_columns, &length_to_win, &player);
fscanf(fp, "\n\n");
// this creates space for the loaded game
aPtr = malloc(num_rows * sizeof(char*));
for (i = 0; i < num_rows; i++){
aPtr[i] = malloc(num_columns * sizeof (char));
}
// this fills the board with the saved game-data
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");
printf("Or load a previously saved game with 'load'\n");
scanf("%s", temp2);
// if the player wants to play again, clear the board for a new game
// and start over
if (strncmp (temp2, "y", 5) == 0){
initialize(num_rows, num_columns, aPtr);
printBoard(num_rows, num_columns, aPtr);
puts("\n");
}
if (strncmp (temp2, "load", 5) == 0) {
int r, c;
// this loads the game settings into game
FILE *fp = fopen("gameSave.txt", "r");
fscanf(fp, "%d %d %d %c", &num_rows, &num_columns, &length_to_win, &player);
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]);
printf("%c ", aPtr[r][c]);
}
fscanf(fp, "\n");
printf("\n");
}
printf("Game Loaded\n");
puts("\n");
printBoard(num_rows, num_columns, aPtr);
fclose(fp);
}
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;
}
首先,您的问题有点笨拙,请查看评论中@Michael 提供的指南。
现在,据我了解,问题是您在调用函数 loadGame(...) 时传递的是变量的值,而不是对它们的引用。函数未修改变量 num_rows、num_columns、length_to_win 和其他变量。
看看这个例子:
void wrong (int a, int b, int c) {
a = 1;
b = 2;
c = 3;
}
void correct (int *a, int *b, int *c) {
*a = 1;
*b = 2;
*c = 3;
}
int main(int argc, const char * argv[]) {
int a, b, c;
a = b = c = -1;
/*
Not modified after function call.
*/
wrong(a, b, c);
printf("wrong a: %i b: %i c: %i\n", a, b, c);
/*
Modified after function call.
*/
correct(&a, &b, &c);
printf("correct a: %i b: %i c: %i\n", a, b, c);
return 0;
}
我正在制作一个 connect 4 游戏。一切正常,当您在启动时使用
加载游戏"./a.out -l"
如果下面的这段代码处于检查该标志的条件中
int r, c, i;
// this loads the game settings into game
FILE *fp = fopen("gameSave.txt", "r");
fscanf(fp, "%d %d %d %c", &num_rows, &num_columns, &length_to_win, &player);
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]);
printf("%c ", aPtr[r][c]);
}
fscanf(fp, "\n");
printf("\n");
}
printf("Game Loaded\n");
fclose(fp);
它工作得很好,在这个条件之后我调用函数 printBoard() 并得到以下输出
Starting Game
0 1 0 9 9 9 9
0 1 9 9 9 9 9
0 1 9 9 9 9 9
9 9 9 9 9 9 9
9 9 9 9 9 9 9
9 9 9 9 9 9 9
9 9 9 9 9 9 9
Game Loaded
*********************
Starting Board
*********************
------ Connect *Four ------
Connect X Command Line Game
&&===========================&&
|| | | | | | | ||
|| | | | | | | ||
|| | | | | | | ||
|| | | | | | | ||
|| X | O | | | | | ||
|| X | O | | | | | ||
|| X | O | X | | | | ||
&&===========================&&
1 2 3 4 5 6 7
Player: 2s Turn
Enter Column # To Place Token
然后我就可以按预期玩游戏并且一切正常。但是,如果我将相同的代码块放入如下函数中
void loadGame(int num_rows, int num_columns, int length_to_win, char player, char **aPtr){
int r, c, i;
// this loads the game settings into game
FILE *fp = fopen("gameSave.txt", "r");
fscanf(fp, "%d %d %d %c", &num_rows, &num_columns, &length_to_win, &player);
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]);
printf("%c ", aPtr[r][c]);
}
fscanf(fp, "\n");
printf("\n");
}
printf("Game Loaded\n");
printBoard(num_rows, num_columns, aPtr);
fclose(fp);
}
然后在条件语句中注释掉相同的代码,只留下以下内容
load = true;
loadGame(num_rows, num_columns, length_to_win, player, aPtr);
它给了我这个输出
Starting Game
0 1 0 9 9 9 9
0 1 9 9 9 9 9
0 1 9 9 9 9 9
9 9 9 9 9 9 9
9 9 9 9 9 9 9
9 9 9 9 9 9 9
9 9 9 9 9 9 9
Game Loaded
*********************
Starting Board
*********************
------ Connect *Four ------
Connect X Command Line Game
&&===========================&&
|| | | | | | | ||
|Segmentation fault: 11
我不确定为什么...这意味着在创建板可视化的 for 循环中存在某种问题...可能是范围问题(也许行数或列数)?创建板的函数如下所示
void printBoard(int num_rows, int num_columns, char **aPtr) {
int row, col;
int r, c;
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 the board is less than 100 columns,
// print the column number (for readability)
if (col < 100){
for(col = 0; col < num_columns; col++) {
if (col < 10) {
printf(" %d ", col + 1);
}
else {
printf("%d ", col + 1);
}
}
puts("\n");
}
}
任何关于为什么会发生这种情况的建议将不胜感激,如果您想 运行 自己的代码,所有代码都在下面
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <stdbool.h>
// This is where the default board gets created
// The reasoning behind setting all values = '9'
// is that when a player places their piece on the board
// the location of that piece will then become their
// player number, which is used accordingly when
// saving and loading the game
void initialize(int num_rows, int num_cols, char **aPtr) {
int r, c;
for (r = 0; r < num_rows; r++) {
for (c = 0; c < num_cols; c++) {
aPtr[r][c] = '9';
}
}
}
// end of initialize
// this is where the board gets printed according to its
// state (whether default-starting, game in progress, or
// loaded game). It looks at the values of the 2D array
// and depending on whether or not they are default 9's or
// player numbers, prints out the appropriate illustration
void printBoard(int num_rows, int num_columns, char **aPtr) {
int row, col;
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 the board is less than 100 columns,
// print the column number (for readability)
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
// This is a global variable used to signify the state of
// whether or not there is a winner
char winnerVal = '0';
// this checks if the board is full or not to check for a win or tie
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;
}
// this checks for the first available location within a column for players
// to place their pieces, if there is no available space in a column, it returns
// -1 which signals the player that they must adjust their placement
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;
}
// this is where a token is placed at an appropriate position if it is within the
// allowances of the game
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;
}
}
// this is where a check for a win occurs. Essentially until it finds a line long enough to win it'll return negative
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';
}
// end of checkForSeries
// checks for any horizontal wins
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;
}
// checks for any vertical wins
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;
}
// checks for any left-diagonal wins
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;
}
// checks for any right-diagonal wins
int checkDiagRight(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 = 0; c < num_columns - (length_to_win - 1); c++) {
char winner = checkForSeries(3, num_rows, num_columns, length_to_win, r, c, aPtr);
if(winner != '2') {
winnerVal = winner;
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) {
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';
}
char **loadGame(int num_rows, int num_columns, int length_to_win, char player, char **aPtr){
int r, c, i;
// this loads the game settings into game
FILE *fp = fopen("gameSave.txt", "r");
fscanf(fp, "%d %d %d %c", &num_rows, &num_columns, &length_to_win, &player);
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]);
printf("%c ", aPtr[r][c]);
}
fscanf(fp, "\n");
printf("\n");
}
return aPtr;
printf("Game Loaded\n");
fclose(fp);
}
// END OF FUNCTIONS
// *******************************************************************************************************
// *******************************************************************************************************
// START OF MAIN METHOD
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, index, attmpt;
char **aPtr;
char player = '0';
bool load = false;
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]);
}
if ( strncmp( argv[index], "-l", 5) == 0 ) {
load = true;
aPtr = loadGame(num_rows, num_columns, length_to_win, player, aPtr);
// int r, c;
// this loads the game settings into game
// FILE *fp = fopen("gameSave.txt", "r");
// fscanf(fp, "%d %d %d %c", &num_rows, &num_columns, &length_to_win, &player);
// 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]);
// printf("%c ", aPtr[r][c]);
// }
// fscanf(fp, "\n");
// printf("\n");
// }
// printf("Game Loaded\n");
// fclose(fp);
}
}
// these conditionals check for valid board size
if (num_rows <= 2 || num_columns <= 2 ){
printf("%s\n","You entered a width or length that was invalid." );
}
if (length_to_win <= 2 || length_to_win > (num_rows - 1)) {
printf("%s\n","You entered a winning length that was invalid." );
}
// if the game isn't loaded upon execution, the load it normally
if (load == false) {
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);
}
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");
// this is the loop that runs while the game is in progress
// it continually checks for winners, full boards, valid moves, etc.
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 called "gameSave.txt"
// if the file doesn't exist it just creates it
int *rows = &num_rows;
int *cols = &num_columns;
int *len = &length_to_win;
char *play = &player;
FILE *fp = fopen("gameSave.txt", "w+");
fprintf(fp, "%d ", *rows);
fprintf(fp, "%d ", *cols);
fprintf(fp, "%d ", *len);
fprintf(fp, "%c ", *play);
fprintf(fp, "\n\n");
// this loop saves the actual board state to the file
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 %c", &num_rows, &num_columns, &length_to_win, &player);
fscanf(fp, "\n\n");
// this creates space for the loaded game
aPtr = malloc(num_rows * sizeof(char*));
for (i = 0; i < num_rows; i++){
aPtr[i] = malloc(num_columns * sizeof (char));
}
// this fills the board with the saved game-data
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");
printf("Or load a previously saved game with 'load'\n");
scanf("%s", temp2);
// if the player wants to play again, clear the board for a new game
// and start over
if (strncmp (temp2, "y", 5) == 0){
initialize(num_rows, num_columns, aPtr);
printBoard(num_rows, num_columns, aPtr);
puts("\n");
}
if (strncmp (temp2, "load", 5) == 0) {
int r, c;
// this loads the game settings into game
FILE *fp = fopen("gameSave.txt", "r");
fscanf(fp, "%d %d %d %c", &num_rows, &num_columns, &length_to_win, &player);
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]);
printf("%c ", aPtr[r][c]);
}
fscanf(fp, "\n");
printf("\n");
}
printf("Game Loaded\n");
puts("\n");
printBoard(num_rows, num_columns, aPtr);
fclose(fp);
}
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;
}
首先,您的问题有点笨拙,请查看评论中@Michael 提供的指南。
现在,据我了解,问题是您在调用函数 loadGame(...) 时传递的是变量的值,而不是对它们的引用。函数未修改变量 num_rows、num_columns、length_to_win 和其他变量。
看看这个例子:
void wrong (int a, int b, int c) {
a = 1;
b = 2;
c = 3;
}
void correct (int *a, int *b, int *c) {
*a = 1;
*b = 2;
*c = 3;
}
int main(int argc, const char * argv[]) {
int a, b, c;
a = b = c = -1;
/*
Not modified after function call.
*/
wrong(a, b, c);
printf("wrong a: %i b: %i c: %i\n", a, b, c);
/*
Modified after function call.
*/
correct(&a, &b, &c);
printf("correct a: %i b: %i c: %i\n", a, b, c);
return 0;
}