Сделайте массив, который был инициализирован в main, доступным для других функций

#arrays #c #function #scope

Вопрос:

Я пытаюсь сделать игру в крестики-нолики и использую отдельный метод, который обновлял бы доску после каждого хода. Однако, похоже , я не могу получить доступ к 2D-массиву board , который был инициализирован main() . Я пытался сделать это общедоступным, как вы сделали бы на Java, но, похоже, это не работает. Любая помощь будет очень признательна.

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

#define public
#define static
#define private static

int main(void) {
    public char board[5][8] = { "  |  |  ", "-- -- --", "  |  |  ", "-- -- --", "  |  |  " };
    int turn = 0;
    public static int base = 0;

    for (size_t row = 0; row < sizeof(board) / sizeof(board[0]); row  ) {
        for (size_t col = 0; col < sizeof(board[0]) / sizeof(board[0][0]); col  )
            printf("%c", board[row][col]);
        printf("n");
    }

    printf("Player1's turnn ");
    fflush(stdout);
    scanf("%i", amp;turn);
    updateBoard(amp;turn);
}

void updateBoard(int a){
    switch (a) {
        case 1:
            board[0][0] = 'X';
            break;

        case 2:
            board[0][4] = 'X';
            break;

        case 3:
            board[0][6] = 'X';
            break;

        case 4:
            board[2][0] = 'X';
            break;

        case 5:
            board[2][4] = 'X';
            break;

        case 6:
            board[2][6] = 'X';
            break;

        case 7:
            board[4][0] = 'X';
            break;

        case 8:
            board[4][4] = 'X';
            break;

        case 9:
            board[4][6] = 'X';
            break;

        default:
            printf("Please input a correct value (1-9)");
        }

    for (size_t row = 0; row < sizeof(board) / sizeof(board[0]); row  ) {
        for (size_t col = 0; col < sizeof(board[0]) / sizeof(board[0][0]); col  )
            printf("%c", board[row][col]);
        printf("n");
    }

    base = 1;
}
 

Комментарии:

1. отправьте доску в качестве аргумента для доски обновления функций.

2. Или объявите его «глобально» вне основной функции.

3. #define private static кажется, это плохо. static имеет несколько значений в c. Это может означать либо «область действия для этой единицы перевода (например, файл *.c)», только если она находится в объявлении за пределами области действия функции, а внутри области действия это означает (упрощение) «сохранять значение этой переменной при повторных вызовах этой функции». Кроме того , поступая #define static так, вы можете нарушить множество вещей, даже не подозревая об этом, например, если в заголовочных файлах есть static где угодно.

Ответ №1:

Самое простое решение-объявить board base , предполагая, что оно будет использоваться для чего-то в будущем) в области файла, часто называемой «глобальной областью».:

 static int base = 0;
static char board[5][9] = { "  |  |  ", "-- -- --", "  |  |  ", "-- -- --", "  |  |  " };

void updateBoard(int a);

int main(void)
{
    int turn = 0;

    // ...
 

Они объявлены static , что означает, что они будут видны только коду в этом файле и не могут быть доступны из других файлов той же программы.
Я удалил #define буквы «с». Ключевые public слова и private не существуют в C; они обычно используются только в языках, поддерживающих объектно-ориентированное (или основанное на классах) программирование. Ключевое static слово действительно существует, но имеет другое значение в зависимости от контекста. Его лучше не переопределять.
Обратите внимание, что второе измерение должно быть 9: 8 символов и 1 нуль-терминатор.

Недостатком наличия переменных в области действия файла является то, что они видны во всем файле, и при наличии нескольких функций, изменяющих их содержимое, может стать трудно контролировать и рассуждать о поведении программы.

Возможно , лучшее решение-сохранить board и base main сохранить, а затем передать их updateBoard кому угодно . Хотя это сразу же вводит некоторые более продвинутые C-концепции. Добавление необходимых дополнительных аргументов/параметров к прототипу функции и вызову функции, вероятно, вам знакомо. Проблема в том, что аргументы массива преобразуются в указатели (см. Здесь, часто называемый «распад массива на указатель»). Это означает, что sizeof теперь предоставляется не размер всего массива, а размер указателя на первый элемент массива. В приведенном ниже решении это разрешается путем получения измерений один раз в основном, сохранения их в переменных и передачи этих значений функции. Это, возможно, лучшее решение, чем использовать sizeof вычисления везде. И как только переменные будут установлены, это также будет работать с динамически выделяемыми массивами.

 // Forward declaring the function, so main knows it exists
void updateBoard(char board[5][9], size_t nRows, size_t nCols, int base, int a);

int main(void)
{
    int base = 0;

    // Note the 9 for the second dimension
    char board[5][9] = { "  |  |  ", "-- -- --", "  |  |  ", "-- -- --", "  |  |  " };
    int turn = 0;

    // Initializing the variables for the dimensions...
    size_t nRows = sizeof(board) / sizeof(board[0]);
    size_t nCols = sizeof(board[0]) / sizeof(board[0][0]);

    // ...which we can now use here as well...
    for (size_t row = 0; row < nRows; row  ) {
        for (size_t col = 0; col < nCols; col  )
            printf("%c", board[row][col]);
        printf("n");
    }
    printf("Player1's turnn ");
    fflush(stdout);
    scanf("%i", amp;turn);

    // ... and here, along with passing board and base.
    updateBoard(board, nRows, nCols, base, turn);
}

void updateBoard(char board[5][9], size_t nRows, size_t nCols, int base, int a){
    switch (a) {
        // ... code omitted for brevity ...
    }

    // Use the passed dimension values here
    for (size_t row = 0; row < nRows; row  ) {
        for (size_t col = 0; col < nCols; col  )
            printf("%c", board[row][col]);
        printf("n");
    }
    base = 1;
}
 

При передаче переменных, подобных этой, существует важное различие между передачей переменных по ссылке и передачей их по значению. Возможно, это хорошая следующая тема для изучения в вашем путешествии на C, наряду с static «строковым литералом»/»терминатором null».