You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将井字棋代码拆分至.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等文件,编译终止。

问题分析与解决方案

编译命令错误原因

  1. -c选项的作用:gcc -c仅编译生成目标文件(.o),不会链接成可执行程序。你执行的命令实际生成的是game.o和ready.o(仅修改了文件名,本质仍是目标文件),而非可执行文件。
  2. 错误的文件引用: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文件编译并链接成可执行文件,操作更简洁。

代码潜在问题修复

  1. 未初始化变量:main函数中computer_enabled未初始化,若用户不使用-i选项,变量值为随机值,可能导致电脑模式异常。修改为:
    int computer_enabled = 0;
    
  2. 不必要的头文件依赖:ready.c中包含了game.h,但代码并未用到game.h的内容,可删除该行:
    // #include "game.h"
    

内容的提问来源于stack exchange,提问作者springbook

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 03:47:08