Динамично разпределяне на памет за промяна на размера на масива, започвайки с неизвестен размер C++

Как да разпределя динамично масив, където размерът ще се променя, тъй като нещата, съхранени в масива, ще бъдат прочетени от файл. Има много предложения за използване на вектор, но искам да знам как да го направя по начина на масива.

Знам, че за разпределението на паметта е така

int count;
int *n = new int[count];

Кажете, че променливата count ще се увеличи в цикъл. Как мога да променя размера на масива?

Освен това, какво ще стане, ако го направим с malloc?


person user2159166    schedule 04.10.2014    source източник
comment
Ще трябва да изтриете вектора n и да създадете нов, по-голям. И няма смисъл да използвате malloc, ако можете да използвате new.   -  person Javi    schedule 04.10.2014
comment
Вижте примера за realloc: cplusplus.com/reference/cstdlib/realloc   -  person Ashalynd    schedule 04.10.2014
comment
@JaviV С изключение на това, че malloc може да поддържа realloc, докато няма еквивалент за new.   -  person Neil Kirk    schedule 04.10.2014
comment
защо не използвате вектор?   -  person pqnet    schedule 04.10.2014
comment
Трябва ли да инициализирам броя на 0?   -  person user2159166    schedule 04.10.2014


Отговори (3)


Не се опитвайте да накарате разпределението на масива да следва точно изискванията за непрекъснато променящ се размер на това, което ще съхранявате. Помислете за използването на традиционното кратно 2*N. Когато масивът е пълен, преразпределете чрез увеличаване с 2*N (разпределете нов масив два пъти по-голям) и копирайте елементи отгоре. Това амортизира логаритмично разходите за преразпределение.

Имайте предвид, че тази логика, която възнамерявате да приложите с масиви от ниско ниво, е точно причината, поради която векторът съществува. Малко вероятно е да внедрите своя собствена толкова ефективно или без грешки.

Но ако сте настроени на това, продължавайте да броите кратно на 2, като започнете с нещо реалистично (или най-близкото кратно на 2, закръглено нагоре)

person codenheim    schedule 04.10.2014
comment
Това означава ли, че ще трябва да направя много масиви, тъй като трябва да копирам елементите? - person user2159166; 04.10.2014
comment
Или мога да копирам в един масив и след това да освободя първия масив, след което да преразпределя отново и да копирам в стария масив и да освободя новия масив? Така че основно просто да използвате само два масива? - person user2159166; 04.10.2014
comment
Без да правите нищо добро, за да се придържате към стария, единственият път, когато преразпределяте е, когато надраснете масива, така че винаги се движите нагоре, а не надолу. След като масивът нарасне, всъщност няма никакво предимство в намаляването на размера, просто го оставете така, както е. - person codenheim; 05.10.2014
comment
Не, след преоразмеряване, след като копирате елементите в новия масив, изтрийте стария. - person codenheim; 05.10.2014
comment
И това е един конкретен случай на употреба, при който е оправдано да използвате malloc/realloc за съхранение на масива. Второ, не забравяйте да капсулирате всичко това в клас. Класът трябва да има текущия размер и указателя на масива. - person codenheim; 05.10.2014
comment
Бихте ли могли да дадете пример? - person user2159166; 05.10.2014

Можете да запазите два указателя, p и q(placeholder), когато броячът се промени, трябва да направите ново разпределение за p, преди това по-ранни разпределения трябва да бъдат отменени, дори преди това съдържанието на по-ранно p да бъде прехвърлено към ново p както добре.

int count, oldcount;
int *p = NULL;
int *q;
p = new int[count];
oldcount = count;

когато трябва да преразпределите:

q = new int[count];
memcpy(q, p, oldcount * sizeof(int)); // OR for (int i = 0; i < oldcount; i++) q[i] = p[i];   
delete [] p;
p = q;
oldcount = count; // for use later

Ако използвате malloc, calloc, тогава трябва да използвате като брой байтове за предаване в malloc. но не е необходимо с оператори new и delete в C++

person Dr. Debasish Jana    schedule 04.10.2014
comment
@JaviV благодаря, редактирах отговора ми и също благодаря на Wyzard - person Dr. Debasish Jana; 04.10.2014

Как мога да променя размера на масива?

Използване на new: Не можете. Размерът на обект (тук масивен обект) не може да се промени по време на изпълнение.

Ще трябва да създадете нов масив с подходящ размер, да копирате всички елементи от стария в новия масив и да унищожите стария. За да избегнете много преразпределения, винаги трябва да разпределяте повече, отколкото ви е необходимо. Проследявайте size (количеството елементи, които се използват в момента) и capacity (действителния размер на разпределения масив). След като искате да увеличите size, проверете дали все още има останала памет (size<capacity) и я използвайте, ако е възможно; в противен случай приложете гореспоменатия метод.

И това е точно това, което vector прави за вас: Но с RAII и всички възможни удобства.

person Columbo    schedule 04.10.2014
comment
Всъщност realloc не винаги премества блока памет. Ако има достатъчно непрекъсната памет след блока, който трябва да бъде преразпределен, тогава блокът не се премества. Ако блокът трябва да бъде преместен, realloc прави копирането... Така че не винаги трябва да се разпредели нова памет и да се копира - person ds27680; 04.10.2014
comment
@ds27680 Не говорим за malloc/realloc, а за new. - person Columbo; 04.10.2014
comment
Той всъщност попита как динамично да разпредели масив, чийто размер е длъжен да се промени. Той даде нов като пример (начина, по който той знае, че може да се направи разпределение). Вашият отговор, както го прочетох, би означавал, че винаги трябва да разпределяте ново и да копирате. Не споменахте, че имате предвид само нови, когато казвате: Не можете. - person ds27680; 04.10.2014
comment
– попита той също в края на въпроса си. Освен това, какво ще стане, ако го направим с malloc? Така че въпросът му очевидно не е само за new, но и за malloc. Докато вашият отговор създава впечатлението, че това, което казвате, като цяло е приложимо. - person ds27680; 04.10.2014
comment
@ds27680 О, не видях частта за malloc. - person Columbo; 04.10.2014