Динамический массив 2 в C

Я изучаю C и пытаюсь создать в нем виртуальную сетку, где пользователь может помещать новые элементы сетки для «активации» в консоль. Так, например, если я начинаю с нуля, а пользователь добавляет (40,50), то размер будет не менее 40x50 с инициализированным элементом (40,50). Если следует (20,30), он просто активирует элемент в 20,30. Но если пользователь затем вводит (500 300), он выделяет еще немного памяти и увеличивает размер массива. Я хотел бы легко получить к ним доступ. Я бы хотел поработать (все равно, возможно, придется), потому что они для меня новые. Мой код (на данный момент) следующий:

int width = 4, height = 5;
bool **arr = (bool **) malloc(height * sizeof(bool *));
for (int x = 0; x < height; x++) {
    arr[x] = (bool *) malloc(width * sizeof(bool));
}

for (int x = 0; x < height; x++) {
    for (int y = 0; y < width; y++) {
        *(*(arr + x) + y) = false;
    }
}

*(*(arr + 3) + 2) = true;

// user puts a value bigger than (4,5) inside
int newX=10, newY = 10;

//allocate more memory

Итак, я использую двумерный указатель с логическими значениями, сначала выполняю "malloc" высоту, а затем создаю из них массив для ширины.

В последней строке просто пример ввода первого элемента в (2,3). Метод сканирования для пользователя здесь не имеет значения.

Итак, есть ли способ впоследствии увеличить размер моего массива или мне нужна совершенно другая концепция?

===== Текущий код:

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

int main() {
    int width = 4, height = 5;
    bool **arr = (bool **) malloc(height * sizeof(bool *));

    for (int x = 0; x < height; x++) {
        arr[x] = (bool *) malloc(width * sizeof(bool));
    }

    for (int x = 0; x < height; x++) {
        for (int y = 0; y < width; y++) {
            *(*(arr + x) + y) = false;
        }
    }

    *(*(arr + 3) + 2) = true;

    int newWidth = 10, newHeight = 10;
    bool **narr = realloc(arr, newHeight * sizeof(bool*));
    if (narr) {
        arr = narr;
        for(size_t i = 0; i < newHeight; i++){
            bool* p = realloc(arr[i] , newWidth * sizeof(bool));
            if ( !p ){
                perror("realloc");
            }
            arr[i] = p;
        }
        // here resize the number of elements if needed
    }
    else {
        perror("realloc failed");
        exit(EXIT_FAILURE);
    }

    return 0;
}

Не имеет отношения к вашей проблеме, но для любого указателя или массива p и индекса i выражение *(p + i) равно точно, равному p[i]. Это означает, например, *(arr + 3) равен arr[3], и, кроме того, *(*(arr + 3) + 2) равен arr[3][2].

Some programmer dude 19.05.2018 17:27

Если массив разреженный, вы можете использовать другие структуры данных.

stark 19.05.2018 17:35

Nitpicking: bool** arr определяет arr как указатель на указатель на bool. Таким образом, на самом деле типично вы делаете нет, определяя 2D-массив, но один массив 1D с элементами указателя height плюс массивы height1D с логическими элементами width.

alk 19.05.2018 17:56

Спасибо за ваши комментарии. Вы правы насчет одномерного массива, я действительно знал об этом, но объяснил это неправильно. По этой причине используется * (* (arr + x) + y) вместо arr [y] [x], потому что это помогло мне понять вычисления.

DORpapst 19.05.2018 18:11
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
61
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Да, есть метод под названием realloc. И вы можете это использовать. Вы можете полностью изменить размер массива с зазубринами.

bool **narr = realloc(arr , newsize * sizeof(bool*));
if ( narr ) {
  arr = narr;
  for(size_t i = 0; i < newsize; i++){
     bool* p = realloc(arr[i] , newsize1 * sizeof(bool));
     if ( !p ){
        perror("realloc");
     }
     arr[i] = p;
  }
  // here resize the number of elements if needed
}
else {
    perror("realloc failed");
    exit(EXIT_FAILURE);
}

Также упростит запись a[1][2] вместо *(*(a+1)+2). Проверка необходима, поскольку realloc может дать сбой - в этом случае вместо того, чтобы позволить вашему коду пойти наперекосяк, при необходимости сделайте соответствующий шаг.

Также обратите внимание, что вам необходимо установить для всех вновь выделенных bool* значение NULL. Итак, сделайте это: -

    for(size_t i = 0; i < newHeight; i++){
        if ( i >= height)
           arr[i] = NULL;
        bool* p = realloc(arr[i] , newWidth * sizeof(bool));
        if ( !p ){
            perror("realloc");
        }
        arr[i] = p;
    }

Это необходимо, потому что realloc ожидает адрес памяти, ранее выделенной функциями *alloc или NULL.

