带有二维数组问题的 C 游戏板

C Gameboard with a 2d Array Issues

更新: 修复了悬挂指针,解决了我的很多问题。还逆转了我的 Game_board 初始化。然后我创建了一个测试件的移动方法。

建议:小心挂指针和内存分配。

欢迎来到 Stack Overflow。一般来说,我们更喜欢您将代码粘贴到此处,而不是 link。 (link 可能会随着时间的推移而过时)。您还应该描述您看到的错误消息,以确保我们都在同一页面上。

您可能有多个问题,但第一个问题肯定是 game_piece_to_label 您使用的是未初始化的指针。

char* game_piece_to_string(struct game_piece* piece)
{
    char* tempLabel;
    strcpy(tempLabel, game_piece_get_label(piece));

您需要分配一些内存并将其分配给 tempLabel。就目前而言,您正在写入随机内存,这对我来说会导致段错误。

使用未初始化的指针

一个大问题是您将 char *tempLabel; 用作 未初始化的指针 。 (它指向哪里?它持有什么有效的内存地址作为它的值?)尝试向它复制数据肯定会导致 SegFault。相反,您需要使用 malloc, calloc or realloc 验证 game_piece_get_label(piece) 分配 length + 1 个存储字符的长度,例如

例如:

char *game_piece_to_string (struct game_piece *piece)
{
    char *tempLabel;    /* uninitialized pointer */
    size_t len = strlen (game_piece_get_label(piece));

    tempLabel = malloc (len + 1);
    if (tempLabel == NULL) {
        perror ("malloc-tempLabel");
        return NULL;
    }
    memcpy (tempLabel, game_piece_get_label(piece), len + 1);

    if (len > 3)
        tempLabel[1] = '[=10=]';
    for (size_t i = 3; i > len; i--)
        strcat(tempLabel, " ");

    return tempLabel;
}

请注意,您尝试用条件语句和 sizeof (a_pointer) 循环做什么毫无意义。假设您想要 tempLabel.

length

板分配问题

您对指针到指针 struct game_piece 的分配几乎是倒退的。您必须首先分配 row 个指针,然后每行分配 colstruct game_piece 个指针。然后,您将在每个 [i][j] 处为一个 struct game_piece 分配存储空间 - 这是您决定将 char label[30]; 作为结构中的单个成员不必要地使引用 [=29= 复杂化的地方].

进行更改,您可以执行以下操作:

void game_board_init(struct game_board* game_board, int rows, int cols)
{
    /* allocate row number of pointers */
    game_board->board = malloc (sizeof(*game_board->board)*rows);
    /* allocate col number of **game_board->board per row
     * (e.g. col * sizeof (struct game_piece) per row)
     */
    for (int i = 0; i < rows; i++){
        game_board->board[i] = malloc(sizeof(struct game_piece) * cols);
    }
    game_board->row = rows;
    game_board->col = cols;
    for (int i=0; i < rows; i++){
        printf("\n");
        for (int j=0; j < cols; j++) {
            game_piece_init_default(&game_board->board[i][j]);
            printf("%s ",game_board->board[i][j].label);
        }
    }
}

所有这些都表明您要么 (1) 在未启用 警告的情况下编译代码 ,要么 (2) 有意识地忽略编译器生成的警告。对于 gcc/clang,请将 -Wall -Wextra -pedantic(至少)添加到您的编译器选项,对于 VS,请添加 /W3 并且在编译 且没有警告 之前不接受代码。让您的编译器帮助您编写更好的代码。 (这将为您节省大量时间 运行)

你也会想看看How to debug small programs和鸭子说话...真的,它有帮助:)

启用编译器警告,查看调试 link,然后编辑 添加 到您问题的底部任何其他您卡住的特定区域我很乐意进一步提供帮助。

进行上述更改,并添加以下 "stub" 以消除未完成 game_board_move_piece 中未使用变量的警告,例如

    if (game_board || src_row || src_col || dest_row || dest_col) {}

我可以使用 gcc 编译你的代码:

gcc -Wall -Wextra -pedantic -Wshadow -std=c11 -Ofast -o gb_init gb_init.c

没有警告。您需要进行一些额外的调试,如下所示:

例子Use/Output

$ ./bin/game_board_init
Please enter the number of rows.
3
Please enter the number of columns.
3

--- --- ---
--- --- ---
--- --- --- Please enter a label for a new piece. Enter "Q" when done.
a
Please enter a row for the piece.
1
Please enter a column for the piece.
1
New piece "a" added.
Please enter a label for a new piece. Enter "Q" when done.c
Please enter a row for the piece.
2
Please enter a column for the piece.
2
New piece "c" added.
Please enter a label for a new piece. Enter "Q" when done.b
Please enter a row for the piece.
0
Please enter a column for the piece.
0
New piece "b" added.
Please enter a label for a new piece. Enter "Q" when done.q
try again -kelly
b  ------
---a  ---
------c  Would you like to move a piece? Enter "Y" to move a piece.
Y
Please enter the piece's row.2
Please enter the piece's column.2
Please enter the piece's new row.2
Please enter the piece's new column.0
A piece is already in that space.
try again -kelly
b  ------
---a  ---
------c  Would you like to move a piece? Enter "Y" to move a piece.
n

这就是与 "duck" 的对话发挥作用的地方...

使用了完整的测试代码

下面是我在没有警告的情况下编译并生成上面输出的内容。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXL 30     /* if you need a constant, #define one (or more) */

struct game_piece
{
    char label[MAXL];
};

struct game_board
{
    struct game_piece **board;
    int row, col;
};

void game_piece_init_default(struct game_piece* piece)
{
    strcpy(piece->label, "---");
}

