Динамічне виділення в java або c ++

Якщо у мене є вказівник на C ++, скажімо, int * array; , я виділяю пам'ять для масиву за допомогою

array=new int[10];

Потім я ініціалізую всі 10 елементів масиву, з 0,1,2,3 ... Після цього я виконую array = new int [15]; будуть перші перші 10 значень, як і раніше, будуть там? Я не припускаю, виправити мене, якщо я помиляюся.

In C there is the function realloc, which has the effect described above. Is there any equivalent in C++ or java? How can I dynamically expand an array (without using Vector class, and without copying the array each time in another array with double capacity) in C++ or Java?

1
Ви правильно. Він буде замінено масивом нулів у Java.
додано Автор asteri, джерело
@ Мариус Я мав на увазі Java. Вибачте, я б сказав це.
додано Автор asteri, джерело
Я думаю, це питання занадто туманне - кілька питань на різних мовах ...
додано Автор Brian Agnew, джерело
@ Даніель, тому що друга частина не має сенсу. Це стосується "ефекту, описаного вище". Але який ефект? У C ++ це витік пам'яті.
додано Автор juanchopanza, джерело
Зауважте, що realloc не обов'язково змінює розмір старого блоку пам'яті. Якщо після масиву не вистачає вільного простору, він виділить новий масив і скопіює попередні значення. Ось чому це дає вам назад покажчик; покажчик може перебувати у зовсім іншому місці, ніж той, який ви перейшли.
додано Автор cHao, джерело
друга частина полягає в динамічному розширенні масиву
додано Автор Tala, джерело
Я думаю, ви повинні замінити вашу "java OR c ++" на "java AND c ++" або "java vs c ++" в питанні.
додано Автор Tala, джерело
Ні, це замінить масив випадкових величин (насправді, що було в пам'яті раніше). C ++ не ініціалізує масив-вміст!
додано Автор Marius, джерело
Цікаво, що більшість відповідей, здається, ігнорують другу половину питання, що є актуальною цікавою частиною ...
додано Автор Daniel, джерело

9 Відповіді

Кожного разу, коли ви виконуєте new int [X] , де X є цілим числом, як у C ++, так і в Java, ви отримуєте посилання на знову виділений масив.

У Java масиви автоматично ініціалізуються так, що кожна запис має значення за замовчуванням (0 для примітивних типів даних, нуль для типів стандартних даних). У C ++ масив не ініціалізується, ви отримуєте сміття на ньому.

Якщо ти зробиш:

array = new int[10];
array[0] = 0;
array[1] = 1;
// etc
array = new int[15];

другий раз, коли ви створюєте масив і покладете посилання на нього в змінній масив , ви просто втратите посилання на свій перший масив. Оскільки це масив new , він підпорядковується правилам мови для знову виділяти масиви: в масиві Java тепер буде вказано масив розміру 15, заповнений нулями; в C ++ масив вказує на масив розміром 15, заповнений сміттям.

У Java, втрачений масив буде в кінцевому підсумку збирати сміття для вас. У C ++ ви тільки що створили витік пам'яті.

Обидві мови забороняють вам змінювати розмір або, якщо ви покладете, динамічно розгортати масив. Ви можете створити нову, копіювати все, від старого до нового, і відкинути стару. Вони можуть надавати методи, які роблять ці операції для вас, але ви не розширюватимете існуючий масив, ви просто створите новий і скопіюєте дані зі старого на новий.

У Java немає realloc (але він має Arrays.copyOf , який працює аналогічно), а також у C ++ (і C) realloc не буде дійсно подовжити масиву; він буде виділяти більше пам'яті в іншому місці , вилучити раніше виділену пам'ять і повернути новий покажчик: вам доведеться замінити будь-які існуючі покажчики на нову адресу!

Нарешті, для класів колекції, які динамічно змінюють розмір себе, вони, як правило, мають внутрішній масив і, коли цей масив заповнюється, клас робить все, що змінює розмір внутрішнього вигляду: він виділяє новий, більше, копіює елементи та відкидає старий. Оскільки масив повністю інкапсулізований у клас, вам не потрібно турбуватися про посилання на старий масив, як я пояснив вище.

3
додано
@ Раду, я не впевнений у точності поведінки. Я думаю, це дійсно може просто розширити блок, якщо є простір, але тоді, як би ви знали, якщо runtime думає, що є достатньо місця? Залежно від випадку користування, вам потрібно перевірити, чи недавно виділений блок пам'яті знаходиться в тій же позиції (і оновлювати старі покажчики, якщо адреса змінилася), або якщо у вас просто є один покажчик, який ви замінюєте, ви просто не дбайте про це - якщо адреса змінюється або залишається однаковою, ваш код буде однаковим.
додано Автор Bruno Reis, джерело
Як так, "це не працює в C ++"?
додано Автор Bruno Reis, джерело
@ Radu realloc працює так само в C і C ++.
додано Автор juanchopanza, джерело
Так, вибачте, я неправильно читаю вашу відповідь. Ну, якщо я використовую realloc для перерозподілу більшої кількості пам'яті, скажімо, sizeof (int) більше пам'яті, я думав, що він буде копіювати масив лише у тому випадку, якщо немає місця для перерозподілу в цьому місці. В іншому випадку, він просто запитує більший блок пам'яті, тим самим розширюючи масив?
додано Автор Radu, джерело
Найкраще відповідь до сих пір :) Чи могли б ви детальніше про останню частину, з realloc? чому він працює в C, а не в C ++ (для примітивних типів я маю на увазі)
додано Автор Radu, джерело