Спасибо за ваш комментарий! Я понимаю, что вы делаете, но расскажите, пожалуйста, о строке «realloc (arr [i], newsize1 * sizeof (bool));» Зачем мне в нем arr [i]? При этом я получаю ошибку malloc: *** для объекта 0x7fff5edd5c33: перераспределенный указатель не был выделен. Просто с arr я получаю полностью инициализированный массив, но с неправильными элементами (см. Мой комментарий к @Ran Elgiser, это то же самое решение тогда (хотя и с хорошей проверкой раньше).

DORpapst 19.05.2018 18:08

Кстати, perrorникак не влияет на ход программы, так что одного его здесь недостаточно. Вы, вероятно, захотите выйти, прервать, вернуть NULL, но нет продолжить.

Antti Haapala 19.05.2018 18:11

@FranzFerdinand .: Я не понимаю ... вы перераспределяете на arr[i], поэтому он вам и нужен.

user9816091 19.05.2018 18:41

@ user9816091 Теперь я понимаю насчет arr [i], большое вам спасибо. Но при таком использовании я получаю сообщение «ошибка для объекта 0x7fff5edd5c33: перераспределенный указатель не был выделен». Возможно, я сделал глупую ошибку. Я только что обновил текущий код в теме. Спасибо за вашу идею!

DORpapst 19.05.2018 18:51

@FranzFerdinand .: Я думаю, вы неправильно его разместили. Всегда проверяйте возвращаемое значение malloc/realloc ... также помните - чтобы применить realloc, вам необходимо выделить arr[i] с помощью malloc/realloc.

user9816091 19.05.2018 19:33

Это должно быть что-то со строкой bool * p = realloc (arr [i], newWidth * sizeof (bool)) ;. Но на самом деле я не знаю, что с этим не так, потому что на самом деле это то же самое, что мы делали двумя строками раньше, только в другом «измерении» нашего «2D-массива» (одномерный указатель).

DORpapst 19.05.2018 19:39

@FranzFerdinand .: Здесь может помочь отладка ... если я не увижу ваш полный код, я не могу сказать.

user9816091 19.05.2018 20:17

Привет, я обновил свой текущий код полный в основном потоке выше. На самом деле он был там раньше, только без int main {} до и после. В настоящее время это единственное, что у меня есть внутри файла после того, как я избавился от вещей, не относящихся к теме. На данный момент я пытаюсь отладить его, редактируя различные строки, чтобы увидеть изменения.

DORpapst 19.05.2018 20:22

@FranzFerdinand: Отредактировано. Проверь это.

user9816091 19.05.2018 20:27

Большое спасибо! Теперь я понимаю, что здесь происходит ... И это работает. Пожалуйста, ответьте мне на последний вопрос: эффективно ли перераспределение для увеличения размера 2D-массива для очень больших размеров? Я не планирую работать с этим в серьезной программе, я просто экспериментирую, но что-то заставляет задуматься, моя идея для этой «проблемы» все еще неэффективна. Но теперь проблема решена, спасибо!

DORpapst 19.05.2018 20:45

@FranzFerdinand .: Это зависит от того ... вы должны выделить большой размер, а затем, в зависимости от использования, вы можете перераспределить его до меньшего размера. Но опять же, на этот вопрос лучше всего ответить в конкретной ситуации.

user9816091 19.05.2018 20:53

Вы можете использовать перераспределить для увеличения размера массива

в твоей ситуации ты бы сделал

arr = (bool **)realloc(arr, sizeof(bool*) * new_height)
for(int i = 0; i < new_height; i++){
    arr[i] = (bool *)realloc(arr, sizeof(bool) * new_width);
}

Обратите внимание, что вам нужно проверить, нужно ли вообще увеличивать массив, realloc также может «сжать» ваш массив, так что действуйте осторожно.

Инициализация вновь созданной памяти в false:

for(int i = old_height; i < new_height; i++){
    for(int j = old_width; j < new_width; j++){
        arr[i][j] = false;
    }
}
arr[new_height - 1][new_width - 1] = true;

В C эти приведения бесполезны.

alk 19.05.2018 17:52

Привет, спасибо за комментарий. Это решение фактически увеличивает размер, это правильно, но оно не сохраняет элементы старого массива. Итак, в моем примере у меня было false (0) везде, кроме (2,3). Впоследствии у меня есть первый столбец с 0, второй с 1, третий с 0 и так далее. Таким образом, он увеличивает размер, но уничтожает старые данные.

DORpapst 19.05.2018 18:09

1. неправильное использование realloc, 2. ненужное приведение типов, 3 неверный указатель на realloc в качестве аргумента ..

Antti Haapala 19.05.2018 18:12

@FranzFerdinand: realloc() - это гарантированный, чтобы нет изменить содержимое. Если вы наблюдаете, что-то идет не так.

alk 19.05.2018 18:13

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

Ran Elgiser 19.05.2018 18:14

Я только что обнаружил ошибку, если и твоя. Вы переходите от oldHeight к newHeight и oldWidth к newWidth. Но на самом деле нам это нужно три раза, для (oldHeight to newHeight) и (от 0 до oldHeight), а также наоборот. Это похоже на сетку 2x2, 1x1 был инициализирован, ваш for-for занимает 2x2, но нас не волнуют 1x2 и 2x1. Я просто пытаюсь это сделать в следующие минуты.

DORpapst 19.05.2018 18:30

Этот arr[i] = (bool *)realloc(arr, sizeof(bool) * new_width); должен читать arr[i] = realloc(arr[i], sizeof(bool) * new_width);. Не нужно приводить к C, BTW.

alk 19.05.2018 18:37

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