void game_piece_init(struct game_piece* piece, char* new_label)
{
    size_t len = strlen (new_label);

    if (len < MAXL)
        memcpy (piece->label, new_label, len + 1);
    else {
        fputs ("warning: label truncated.\n", stderr);
        memcpy (piece->label, new_label, MAXL-1);
        piece->label[MAXL-1] = 0;   /* nul-terminate */
    }
}

char *game_piece_get_label (struct game_piece *piece)
{
    return piece->label;
}

char *game_piece_to_string (struct game_piece *piece)
{
    char *tempLabel;    /* uninitialized pointer */
    size_t len = strlen (game_piece_get_label(piece));

    tempLabel = malloc (len + 1);
    if (tempLabel == NULL) {
        perror ("malloc-tempLabel");
        return NULL;
    }
    memcpy (tempLabel, game_piece_get_label(piece), len + 1);

    if (len > 3)
        tempLabel[1] = '[=15=]';
    for (size_t i = 3; i > len; i--)
        strcat(tempLabel, " ");

    return tempLabel;
}

void game_board_init(struct game_board* game_board, int rows, int cols)
{
    /* allocate row number of pointers */
    game_board->board = malloc (sizeof(*game_board->board)*rows);
    /* allocate col number of **game_board->board per row
     * (e.g. col * sizeof (struct game_piece) per row)
     */
    for (int i = 0; i < rows; i++){
        game_board->board[i] = malloc(sizeof(struct game_piece) * cols);
    }
    game_board->row = rows;
    game_board->col = cols;
    for (int i=0; i < rows; i++){
        printf("\n");
        for (int j=0; j < cols; j++) {
            game_piece_init_default(&game_board->board[i][j]);
            printf("%s ",game_board->board[i][j].label);
        }
    }
}

int game_board_is_space_valid(struct game_board* game_board, 
                                int row, int col)
{
    if (row > game_board->row || col > game_board->col)
        return 0;
    if (row < 0 || col < 0) 
        return 0;
    return 1;
}

int game_board_add_piece(struct game_board* game_board, 
                        struct game_piece* piece, int row, int col)
{
    if (game_board_is_space_valid(game_board, row, col) == 0) 
        return 0;
    if (strncmp(game_board->board[row][col].label, "---", 3) == 0) {
        game_board->board[row][col] = *piece;
        return 1;
    }
    return 0;
}

int game_board_move_piece(struct game_board* game_board, 
                    int src_row, int src_col, int dest_row, int dest_col)
{
    return 0;
    if (game_board || src_row || src_col || dest_row || dest_col) {}
}

void game_board_print(struct game_board* game_board)
{
    int col = 3;
    int row = 3;
    printf("try again -kelly");
    for (int i=0; i < row; i++) {
        printf("\n");
        for (int j=0; j < col; j++) {
            printf("%s",game_piece_to_string(&game_board->board[i][j]));
        }
    }
}

int main()
{
    /* declare local variables */
    int row;
    int col;
    int destRow;
    int destCol;
    int rowNum;
    int colNum;
    struct game_board board;
    struct game_piece piece;
    char input_string[30];

    /* get the size of the game board */
    printf("Please enter the number of rows.\n");
    scanf("%d", &rowNum);

    printf("Please enter the number of columns.\n");
    scanf("%d", &colNum);

    game_board_init(&board, rowNum, colNum);

    /* get the first piece's label */
    printf("Please enter a label for a new piece. "
            "Enter \"Q\" when done.\n");
    scanf("%s", input_string);

    while (strcmp(input_string, "Q") != 0 && strcmp(input_string, "q") != 0)
    {
        game_piece_init(&piece, input_string);

        /* get the location to place the piece */
        printf("Please enter a row for the piece.\n");
        scanf("%d", &row);

        printf("Please enter a column for the piece.\n");
        scanf("%d", &col);

        /* verify the space is valid then add the piece to the board */
        if (game_board_is_space_valid(&board, row, col))
        {
            if (game_board_add_piece(&board, &piece, row, col))
            {
                printf("New piece \"%s\" added.\n", 
                        game_piece_get_label(&piece));
            }
            else
            {
                printf("A piece is already at that space.\n");
            }
        }
        else
        {
            printf("Invalid row and/or column.\n");
        }

        /* get the label for the next piece */
        printf("Please enter a label for a new piece. "
                "Enter \"Q\" when done.");
        scanf("%s", input_string);
    }

    /* print the board and check if user wants to move a piece */
    game_board_print(&board);
    printf("Would you like to move a piece? Enter \"Y\" to move a piece.\n");
    scanf("%s", input_string);

    while (strcmp(input_string, "Y") == 0 || strcmp(input_string, "y") == 0)
    {
        /* get the location of the piece */
        printf("Please enter the piece's row.");
        scanf("%d", &row);

        printf("Please enter the piece's column.");
        scanf("%d", &col);

        /* get the destination for the piece */
        printf("Please enter the piece's new row.");
        scanf("%d", &destRow);

        printf("Please enter the piece's new column.");
        scanf("%d", &destCol);

        /* verify both spaces are valid then move the piece */
        if (game_board_is_space_valid(&board, row, col) &&
            game_board_is_space_valid(&board, destRow, destCol))
        {
            if (game_board_move_piece(&board, row, col, destRow, destCol))
            {
                printf("Piece moved to new space.\n");
            }
            else
            {
                printf("A piece is already in that space.\n");
            }
        }
        else
        {
            printf("A row or column is invalid. No piece moved.\n");
        }

        /* print the board and check if the user wants move another piece */
        game_board_print(&board);
        printf("Would you like to move a piece? "
                "Enter \"Y\" to move a piece.\n");
        scanf("%s", input_string);
    }

    return 0;
}