Как и во всем, что поначалу кажется страшнее, чем было позже, лучший способ преодолеть первоначальный страх - это погрузиться в дискомфорт неизвестного !В конце концов, именно такие моменты мы изучаем больше всего.
К сожалению, существуют ограничения.Хотя вы все еще учитесь использовать функцию, вы не должны брать на себя роль учителя, например.Я часто читаю ответы от тех, кто, по-видимому, не знает, как использовать realloc
(то есть текущий принятый ответ! ), рассказывая другим, как использовать его неправильно, иногда под видом того, что они опущена обработка ошибок , хотя это распространенная ошибка, о которой стоит упомянуть. Вот ответ, объясняющий, как правильно использовать realloc
. Обратите внимание, что ответ хранит возвращаемое значение в другой переменной для проверки ошибок.
Каждый раз, когда вы вызываете функцию, и каждый раз, когда выиспользовать массив, вы используете указатель.Преобразования происходят неявно, что, если что-то должно быть еще страшнее, поскольку именно то, что мы не видим, часто вызывает наибольшее количество проблем.Например, утечки памяти ...
Операторы массива являются операторами указателя.array[x]
- это действительно сокращение *(array + x)
, которое можно разбить на: *
и (array + x)
.Скорее всего, *
- это то, что вас смущает.Кроме того, мы можем исключить добавление из проблемы, приняв x
равным 0
, таким образом, array[0]
становится *array
, поскольку добавление 0
не изменит значения ...
... и, таким образом, мы можем видеть, что *array
эквивалентно array[0]
.Вы можете использовать один, где вы хотите использовать другой, и наоборот.Операторы массива являются операторами указателя.
malloc
, realloc
, а друзья не изобретают концепцию указателя, которую вы использовали все это время;они просто используют для реализации какой-либо другой функции, которая представляет собой другую форму продолжительности хранения, наиболее подходящую, когда вы хотите резких, динамических изменений в размере .
ЭтоЖаль, что принятый в настоящее время ответ также идет вразрез с некоторыми другими очень обоснованными рекомендациями по StackOverflow , и в то же время упускает возможность ввести немного-известная особенность, которая подходит именно для этого варианта использования: гибкие члены массива!Это на самом деле довольно неправильный ответ ...: (
Когда вы определяете struct
, объявляете ваш массив в конце структуры, без каких-либо верхнихнапример:
struct int_list {
size_t size;
int value[];
};
Это позволит вам объединить ваш массив int
в то же выделение, что и ваш count
, и связать их таким образом можно очень удобно !
sizeof (struct int_list)
будет действовать так, как если бы value
имел размер 0, поэтому он сообщит вам размер структуры с пустым списком . Вам все еще нужнодобавить к размеру, переданному в realloc
, чтобы указать размер вашего списка.
Еще один полезный совет: помните, что realloc(NULL, x)
эквивалентно malloc(x)
, и мы можем использовать это для упрощения нашего кода.Например:
int push_back(struct int_list **fubar, int value) {
size_t x = *fubar ? fubar[0]->size : 0
, y = x + 1;
if ((x & y) == 0) {
void *temp = realloc(*fubar, sizeof **fubar
+ (x + y) * sizeof fubar[0]->value[0]);
if (!temp) { return 1; }
*fubar = temp; // or, if you like, `fubar[0] = temp;`
}
fubar[0]->value[x] = value;
fubar[0]->size = y;
return 0;
}
struct int_list *array = NULL;
Причина, по которой я решил использовать struct int_list **
в качестве первого аргумента, может показаться не сразу очевидной, но если подумать о втором аргументе, любые изменения, сделанные в value
изнутриpush_back
не будет виден функции, из которой мы вызываем, верно?идет к первому аргументу, и мы должны иметь возможность изменить наш array
, не только здесь , но , возможно, также в любой другой функции / с, мы передаем его ...
array
начинает указывать ни на что;это пустой список. Инициализация это то же самое, что и добавление к нему.Например:
struct int_list *array = NULL;
if (!push_back(&array, 42)) {
// success!
}
PS Не забудьте free(array);
, когда закончите с этим!