Серце масиву концепції, як в C + + і Java, є фіксованим розмір колекції. realloc може виглядати як якийсь бекдор у цій концепції, але він все одно не обіцяє розширити даний масив - він може створювати масив в іншому місці, копіювати оригінальний вміст і випускати оригінальну пам'ять. І цілком імовірно це буде.
Отже, якщо ви хочете збирати змінні розміри, скористайтеся командою std :: vector в C ++ та ArrayList в Java. Або ви можете кодувати цю функцію самостійно. Але я боюся, що вам доведеться почати з власного розподільника пам'яті, оскільки ви не можете зробити стандартний розширений один раз виділений фрагмент пам'яті.

2
додано

чи перші перші 10 значень залишиться там?

У C ++ буде десь , але ви втратили свою рукопис до них. Вони будуть недоступні. Це становить витік пам'яті.

int* array=new int[10];//array points to dynamically allocated array
array=new int[15];//array points to a completely different place now

У наведеному вище прикладі покажчик array є єдиним у вас русі у першому динамічно виділеному масиві. Зробивши це точку в іншому місці, ви витікаєте масив.

Зауважте також, що в C ++ елементи масиву не нуль ініціалізовані. Для цього потрібно визначити ініціалізацію масиву:

int* array=new int[10]();
//                    ^^
1
додано

У керуванні пам'яттю java знаходиться під контролем JVM. Ось це красуня яви. Ви можете використовувати функцію System.arraycopy() для створення копії масиву. Якщо вашою метою є розширення масиву, просто надішліть масив більше як масив призначення.

З іншого боку, ви можете використовувати рамки колекцій для динамічного розширення колекцій.

1
додано

The best option in C++ is stl and std::vector I have no idea why you can't use it but lets say, that you can't. Probably the best way:

const int c_startSize = 10;
const int c_increasing = 13;   //1.3

int * array;
int arraySize = c_startSize;
array = new int[arraySize];
//some code
//now we need to increase size of array.
int * tmp;
tmp = new int[arraySize * c_increasing/10];
for (int i = 0; i < arraySize; i++)
    tmp[i] = array[i];
arraySize = arraySize * c_increasing/10;
delete [] array;
array = tmp;
//some code

Це, напевно, єдиний спосіб. Звичайно, ви можете скористатись realloc або memcpy для копіювання значень, але вона базується на недійсних вказівниках, а для початківців, як правило, це складніше. Сподіваюсь, що це допомогло, не забудьте зробити клас або структуру для цієї речі, інакше це буде для багатьох безлад.

EDIT: Забули згадати, моя відповідь включає тільки C + +, не JAVA.

0
додано
Ідея про те, що ви є новачком, полягає в тому, що ви хочете зробити щось замість того, щоб використовувати якийсь надійний джерело, як вектор.
додано Автор ST3, джерело
В основному поза теми. По-перше, це не STL, це стандартна бібліотека, незважаючи на те, що більшість людей змушує їх плутати, вони різні. По-друге, я попросив щось зовсім інше. Ви знаєте, що означає "без використання вектора та без копіювання масиву"? По-третє, де ви зрозуміли, що я новачок? По-четверте, ні, це взагалі не допомогло. Це дуже дратує мене, коли люди відповідають на питання, які не були задані.
додано Автор Radu, джерело

