2016-10-03 5 views
1

Я хотел написать функцию, которая изменяет размер динамического массива и позволяет пользователю заполнить его сразу. Я знаю, что я должен делать это с использованием «перераспределить» (так что я сделал, и поэтому он работает ...), но моя первая попытка выглядела так:С динамическим изменением размера массива с использованием malloc и memcpy

void ChangeDynamicArraySize(int* dArray, int oldSize, int newSize){ 

    int* tempArray = (int*) malloc(sizeof(int) * oldSize); 
    CopyArray(tempArray, dArray, oldSize); 
    free(dArray); 
    dArray = (int*) malloc(sizeof(int) * newSize); 
    CopyArray(dArray, tempArray, oldSize); 

    for (int i = oldSize; i < newSize; i++){ 
     scanf("%i", &dArray[i]); 
    } 
    PrintArray(dArray, newSize); 
    free(tempArray); 
} 

В теле функции «PrintArray (DArray, NewSize) ;» работал правильно. Но когда вызывается из основной() это дает результат, как: - 17891602 - 17891602 - 17891602 - 17891602

Так что, похоже DArray был освобожден ...? Но поскольку я знаю, что выделенная memmory не автоматически освобождается после выхода из функции.

Тогда что может быть причиной?

+0

A, и CopyArray - это только моя версия memcpy() – WJuz

+3

'dArray' передается по значению, и вы меняете только свою локальную копию. – deniss

ответ

2

В C параметры параметров копируются локально. Любые изменения, внесенные вами по значению dArray, указывают на (*dArray), но любые изменения, внесенные вами по адресу (адресу) dArray, переданные как параметр, являются только локальными для этой функции, потому что это копия.

Возможно, вы захотите передать адрес вашего массива (&array в вашей основной, dArray** в прототипе функции) и вместо этого внести изменения в указатель.

Что-то вроде этого:

void ChangeDynamicArraySize(int** dArray, int oldSize, int newSize){ 

    int* tempArray = (int*) malloc(sizeof(int) * oldSize); 
    CopyArray(tempArray, *dArray, oldSize); 
    free(*dArray); 
    *dArray = (int*) malloc(sizeof(int) * newSize); 
    CopyArray(*dArray, tempArray, oldSize); 

    for (int i = oldSize; i < newSize; i++){ 
     scanf("%i", dArray[i]); 
    } 
    PrintArray(*dArray, newSize); 
    free(tempArray); 
} 

В качестве альтернативы, вы можете также просто вернуть адрес вашего нового malloc массива эд (что делает ваша функция возвращает этот int* вместо значения).

Кроме того, для эффективной практики вы можете указать not cast the return of malloc и проверить, не удалось ли это сделать и changed ERRNO (если вы используете API POSIX).

+0

A, хорошо ... Я получил его, спасибо :) – WJuz

+0

Я пробовал это, но scanf («% i», dArray [i]) поднимается. Место записи нарушения доступа 0xcccccccc. – WJuz

+0

Но тот: scanf («% i», & (* dArray) [i]) кажется прекрасным;) Теперь он работает. – WJuz

1

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

ptr = ChangeDynamicArraySize(ptr, oldSize, newSize); 

С dArray является копией указателя передается в вызове функции, при изменении значения *dArray, который виден снаружи функции, потому что вы меняете значение хранится в ячейке памяти, на которую указывают как исходный указатель, так и копия. Но когда вы переназначаете указатель dArray внутри функции, вы просто говорите, что этот указатель теперь должен указывать на другое место. Оригинал по-прежнему указывает на исходное местоположение.

Решения в первоначальном вопросе страдает от фундаментальной проблемы: когда вы передаете указатель на область памяти для функции, а указатель перераспределяет, что память с помощью malloc() или calloc() или realloc(), новая память имеет новый адрес , Это справедливо даже с realloc(), потому что может быть недостаточно смежных байтов в старой папке для выделения запрошенной памяти. Исходное решение перераспределяет память внутри функции ChangeDynamicArraySize(), а затем изменяет содержимое этой памяти. Но после возвращения вызывающая функция не знает, где находится новая память. Таким образом, вы должны вернуть указателю на вновь выделенную память вызывающему.

@ Diti предложил альтернативное решение, чтобы обойти это, передав адрес указателя на первый элемент массива. Этот указатель может быть разыменован и задан значение адреса вновь выделенной памяти. Таким образом, вызывающая функция не является более мудрой, поскольку всякий раз, когда вызывающая функция обращается к массиву, она делает это через указатель, который предоставляет адрес первого элемента массива. Ухоженная. Но я все же думаю, что я предпочитаю явно передавать указатели, когда это возможно - мне кажется яснее.

+0

Hm, dArray - указатель, поэтому я думал, что операция, выполняемая в блоке, повлияет и на указатель вне его - как изменение значения переменной ... – WJuz

+1

Нет. Внутри функции вы просто работаете с копией. Если вы измените '* dArray' в функции, THAT будет виден вне функции, потому что вы меняете значение, хранящееся в памяти, на которое указывают как исходный указатель, так и копия. Но если вы переназначите указатель внутри этой функции, вы просто скажете, что этот указатель, который был копией какого-либо другого указателя, теперь должен указывать в другом месте. –

+0

Хорошо, теперь я понимаю, что если я вызываю realloc() в моем теге функции ChangeSize, эффект будет виден и в main(), потому что realloc() ссылается на блок памяти, который указывает как мой MainPointer, так и ChangeSizePointer. надеюсь, что я прав ... это просто изменение его размера, а не место. – WJuz