Я изучаю 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;
}
Если массив разреженный, вы можете использовать другие структуры данных.
Nitpicking: bool** arr определяет arr как указатель на указатель на bool. Таким образом, на самом деле типично вы делаете нет, определяя 2D-массив, но один массив 1D с элементами указателя height плюс массивы height1D с логическими элементами width.
Спасибо за ваши комментарии. Вы правы насчет одномерного массива, я действительно знал об этом, но объяснил это неправильно. По этой причине используется * (* (arr + x) + y) вместо arr [y] [x], потому что это помогло мне понять вычисления.





Да, есть метод под названием 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, это то же самое решение тогда (хотя и с хорошей проверкой раньше).
Кстати, perrorникак не влияет на ход программы, так что одного его здесь недостаточно. Вы, вероятно, захотите выйти, прервать, вернуть NULL, но нет продолжить.
@FranzFerdinand .: Я не понимаю ... вы перераспределяете на arr[i], поэтому он вам и нужен.
@ user9816091 Теперь я понимаю насчет arr [i], большое вам спасибо. Но при таком использовании я получаю сообщение «ошибка для объекта 0x7fff5edd5c33: перераспределенный указатель не был выделен». Возможно, я сделал глупую ошибку. Я только что обновил текущий код в теме. Спасибо за вашу идею!
@FranzFerdinand .: Я думаю, вы неправильно его разместили. Всегда проверяйте возвращаемое значение malloc/realloc ... также помните - чтобы применить realloc, вам необходимо выделить arr[i] с помощью malloc/realloc.
Это должно быть что-то со строкой bool * p = realloc (arr [i], newWidth * sizeof (bool)) ;. Но на самом деле я не знаю, что с этим не так, потому что на самом деле это то же самое, что мы делали двумя строками раньше, только в другом «измерении» нашего «2D-массива» (одномерный указатель).
@FranzFerdinand .: Здесь может помочь отладка ... если я не увижу ваш полный код, я не могу сказать.
Привет, я обновил свой текущий код полный в основном потоке выше. На самом деле он был там раньше, только без int main {} до и после. В настоящее время это единственное, что у меня есть внутри файла после того, как я избавился от вещей, не относящихся к теме. На данный момент я пытаюсь отладить его, редактируя различные строки, чтобы увидеть изменения.
@FranzFerdinand: Отредактировано. Проверь это.
Большое спасибо! Теперь я понимаю, что здесь происходит ... И это работает. Пожалуйста, ответьте мне на последний вопрос: эффективно ли перераспределение для увеличения размера 2D-массива для очень больших размеров? Я не планирую работать с этим в серьезной программе, я просто экспериментирую, но что-то заставляет задуматься, моя идея для этой «проблемы» все еще неэффективна. Но теперь проблема решена, спасибо!
@FranzFerdinand .: Это зависит от того ... вы должны выделить большой размер, а затем, в зависимости от использования, вы можете перераспределить его до меньшего размера. Но опять же, на этот вопрос лучше всего ответить в конкретной ситуации.
Вы можете использовать перераспределить для увеличения размера массива
в твоей ситуации ты бы сделал
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 эти приведения бесполезны.
Привет, спасибо за комментарий. Это решение фактически увеличивает размер, это правильно, но оно не сохраняет элементы старого массива. Итак, в моем примере у меня было false (0) везде, кроме (2,3). Впоследствии у меня есть первый столбец с 0, второй с 1, третий с 0 и так далее. Таким образом, он увеличивает размер, но уничтожает старые данные.
1. неправильное использование realloc, 2. ненужное приведение типов, 3 неверный указатель на realloc в качестве аргумента ..
@FranzFerdinand: realloc() - это гарантированный, чтобы нет изменить содержимое. Если вы наблюдаете, что-то идет не так.
На самом деле Realloc сохраняет элементы старого массива, просто вновь выделенное пространство еще не инициализировано, вам нужно будет инициализировать новую память самостоятельно, я добавлю это в свой комментарий.
Я только что обнаружил ошибку, если и твоя. Вы переходите от oldHeight к newHeight и oldWidth к newWidth. Но на самом деле нам это нужно три раза, для (oldHeight to newHeight) и (от 0 до oldHeight), а также наоборот. Это похоже на сетку 2x2, 1x1 был инициализирован, ваш for-for занимает 2x2, но нас не волнуют 1x2 и 2x1. Я просто пытаюсь это сделать в следующие минуты.
Этот arr[i] = (bool *)realloc(arr, sizeof(bool) * new_width); должен читать arr[i] = realloc(arr[i], sizeof(bool) * new_width);. Не нужно приводить к C, BTW.
Не имеет отношения к вашей проблеме, но для любого указателя или массива
pи индексаiвыражение*(p + i)равно точно, равномуp[i]. Это означает, например,*(arr + 3)равенarr[3], и, кроме того,*(*(arr + 3) + 2)равенarr[3][2].