将井字棋代码拆分至.c和.h文件后编译失败求助
井字棋游戏编译问题排查
我开发了一个井字棋(tic tac toe)游戏,尝试将函数拆分到.c和.h文件中,但出现编译错误无法运行。排查后仍未解决,不确定错误来自代码本身还是GCC编译命令。
代码文件
1. game.c(含main函数)
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <unistd.h> #include "ready.h" #include "game.h" int play_tictactoe(int board_sz, int computer_enabled ); int main(int argc, char **argv) { int opt; int board_sz = 3; int computer_enabled; srand(time(NULL)); // Parse command line arguments using getopt() while ((opt = getopt(argc, argv, "s:i")) != -1) { switch (opt) { case 's': board_sz = atoi(optarg); break; case 'i': computer_enabled = 1; break; default: break; } } play_tictactoe(board_sz, computer_enabled); return 0; } int play_tictactoe(int board_sz, int computer_enabled ){ char **Board = create_board(board_sz); char winner = '\0'; char row; char col; char turn = 'X'; // standard game loop while (!winner && !is_draw(Board, board_sz)) { print_board(Board, board_sz); if (turn == 'X' || !computer_enabled) { printf("computer 'O' Moves are 'enabled'\n"); printf("-Player's %c turn (qq to quit)\n\n", turn); // suggestion do { row = rand() % board_sz + 'a'; // col = rand() % board_sz + '0'; } while (Board[row - 'a'][col - '1'] != ' '); printf("*---> suggestion:\t(%c %c)\n\n", row, col); printf("(X) Enter Move (row column) ---------------------------> "); fflush(stdout); scanf(" %c %c", &row, &col); // quit when enter qq. if (row == 'q' && col == 'q'){ exit(0); } } else { printf("computer 'O' Moves are 'enabled'\n"); printf("*Player's O turn (qq to quit)\n\n\n"); // Randomly pick a move do { row = rand() % board_sz + 'a'; // col = rand() % board_sz + '0'; } while (Board[row - 'a'][col - '1'] != ' '); printf("(O) computer Picks (%c %c) (hit a key to continue) ----> ", row, col); } // Make move if square is free int rowind = row - 'a'; int colind = col - '0'; if (rowind >= board_sz || colind >= board_sz) { printf("Invalid move\n"); } else if (Board[rowind][colind] == ' ') { char enter; enter = getchar(); printf("Move is %c %c (%d, %d)\n", row, col, rowind, colind); Board[rowind][colind] = turn; if (turn == 'X') { turn = 'O'; } else { turn = 'X'; } winner = winning_move(Board, board_sz, rowind, colind); } else { printf("Square is occupied; try again.\n"); } } // Game over - print Board & declare finish print_board(Board, board_sz); if (winner == 'X' || winner == 'O') { printf("Congratulations %c!\n", winner); } else { printf("Game ends in a draw.\n"); } return 0; }
2. ready.c(工具函数实现)
#include "ready.h" #include "game.h" #include <stdio.h> #include <stdlib.h> // malloc #include <time.h> // srand #include <unistd.h> // optarg // Creates nxn tic tac toe Board char **create_board(int board_sz) { char **Board = (char **)malloc(board_sz * sizeof(char *)); for (int i = 0; i < board_sz; i++) { Board[i] = (char *)malloc(board_sz * sizeof(char)); } for (int i = 0; i < board_sz; i++) { for (int j = 0; j < board_sz; j++) { Board[i][j] = ' '; } } return Board; } // Prints the Board void print_board(char **Board, int board_sz) { printf(" "); for (int i = 0; i < board_sz; i++) { printf("|%d", i); // column } printf("|\n"); for (int i = 0; i < board_sz; i++) { printf("%c", 'a' + i); // row for (int j = 0; j < board_sz; j++) { printf("|%c", Board[i][j]); // index for each square } printf("|\n"); } } // Returns true if the game is a draw int is_draw(char **Board, int board_sz) { for (int i = 0; i < board_sz; i++) { for (int j = 0; j < board_sz; j++) { if (Board[i][j] == ' ') { // empty square, so game ain't over yet return 0; } } } // no empty squares, so it's a draw return 1; } // Returns 'X' if (i,j) was a winning move for X // Returns 'O' if (i,j) was a winning move for O // Returns ASCII value 0 otherwise char winning_move(char **Board, int board_sz, int row_index, int col_index) { int win = 1; // check row for (int k = 0; k < board_sz; k++) { if (Board[row_index][k] != Board[row_index][col_index]) { win = 0; break; } } if (win) // means Board[i][k] == Board[i][j] { return Board[row_index][col_index]; } // check column win = 1; for (int k = 0; k < board_sz; k++) { if (Board[k][col_index] != Board[row_index][col_index]) { win = 0; break; } } if (win) { return Board[row_index][col_index]; } // check forward diagonal win = 1; for (int k = 0; k < board_sz; k++) { if (Board[k][k] != Board[row_index][col_index]) { win = 0; break; } } if (win) { return Board[row_index][col_index]; } // check reverse diagonal win = 1; for (int k = 0; k < board_sz; k++) { if (Board[k][board_sz - k - 1] != Board[row_index][col_index]) { win = 0; break; } } if (win) { return Board[row_index][col_index]; } // got nothing return 0; }
3. game.h头文件
#ifndef GAME_H #define GAME_H #include "ready.h" int play_tictactoe(int board_sz, int computer_enabled ); #endif
4. ready.h头文件
#ifndef READY_H #define READY_H char **create_board(int board_sz); void print_board(char **Board, int board_sz); int is_draw(char **Board, int board_sz); char winning_move(char **Board, int board_sz, int row_index, int col_index); #endif
尝试的编译命令及结果
gcc -c game.c -o game和gcc -c ready.c -o ready:编译无错误,但未生成可执行文件。gcc game.c create_board.c print_board.c winning_move.c is_draw.c -o game及类似命令:出现错误,提示找不到create_board.c等文件,编译终止。
问题分析与解决方案
编译命令错误原因
-c选项的作用:gcc -c仅编译生成目标文件(.o),不会链接成可执行程序。你执行的命令实际生成的是game.o和ready.o(仅修改了文件名,本质仍是目标文件),而非可执行文件。- 错误的文件引用:
create_board等函数均实现于ready.c中,不存在单独的create_board.c等文件,因此第二个命令会提示文件不存在。
正确的编译命令
方法1:分步编译+链接
# 编译生成目标文件 gcc -c game.c -o game.o gcc -c ready.c -o ready.o # 链接目标文件生成可执行程序 gcc game.o ready.o -o tictactoe
执行后生成可执行文件tictactoe,运行./tictactoe即可启动游戏。
方法2:一步编译链接
gcc game.c ready.c -o tictactoe
直接将两个.c文件编译并链接成可执行文件,操作更简洁。
代码潜在问题修复
- 未初始化变量:
main函数中computer_enabled未初始化,若用户不使用-i选项,变量值为随机值,可能导致电脑模式异常。修改为:int computer_enabled = 0; - 不必要的头文件依赖:
ready.c中包含了game.h,但代码并未用到game.h的内容,可删除该行:// #include "game.h"
内容的提问来源于stack exchange,提问作者springbook
相关产品推荐
相关产品推荐