У C ++ нове завжди повертає покажчик. Назва масиву - це вказівник на перший елемент масиву, і ось що станеться.

 int *array;           //get a point of type int
 array=new int[10];    //allocate 10 ints, and set the array ponter to the first one

 array = new int[15]   //allocate 15 ints, and set the array pointer to the first one

проблема в даний час ми не маємо можливості дізнатися, де в пам'яті перші 10 інтрів. Операційні системи "думає", ми використовуємо його b/c, ми просили про це. але ми не можемо використовувати це b/c, ми не знаємо, де він є.


зараз для чогось корисного. Використовуйте вектори, вектори - це об'єкти в c ++, у яких вбудовано динамічне запам'ятовування, тому вам не потрібно вручну робити це самостійно.

Якщо ви дійсно хочете побачити, як це зроблено, ви можете створити об'єкт, який обробляє пам'ять, що виділяє себе.

0
додано

У Java ви не можете динамічно розширити масив. Для цього є різні структури даних, як-от ArrayList.

У Java, у вашому прикладі, якщо немає посилання на перший масив з розміром 10, він буде зібраний GarbageCollector.

0
додано
Використовуйте ArrayList замість Vector, якщо вам не потрібно, щоб він був безпечним. У ній є масив. Коли ви заповнюєте весь простір і вам потрібно додати один mroe, він копіює все до більшого масиву і видає посилання на попередній масив (так що збирається сміття)
додано Автор Tala, джерело
Ось що я хотів би знати, якщо ви можете або не динамічно розширювати масив. Як вектор працює всередині?
додано Автор Radu, джерело

Як я можу динамічно розширити масив (без використання класу Vector і без копіювання масиву кожен раз в іншому масиві з подвійною ємністю) в Java?

In java.util.Arrays, there are a lot of method to use. In your situation you need copyOf

Документи Api

array = Arrays.copyOf(array, 15);
0
додано
Це неправильно. Масив не буде розширено, ви просто отримаєте знову виділений масив. Будь-які посилання на старий масив, як і раніше, вказують на старий масив із старим розміром.
додано Автор Bruno Reis, джерело
не копіюючи масив кожного разу ...
додано Автор jlordo, джерело
@jlordo Я думаю, ОП означає, що без вручну копіювання масиву кожного разу ...
додано Автор johnchen902, джерело
@ BrunoReis Хороший аргумент ... Я не думав про те, що масив поділений ...
додано Автор johnchen902, джерело
@ Раду Так. Як зазначено в apidocs: Повертає копію оригінального масиву, урізаного або заповненого нулями, щоб отримати вказану довжину
додано Автор johnchen902, джерело
Отже, якщо вихідний масив має розмір 10, і я масив = Arrays.copyOf (масив, 20), я отримаю новий масив з першими 10 полями, подібними до оригінального?
додано Автор Radu, джерело

Так, існує еквівалент в C ++, який є стандартним C ++.

std::vector array(10);

І потім

array.resize(15);

vector керує пам'яттю пам'яті саме так, як ви очікуєте. vector був розроблений для заміни покажчиків масиву перерозподілених C. Щоб замінити масиви on-stack, у вас є std :: array , починаючи з C ++ 11. Щоб замінити VLA на on-stack, у вас буде std :: dynarray на C ++ 14 або C ++ 17.

І не заманюйте, realloc час від часу копіює свої дані. (Коли він не знаходить достатньо місця на місці, щоб отримати перерозподілений буфер)

Про еквівалент realloc для C ++ немає, update , що відповідає new не існує realloc відповідає malloc . І це не щось відсутнє на мові. Це було вирішено за допомогою класу std :: vector . Вона керує самою своєю пам'яттю, вона ефективна, і ні, це не невимушений стиль його використання. У C ++ стандартний спосіб мати масив, який може змінювати розмір.

0
додано
IT KPI C/С++ новым годом
IT KPI C/С++ новым годом
747 учасників

Чат обсуждения С/С++. - Вопросы "напишите за меня лабу" - это оффтоп. - Оффтоп, флуд, оскорбления и вбросы здесь не приняты. - За нарушение - предупреждение или mute на неделю. - За спам и рекламу - ban. Все чаты IT KPI: https://t.me/itkpi/1147

ІТ КПІ - Java
ІТ КПІ - Java
436 учасників