Копирование указателей для двух динамически растущих массивов в C

ОБНОВЛЕНИЕ: я думаю, что я ответил на свой собственный вопрос, за исключением некоторых возможных проблем с утечками памяти.

ОРИГИНАЛЬНЫЙ ВОПРОС ЗДЕСЬ, ОТВЕТЬ НИЖЕ.

Предыстория: я занимаюсь некоторыми числовыми вычислениями, но я почти никогда не использую языки, которые требуют, чтобы я управлял памятью самостоятельно. Я сейчас что-то передаю в C и испытываю проблемы с (я думаю) ссылками на указатели.

У меня есть два массива значений типа double, которые растут в цикле while, и на каждой итерации я хочу освободить память для меньшего, более старого массива, установить 'old', чтобы он указывал на новый массив, а затем установить 'new' в указать на больший блок памяти.

Посмотрев немного, мне показалось, что я должен использовать указатели для указателей, поэтому я попробовал это, но столкнулся с ошибками "lvalue required as unary" & "operand".

Я начинаю с:

double ** oldarray;
oldarray = &malloc(1*sizeof(double));
double ** newarray;
newarray = &malloc(2*sizeof(double));

Эти инициализации дают мне ошибку "lvalue Требуется как унарный" и "операнд", и я не уверен, должен ли я заменить ее на

*oldarray = (double *) malloc(1*sizeof(double));

Когда я делаю это, я могу скомпилировать простую программу (она просто содержит строки, которые у меня есть выше, и возвращает 0), но я получаю ошибку сегмента.

Остальная часть программы выглядит следующим образом:

while ( <some condition> ) {

// Do a lot of processing, most of which is updating
// the values in newarray using old array and other newarray values. 

// Now I'm exiting the loop, and growing and reset ing arrays.
free(*oldarray)        // I want to free the memory used by the smaller, older array.
*oldarray = *newarray  // Then I want oldarray to point to the larger, newer array.
newarray = &malloc( <previous size + 1>*sizeof(double))
}

Поэтому я бы хотел, чтобы на каждой итерации обновлялся массив размера (n) с использованием самого себя и более старого массива размера (n-1). Затем я хочу освободить память массива размера (n-1), установить 'oldarray', чтобы он указывал на только что созданный массив, а затем установить 'newarray', чтобы он указывал на новый блок размера (n+1).) удваивается.

Мне действительно нужно использовать указатели на указатели? Я думаю, что моя главная проблема заключается в том, что, когда я устанавливаю old на new, они разделяют pointee, и тогда я не знаю, как установить new для нового массива. Я думаю, что использование указателей на указатели выводит меня из этого, но я не уверен, и у меня все еще есть ошибки lvalue с указателями на указатели.

Я проверил динамически растущий массив C и несколько других вопросов о стеке, и примерно полдня гуглил указатели, malloc и копировал.

Спасибо!

ЗДЕСЬ МОЙ СОБСТВЕННЫЙ ОТВЕТ

Теперь у меня есть рабочее решение. Меня беспокоит только то, что в нем могут быть утечки памяти.

Использование realloc() работает, и мне также нужно быть осторожным, чтобы убедиться, что я освобождаю () только указатели, которые я инициализировал с помощью malloc или realloc, а не указатели, инициализированные с помощью double * oldarray;,

Рабочая версия выглядит так:

double * olddiagonal = (double *) malloc(sizeof(double));
olddiagonal[0] = otherfunction(otherstuff);
int iter = 1;

// A bunch of other stuff
while (<error tolerance condition>) {

  double * new diagonal = (double *) malloc((iter+1)*sizeof(double));
  newdiagonal[0] = otherfunction(moreotherstuff);

  // Then I do a bunch of things and fill in the values of new diagonal using
  // its other values and the values in olddiagonal.

  // To finish, I free the old stuff, and use realloc to point old to new.    
  free(olddiagonal);
  olddiagonal = (double *) realloc(newdiagonal, sizeof(double) * (iter+1));

  iter++
}

Кажется, это работает для моих целей. Мое единственное беспокойство - возможные утечки памяти, но пока, это ведет себя хорошо и получает правильные значения.

1 ответ

Вот несколько объяснений:


double ** oldarray;
oldarray = &malloc(1*sizeof(double));

неправильно, потому что вы не храните результат malloc() в любом месте, и поскольку он нигде не хранится, вы не можете взять его адрес. Вы можете получить эффект, который, по-видимому, имеете в виду, добавив промежуточную переменную:

double* intermediatePointer;
double** oldarray = &intermediatePointer;
intermediatePointer = malloc(1*sizeof(*intermediatePointer);

oldarray теперь указатель на ячейку памяти intermediatePointer, который указывает на выделенный шлепок памяти по очереди.


*oldarray = (double *) malloc(1*sizeof(double));

неправильно, потому что вы разыменовываете унифицированный указатель. Когда вы объявляете oldarray с double** oldarray;Вы резервируете память только для одного указателя, а не для чего-либо, на что должен указывать указатель (резервирование памяти не зависит от того, на что указывает указатель!). Значение, которое вы найдете в этой переменной указателя, не определено, поэтому вы абсолютно не можете контролировать, какой адрес памяти вы записываете, когда назначаете что-либо *oldarray,

Всякий раз, когда вы объявляете указатель, вы должны инициализировать указатель, прежде чем разыменовать его:

int* foo;
*foo = 7;    //This is always a bug.

int bar;
int* baz = &bar;   //Make sure the pointer points to something sensible.
*baz = 7;    //OK.

Ваш код ответа действительно правильный. Тем не менее, это может быть улучшено в отношении стиля:

Сочетание

int iter = 1;
while (<error tolerance condition>) {
    ...
    iter++
}

призывает к использованию for() цикл, который инкапсулирует определение и приращение переменной цикла в оператор управления циклом:

for(int iter = 1; <error tolerance condition>; iter++) {
    ...
}

В C приведение возвращаемого значения malloc() совершенно излишне, это только загромождает ваш код. (Обратите внимание, что C++ не позволяет неявное преобразование void*S как C, так int *foo = malloc(sizeof(*foo)) совершенно допустимый C, но не законный в C++. Однако в C++ вы бы не использовали malloc() на первом месте.)

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