Проблемы с геттером для матрицы 4х4 в c

Здравствуйте, я должен запрограммировать игру тетрис на C к завтрашнему дню, и у меня возникли небольшие проблемы с геттером, который должен возвращать спрайт в виде матрицы 4x4.

Скорее всего, это довольно просто, хотя я не очень знаком с указателями на массивы.

так что в первом файле, где я хранил свои фигуры, это тестовый геттер для 1 фигуры

int shape_i[4][4] = {
    {1,0,0,0},
    {1,0,0,0},
    {1,0,0,0},
    {1,0,0,0}
};


int **get_shape(){
return shape_i;}

Теперь из моего файла ничья я называю это так

void draw_shape(){
int **shape= get_shape();
for (int i = 0; i<4; i++){
    for (int j=0; j<4; j++){
        int value = shape[j][i];

            if (value != 0){
                SDL_Rect rect;
                rect.x = (get_x()+i)*BLOCK_WIDTH;
                rect.y = (get_y()+j) *BLOCK_HEIGHT;
                rect.h = BLOCK_HEIGHT;
                rect.w = BLOCK_WIDTH;
                SDL_FillRect(window,&rect,0x044DDE);
            }
            }
    }
SDL_Flip(window);
}

Это не выдает ошибку при компиляции, но моя программа останавливается, как только достигает get_shape()

1 ответ

Решение

TL; DR: скопировать данные в массив фигур с помощью memcpyсм. второй пример ниже. Другие примеры - это альтернативные подходы с объяснениями.


В C вы не можете вернуть массивы. Вы можете только вернуть указатель на первый элемент массива. Первым элементом вашего массива является сам массив, массив из 4 ints.

Синтаксис определения указателя на массив из четырех целых чисел несколько барочный:

int (*p)[4];

Еще более барокко, когда вы должны определить его как тип возвращаемого значения функции:

int (*get_shape(int c))[4] { ... }

Способ обойти это заключается в использовании typedef:

typedef int (*Shape)[4];

Теперь ваши переменные и прототип функции выглядят так:

Shape p = get_shape(c);

Shape get_shape(int c) { ... }

Вот полный пример:

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

typedef int (*Shape)[4];

int shape_i[4][4] = {{1,0,0,0}, {1,0,0,0}, {1,0,0,0}, {1,0,0,0}};
int shape_l[4][4] = {{1,0,0,0}, {1,0,0,0}, {1,1,0,0}, {0,0,0,0}};
int shape_z[4][4] = {{1,0,0,0}, {1,1,0,0}, {0,1,0,0}, {0,0,0,0}};

Shape get_shape(int c)
{
    switch (c) {
    case 'I':   return shape_i;
    case 'L':   return shape_l;
    case 'Z':   return shape_z;
    }
    return NULL;
}

int main()
{
    int c;

    for (c = 'A'; c <= 'Z'; c++) {
        Shape p = get_shape(c);

        if (p) {
            int i, j;

            for (j = 0; j < 4; j++) {
                for (i = 0; i < 4; i++) {
                    putchar(p[j][i] ? '#' : ' ');
                }
                puts("");
            }
            puts("--");
        }        
    }

    return 0;
}

Обратите внимание, что определение форм все еще требует от вас использования int[4][4]потому что массивы не указатели. Вам нужны массивы, где вы определяете свои данные. Также обратите внимание, что это решение возвращает указатель на оригинал shape_i, Когда вы изменяете данные в pВы модифицируете shape_i через p, уничтожая тем самым вашу форму прототипа.


Если вы хотите заполнить массив данными, просто передайте данные. Это общий подход даже для одномерных массивов: передайте массив и сделайте так, чтобы функция заполнила его. Вернуть (иначе не связанное) значение, которое сообщает вам, была ли операция успешной.

int get_shape(int shape[4][4], int c)
{
    switch (c) {
    case 'I':   memcpy(shape, shape_i, sizeof(shape)); return 1;
    case 'L':   memcpy(shape, shape_l, sizeof(shape)); return 1;
    case 'Z':   memcpy(shape, shape_z, sizeof(shape)); return 1;
    }
    return 0;
}

memcpy это функция стандартной библиотеки, для которой вы должны включить <string.h>, Возвращаемое значение просто для проверки правильности формы. Используйте это так:

int p[4][4];

if (get_shape('I')) {
    // p is now filled with a copy of shape_i
}

Я думаю, что это метод, который вы должны использовать. Это скопирует содержимое shape_tв pИ это то, что вы хотите здесь. Вы собираетесь вращать и переворачивать свой текущий блок pтогда как вы хотите сохранить свой блок-прототип shape_i без изменений для будущих "клонов".


Я уже говорил выше, что вы не можете вернуть массивы в C. Что вы можете сделать, это обернуть ваш массив в struct и верни это. Структуры передаются по значению и не распадаются на указатели, такие как массивы.

struct Shape {
    int data[4][4];
};

struct shape shape_i = {{{1,0,0,0}, {1,0,0,0}, {1,0,0,0}, {1,0,0,0}}};

struct Shape get_shape(void) {
    return shape_i;
};

struct Shape p = get_shape();

Это также скопирует содержание, но вы должны получить доступ к элементам как p.data[i][j],

Другие вопросы по тегам