Чому динамічна пам'ять дозволяє маніпулювати масивами під час виконання?

Чи це лише один з тих, "питання, як працює мова"? РЕДАГУВАТИ:

Чому динамічна пам'ять дозволяє виділити розмір масивів під час виконання?

Чому я не можу просто використовувати змінну, викликану зі стека, на відміну від змінної, викликаної з купи? Вони обидві змінні, їх просто називають з іншого місця, їх треба вручну видалити та створювати. Змінні, створені в стеку, можуть зміна під час роботи справа?

2
"Ви можете замислитися про різницю між декларуванням нормального масиву та призначенням динамічної пам'яті вказівнику, як ми вже зробили. Найважливішою відмінністю є те, що розмір масиву повинен бути постійним значенням, яке обмежує його розмір до того, що ми вирішуємо на момент розробки програми перед його виконанням, тоді як динамічне розподіл пам'яті дозволяє призначити пам'ять під час виконання програми (виконання) за допомогою будь-якої змінної або константного значення, як його розміру ". -cplusplus.org @TomerArazy Я не розумію, що вони кажуть?
додано Автор moonbeamer2234, джерело
"Ви можете замислитися про різницю між декларуванням нормального масиву та призначенням динамічної пам'яті вказівнику, як ми вже зробили. Найважливішою відмінністю є те, що розмір масиву повинен бути постійним значенням, яке обмежує його розмір до того, що ми вирішуємо на момент розробки програми перед його виконанням, тоді як динамічне розподіл пам'яті дозволяє призначити пам'ять під час виконання програми (виконання) за допомогою будь-якої змінної або константного значення, як його розміру ". -cplusplus.org @TomerArazy Я не розумію, що вони кажуть?
додано Автор moonbeamer2234, джерело
Будь ласка, виділіть приміщення з питання. Напишіть свої думки чітко як речення і поставте знак питання лише з актуального питання. Важко сказати, що саме ви зрозуміли і чого ти запитуєш.
додано Автор Theodoros Chatzigiannakis, джерело
@TomerArazy правильно. Мій коментар мав на увазі C ++. Я навіть не бачив теги C!
додано Автор juanchopanza, джерело
@TomerArazy правильно. Мій коментар мав на увазі C ++. Я навіть не бачив теги C!
додано Автор juanchopanza, джерело
@TomerArazy правильно. Мій коментар мав на увазі C ++. Я навіть не бачив теги C!
додано Автор juanchopanza, джерело
Динамічне виділення дозволяє вибрати розмір масиву під час виконання. Розмір виділених об'єктів стека повинен бути відомий під час компіляції.
додано Автор juanchopanza, джерело
@ user1907736: це прямо протилежне; розмовляючи лише про стандартні функції, ви не можете отримати розмір динамічно виділеного блоку пам'яті, але ви можете змінити його розмір, використовуючи realloc (хоча цей може призвести до переміщення блоку в пам'ять).
додано Автор Matteo Italia, джерело
@ user1907736: це прямо протилежне; розмовляючи лише про стандартні функції, ви не можете отримати розмір динамічно виділеного блоку пам'яті, але ви можете змінити його розмір, використовуючи realloc (хоча цей може призвести до переміщення блоку в пам'ять).
додано Автор Matteo Italia, джерело
@ user1907736: це прямо протилежне; розмовляючи лише про стандартні функції, ви не можете отримати розмір динамічно виділеного блоку пам'яті, але ви можете змінити його розмір, використовуючи realloc (хоча цей може призвести до переміщення блоку в пам'ять).
додано Автор Matteo Italia, джерело
@TomerArazy У поточному стандарті C, так. Не в поточному стандарті C ++, а не у версії стандарту C (C89/"ANSI"), багато проектів все-таки обмежуються, для кращого або для гіршого.
додано Автор delnan, джерело
@TomerArazy У поточному стандарті C, так. Не в поточному стандарті C ++, а не у версії стандарту C (C89/"ANSI"), багато проектів все-таки обмежуються, для кращого або для гіршого.
додано Автор delnan, джерело
@TomerArazy У поточному стандарті C, так. Не в поточному стандарті C ++, а не у версії стандарту C (C89/"ANSI"), багато проектів все-таки обмежуються, для кращого або для гіршого.
додано Автор delnan, джерело
@juanchopanza - неправда (принаймні не в поточному стандарті). Ви можете зробити щось на кшталт int a [n] , де n - це параметр, переданий до функції
додано Автор Tomer Arazy, джерело
Ви не можете маніпулювати розміром масиву під час виконання, незалежно від того, динамічно він виділений чи ні.
додано Автор Tomer Arazy, джерело
@TomerArazy Ха, коли-небудь ви використовували realloc() ?
додано Автор user529758, джерело
@TomerArazy Ха, коли-небудь ви використовували realloc() ?
додано Автор user529758, джерело
@ juanchopanza Невірний з C99.
додано Автор user529758, джерело
@ juanchopanza Невірний з C99.
додано Автор user529758, джерело
@ juanchopanza Невірний з C99.
додано Автор user529758, джерело
так ви можете визначити розмір динамічно виділеного масиву під час виконання. Але коли це буде вирішено, і вам буде виділений простір, більше не можна змінити його розмір. Але, можливо, ви можете використовувати пов'язаний список для збільшення розміру?
додано Автор 0x64, джерело
так ви можете визначити розмір динамічно виділеного масиву під час виконання. Але коли це буде вирішено, і вам буде виділений простір, більше не можна змінити його розмір. Але, можливо, ви можете використовувати пов'язаний список для збільшення розміру?
додано Автор 0x64, джерело
так ви можете визначити розмір динамічно виділеного масиву під час виконання. Але коли це буде вирішено, і вам буде виділений простір, більше не можна змінити його розмір. Але, можливо, ви можете використовувати пов'язаний список для збільшення розміру?
додано Автор 0x64, джерело

7 Відповіді

Чому я не можу просто використовувати змінну, викликану зі стека, на відміну від змінної, викликаної з купи?

Розподіл купи дозволяє вам більше контролювати пам'ять.

Також існують обмеження, коли мова йде про стек змінних.


// попередження: застосовується тільки до ПК, може бути неправдою для інших архітектур, якими я не знайома. (mips, motorola 68000 і т. д. Все, що не пов'язано з x86, bascially).

Змінні, створені в стекі, можуть змінюватися під час виконання runtime?

Їх SIZE не може змінити.

  1. Stack has limited size. Size is decided by operating system AND compiler. If stack becomes too big, program dies because of stack overflow. Classic example:

    int main(int argc, char** argv){
        char buffer[1024*1024*64];
        buffer[0] = 0;
        return 0;
    }
    

    This program will crash if compiled with default settings on windows and it should crash on linux as well. That's because default stack size is 1 MB on 32bit windows and 8 MB on 32 bit linux (system may change this, though, using ulimit), and 64-megabyte array won't fit on stack.

  2. If your varaible is located between two other variables on stack, you can't change its size, no matter what. At least on x86/64 cpus.

  3. You can, in theory, increase size of stack array if it is the last thing on stack. (if I remember correctly, there was possibly non-standard C function called alloca that could allocate arrays on stack). However, you'll still hit stack size limit.

To understand WHY there are such limits, you need to step back from C++, and learn a bit of assembly. Try to find a book that covers segments (data/code/stack), explains where function return addresses are stored, and, preferably, tells you about protected mode. That should help.

Of course, there is a bit of a problem. Assembly knowledge will help only for particular family of CPUs. Different CPU with C++ compiler may use different rules.

--повідомлення

Чому динамічна пам'ять дозволяє виділяти розмір масивів під час виконання?

Залежно від арки, розмір стека може бути більш-менш фіксованим. У вас є деяка область пам'яті, зарезервована для стека, скажімо за адресою 0x00100000..0x00200000, і всі змінні, розташовані на стекі, будуть десь у цій області. Розташування нових змінних визначається (якщо я пам'ятаю правильно) "стек-покажчик", який рухається у напрямку, визначеному ЦП. Коли ви додаєте нову змінну в стеку, рух покажчика стеку (напрямок руху визначається процесором) за змінною величиною, а змінна буде розташовуватися в адресах між старою та новою позицією пам'яті. Оскільки простір стеків може бути обмежений, і тому що змінні є сусідніми (плюс функції повернення адреси також зберігаються на стекі), ви не можете раптом забити 2 ГБ масив посередині нього. Основна проблема полягає не в фактично обмеженому розмірі, але змінні сусідні один з одним.

Тепер HEAP відрізняється. Розподіл купу, в теорії , може повернути вам будь-яку адресу з усього адресного простору, але на практиці деякі адреси будуть зарезервовані (на 32-бітових вікнах у вас є лише 2 ... 3 ГБ доступні з всього 4 Гб простору, наприклад). Через те, що у вас набагато більше вільного простору, і тому що виділені блоки не повинні бути сусідніми, ви можете вільно виділяти великий масив і (теоретично) навіть змінювати їх розмір (на практиці такі функції, як realloc, можливо, просто зробити новий масив, копіювати старе вміст у новий масив, а потім вбити старий масив).

Зверніть увагу, що є додаткові приховані дані. Наприклад, адреси, які повертаються вам функціями виділення купу, - це не фізичні адреси, а віртуальні адреси, і насправді ОС може перемістити вашу програму у фізичну пам'ять, тоді як (віртуальні) адреси, що використовуються в межах програми, залишаться незмінними.

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

4
додано
@SigTerm: насправді, немає згадки про стек в C ++; так що це стосується і C ++, хоча для цього може знадобитися зміна ABI. Як Хаскелл, так і Руст складають машинний код і використовують нативний стовп сегментований , тут немає суперечностей. Проте всі методи, які я бачив до цих пір, додавали деяких накладних витрат, хоча найкращий варіант полягає в тому, що програма, начебто, перехоплює несправності сегментації (або якийсь інший тип сигналу ОС) і розширює стек потім (примітка: стек може не можна розширювати, в цьому випадку вам потрібна структура пов'язаних списків для стеку).
додано Автор Matthieu M., джерело
Я хотів би зазначити, що деякі мови і компілятори ввели сегментовані стеки деякий час тому назад; хоча вони можуть не працювати з надзвичайно великими асигнуваннями стеків, вони дозволяють не натискати помилку стека-переповнення навіть при дуже глибоких рекурсіях, оскільки вам призначено використання всієї доступної пам'яті у вашій системі.
додано Автор Matthieu M., джерело
До речі, на виділенні стеків runtime x86 можна запобігти оптимізації, зокрема "пропустити покажчик фрейму стек". Якщо кожна функція заздалегідь знає, скільки даних він матиме у стекі, вказівник фрейму стека буде зайвим: положення кожної локальної змінної може бути розрахована з фіксованими змінами з покажчика стека, тому EBP може використовуватися як додаткове загальне призначення зареєструвати і стек колір установки/очищення коду може бути опущений; це не стосується розподілу стеків runtime, що потребує EBP-адресації. Див. Також stackoverflow.com/questions/4343850/…
додано Автор Matteo Italia, джерело
@MatthieuM .: Ось чому я додав "Різні процесори можуть використовувати різні правила". Що стосується мов/компіляторів ... Я не чув про такі компілятори C ++. Можливо, я просто не знаю про них. Що стосується інших мов, то я не думаю, що це актуально тут. Повідомлення позначено як C/C ++, а AFAIK C ++ зазвичай перекладається на машинний код і використовує власний стек. Якщо інша мова використовує інший тип стека, це буде невластивий стек, створений спеціально для цієї мови. Іншими словами - зовсім інша історія.
додано Автор SigTerm, джерело

Чому я не можу просто використовувати змінну, викликану зі стека, на відміну від змінної, викликаної з купи?

Розподіл купи дозволяє вам більше контролювати пам'ять.

Також існують обмеження, коли мова йде про стек змінних.


// попередження: застосовується тільки до ПК, може бути неправдою для інших архітектур, якими я не знайома. (mips, motorola 68000 і т. д. Все, що не пов'язано з x86, bascially).

Змінні, створені в стекі, можуть змінюватися під час виконання runtime?

Їх SIZE не може змінити.

  1. Stack has limited size. Size is decided by operating system AND compiler. If stack becomes too big, program dies because of stack overflow. Classic example:

    int main(int argc, char** argv){
        char buffer[1024*1024*64];
        buffer[0] = 0;
        return 0;
    }
    

    This program will crash if compiled with default settings on windows and it should crash on linux as well. That's because default stack size is 1 MB on 32bit windows and 8 MB on 32 bit linux (system may change this, though, using ulimit), and 64-megabyte array won't fit on stack.

  2. If your varaible is located between two other variables on stack, you can't change its size, no matter what. At least on x86/64 cpus.

  3. You can, in theory, increase size of stack array if it is the last thing on stack. (if I remember correctly, there was possibly non-standard C function called alloca that could allocate arrays on stack). However, you'll still hit stack size limit.

Щоб зрозуміти, ЧОМУ існують такі обмеження, вам потрібно відмовитися від C + +, і навчитися трохи збірки. Спробуйте знайти книгу, яка охоплює сегменти (дані/код/​​стек), пояснює, де зберігаються адреси повернення функції, і, бажано, повідомляє про захищений режим. Це має допомогти.

Звичайно, є трохи проблеми. Знання збірки допоможуть лише для певного сімейства процесорів. Різноманітний процесор з компілятором C ++ може використовувати різні правила.

--повідомлення

Чому динамічна пам'ять дозволяє виділяти розмір масивів під час виконання?

Залежно від арки, розмір стека може бути більш-менш фіксованим. У вас є деяка область пам'яті, зарезервована для стека, скажімо за адресою 0x00100000..0x00200000, і всі змінні, розташовані на стекі, будуть десь у цій області. Розташування нових змінних визначається (якщо я пам'ятаю правильно) "стек-покажчик", який рухається у напрямку, визначеному ЦП. Коли ви додаєте нову змінну в стеку, рух покажчика стеку (напрямок руху визначається процесором) за змінною величиною, а змінна буде розташовуватися в адресах між старою та новою позицією пам'яті. Оскільки простір стеків може бути обмежений, і тому що змінні є сусідніми (плюс функції повернення адреси також зберігаються на стекі), ви не можете раптом забити 2 ГБ масив посередині нього. Основна проблема полягає не в фактично обмеженому розмірі, але змінні сусідні один з одним.

Тепер HEAP відрізняється. Розподіл купу, в теорії , може повернути вам будь-яку адресу з усього адресного простору, але на практиці деякі адреси будуть зарезервовані (на 32-бітових вікнах у вас є лише 2 ... 3 ГБ доступні з всього 4 Гб простору, наприклад). Через те, що у вас набагато більше вільного простору, і тому що виділені блоки не повинні бути сусідніми, ви можете вільно виділяти великий масив і (теоретично) навіть змінювати їх розмір (на практиці такі функції, як realloc, можливо, просто зробити новий масив, копіювати старе вміст у новий масив, а потім вбити старий масив).

Зверніть увагу, що є додаткові приховані дані. Наприклад, адреси, які повертаються вам функціями виділення купу, - це не фізичні адреси, а віртуальні адреси, і насправді ОС може перемістити вашу програму у фізичну пам'ять, тоді як (віртуальні) адреси, що використовуються в межах програми, залишаться незмінними.

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

4
додано
@SigTerm: насправді, немає згадки про стек в C ++; так що це стосується і C ++, хоча для цього може знадобитися зміна ABI. Як Хаскелл, так і Руст складають машинний код і використовують нативний стовп сегментований , тут немає суперечностей. Проте всі методи, які я бачив до цих пір, додавали деяких накладних витрат, хоча найкращий варіант полягає в тому, що програма, начебто, перехоплює несправності сегментації (або якийсь інший тип сигналу ОС) і розширює стек потім (примітка: стек може не можна розширювати, в цьому випадку вам потрібна структура пов'язаних списків для стеку).
додано Автор Matthieu M., джерело
Я хотів би зазначити, що деякі мови і компілятори ввели сегментовані стеки деякий час тому назад; хоча вони можуть не працювати з надзвичайно великими асигнуваннями стеків, вони дозволяють не натискати помилку стека-переповнення навіть при дуже глибоких рекурсіях, оскільки вам призначено використання всієї доступної пам'яті у вашій системі.
додано Автор Matthieu M., джерело
До речі, на виділенні стеків runtime x86 можна запобігти оптимізації, зокрема "пропустити покажчик фрейму стек". Якщо кожна функція заздалегідь знає, скільки даних він матиме у стекі, вказівник фрейму стека буде зайвим: положення кожної локальної змінної може бути розрахована з фіксованими змінами з покажчика стека, тому EBP може використовуватися як додаткове загальне призначення зареєструвати і стек колір установки/очищення коду може бути опущений; це не стосується розподілу стеків runtime, що потребує EBP-адресації. Див. Також stackoverflow.com/questions/4343850/…
додано Автор Matteo Italia, джерело
@MatthieuM .: Ось чому я додав "Різні процесори можуть використовувати різні правила". Що стосується мов/компіляторів ... Я не чув про такі компілятори C ++. Можливо, я просто не знаю про них. Що стосується інших мов, то я не думаю, що це актуально тут. Повідомлення позначено як C/C ++, а AFAIK C ++ зазвичай перекладається на машинний код і використовує власний стек. Якщо інша мова використовує інший тип стека, це буде невластивий стек, створений спеціально для цієї мови. Іншими словами - зовсім інша історія.
додано Автор SigTerm, джерело

Чому я не можу просто використовувати змінну, викликану зі стека, на відміну від змінної, викликаної з купи?

Розподіл купи дозволяє вам більше контролювати пам'ять.

Також існують обмеження, коли мова йде про стек змінних.


// попередження: застосовується тільки до ПК, може бути неправдою для інших архітектур, якими я не знайома. (mips, motorola 68000 і т. д. Все, що не пов'язано з x86, bascially).

Змінні, створені в стекі, можуть змінюватися під час виконання runtime?

Їх SIZE не може змінити.

  1. Stack has limited size. Size is decided by operating system AND compiler. If stack becomes too big, program dies because of stack overflow. Classic example:

    int main(int argc, char** argv){
        char buffer[1024*1024*64];
        buffer[0] = 0;
        return 0;
    }
    

    This program will crash if compiled with default settings on windows and it should crash on linux as well. That's because default stack size is 1 MB on 32bit windows and 8 MB on 32 bit linux (system may change this, though, using ulimit), and 64-megabyte array won't fit on stack.

  2. If your varaible is located between two other variables on stack, you can't change its size, no matter what. At least on x86/64 cpus.

  3. You can, in theory, increase size of stack array if it is the last thing on stack. (if I remember correctly, there was possibly non-standard C function called alloca that could allocate arrays on stack). However, you'll still hit stack size limit.

Щоб зрозуміти, ЧОМУ існують такі обмеження, вам потрібно відмовитися від C + +, і навчитися трохи збірки. Спробуйте знайти книгу, яка охоплює сегменти (дані/код/​​стек), пояснює, де зберігаються адреси повернення функції, і, бажано, повідомляє про захищений режим. Це має допомогти.

Звичайно, є трохи проблеми. Знання збірки допоможуть лише для певного сімейства процесорів. Різноманітний процесор з компілятором C ++ може використовувати різні правила.

--повідомлення

Чому динамічна пам'ять дозволяє виділяти розмір масивів під час виконання?

Залежно від арки, розмір стека може бути більш-менш фіксованим. У вас є деяка область пам'яті, зарезервована для стека, скажімо за адресою 0x00100000..0x00200000, і всі змінні, розташовані на стекі, будуть десь у цій області. Розташування нових змінних визначається (якщо я пам'ятаю правильно) "стек-покажчик", який рухається у напрямку, визначеному ЦП. Коли ви додаєте нову змінну в стеку, рух покажчика стеку (напрямок руху визначається процесором) за змінною величиною, а змінна буде розташовуватися в адресах між старою та новою позицією пам'яті. Оскільки простір стеків може бути обмежений, і тому що змінні є сусідніми (плюс функції повернення адреси також зберігаються на стекі), ви не можете раптом забити 2 ГБ масив посередині нього. Основна проблема полягає не в фактично обмеженому розмірі, але змінні сусідні один з одним.

Тепер HEAP відрізняється. Розподіл купу, в теорії , може повернути вам будь-яку адресу з усього адресного простору, але на практиці деякі адреси будуть зарезервовані (на 32-бітових вікнах у вас є лише 2 ... 3 ГБ доступні з всього 4 Гб простору, наприклад). Через те, що у вас набагато більше вільного простору, і тому що виділені блоки не повинні бути сусідніми, ви можете вільно виділяти великий масив і (теоретично) навіть змінювати їх розмір (на практиці такі функції, як realloc, можливо, просто зробити новий масив, копіювати старе вміст у новий масив, а потім вбити старий масив).

Зверніть увагу, що є додаткові приховані дані. Наприклад, адреси, які повертаються вам функціями виділення купу, - це не фізичні адреси, а віртуальні адреси, і насправді ОС може перемістити вашу програму у фізичну пам'ять, тоді як (віртуальні) адреси, що використовуються в межах програми, залишаться незмінними.

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

4
додано
@SigTerm: насправді, немає згадки про стек в C ++; так що це стосується і C ++, хоча для цього може знадобитися зміна ABI. Як Хаскелл, так і Руст складають машинний код і використовують нативний стовп сегментований , тут немає суперечностей. Проте всі методи, які я бачив до цих пір, додавали деяких накладних витрат, хоча найкращий варіант полягає в тому, що програма, начебто, перехоплює несправності сегментації (або якийсь інший тип сигналу ОС) і розширює стек потім (примітка: стек може не можна розширювати, в цьому випадку вам потрібна структура пов'язаних списків для стеку).
додано Автор Matthieu M., джерело
Я хотів би зазначити, що деякі мови і компілятори ввели сегментовані стеки деякий час тому назад; хоча вони можуть не працювати з надзвичайно великими асигнуваннями стеків, вони дозволяють не натискати помилку стека-переповнення навіть при дуже глибоких рекурсіях, оскільки вам призначено використання всієї доступної пам'яті у вашій системі.
додано Автор Matthieu M., джерело
До речі, на виділенні стеків runtime x86 можна запобігти оптимізації, зокрема "пропустити покажчик фрейму стек". Якщо кожна функція заздалегідь знає, скільки даних він матиме у стекі, вказівник фрейму стека буде зайвим: положення кожної локальної змінної може бути розрахована з фіксованими змінами з покажчика стека, тому EBP може використовуватися як додаткове загальне призначення зареєструвати і стек колір установки/очищення коду може бути опущений; це не стосується розподілу стеків runtime, що потребує EBP-адресації. Див. Також stackoverflow.com/questions/4343850/…
додано Автор Matteo Italia, джерело
@MatthieuM .: Ось чому я додав "Різні процесори можуть використовувати різні правила". Що стосується мов/компіляторів ... Я не чув про такі компілятори C ++. Можливо, я просто не знаю про них. Що стосується інших мов, то я не думаю, що це актуально тут. Повідомлення позначено як C/C ++, а AFAIK C ++ зазвичай перекладається на машинний код і використовує власний стек. Якщо інша мова використовує інший тип стека, це буде невластивий стек, створений спеціально для цієї мови. Іншими словами - зовсім інша історія.
додано Автор SigTerm, джерело

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

Стандарт для C99 і пізніших версій (але не C ++, хоча, на мій погляд, деякі компілятори (g ++?) Мають розширення, що дозволяють це, принаймні, іноді) дозволяє "масивів змінної довжини" у функціях, але, як і фіксовані масиви розмірів, вони "зникають" коли функція закінчується.

У стандарті для C ++ всі масиви повинні мати "відомі (постійні) довжини під час компіляції". Ви повинні використовувати купу, щоб створити те, що не має постійної довжини, відоме під час компіляції. Це "мова, як працює мова".

Сказавши це, є і розумна причина для цього. Стек простір дуже обмежений, і це насправді досить "небезпечно" для вичерпання стеку, оскільки немає нічого, що програма може зробити про це - вона збірається, і немає безпечного/розумного способу відновлення. Можна обробити запуск з перешкод (є винятком виключення виключення C ++, але принаймні, програма може відобразити деяке обґрунтоване повідомлення про помилку і, можливо, продовжувати певним чином, навіть якщо це не вдалося з тим, що він намагався зробити, коли він пробіг вичерпаний простір)

Звичайно, "C ++ шлях" полягає в тому, щоб не писати код, який маніпулює розмірами масиву вручну, але використовуйте один із заздалегідь визначених типів контейнерів, таких як std :: vector та подібні.

Edit Note that once an array is allocated from the heap, it remains whatever size it was when it was allocated. What can be done to alter its size is to allocate ANOTHER lump of memory, for a second array, of a different size, and then copy the contents of the "old" array into the "new" array - and as long as this is done in a way where the code can only ever see the "current" value of the array address [pointer to first element], nobody will know that it wasn't the same array.

3
додано

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

Стандарт для C99 і пізніших версій (але не C ++, хоча, на мій погляд, деякі компілятори (g ++?) Мають розширення, що дозволяють це, принаймні, іноді) дозволяє "масивів змінної довжини" у функціях, але, як і фіксовані масиви розмірів, вони "зникають" коли функція закінчується.

У стандарті для C ++ всі масиви повинні мати "відомі (постійні) довжини під час компіляції". Ви повинні використовувати купу, щоб створити те, що не має постійної довжини, відоме під час компіляції. Це "мова, як працює мова".

Сказавши це, є і розумна причина для цього. Стек простір дуже обмежений, і це насправді досить "небезпечно" для вичерпання стеку, оскільки немає нічого, що програма може зробити про це - вона збірається, і немає безпечного/розумного способу відновлення. Можна обробити запуск з перешкод (є винятком виключення виключення C ++, але принаймні, програма може відобразити деяке обґрунтоване повідомлення про помилку і, можливо, продовжувати певним чином, навіть якщо це не вдалося з тим, що він намагався зробити, коли він пробіг вичерпаний простір)

Звичайно, "C ++ шлях" полягає в тому, щоб не писати код, який маніпулює розмірами масиву вручну, але використовуйте один із заздалегідь визначених типів контейнерів, таких як std :: vector та подібні.

Edit Note that once an array is allocated from the heap, it remains whatever size it was when it was allocated. What can be done to alter its size is to allocate ANOTHER lump of memory, for a second array, of a different size, and then copy the contents of the "old" array into the "new" array - and as long as this is done in a way where the code can only ever see the "current" value of the array address [pointer to first element], nobody will know that it wasn't the same array.

3
додано

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

Стандарт для C99 і пізніших версій (але не C ++, хоча, на мій погляд, деякі компілятори (g ++?) Мають розширення, що дозволяють це, принаймні, іноді) дозволяє "масивів змінної довжини" у функціях, але, як і фіксовані масиви розмірів, вони "зникають" коли функція закінчується.

У стандарті для C ++ всі масиви повинні мати "відомі (постійні) довжини під час компіляції". Ви повинні використовувати купу, щоб створити те, що не має постійної довжини, відоме під час компіляції. Це "мова, як працює мова".

Сказавши це, є і розумна причина для цього. Стек простір дуже обмежений, і це насправді досить "небезпечно" для вичерпання стеку, оскільки немає нічого, що програма може зробити про це - вона збірається, і немає безпечного/розумного способу відновлення. Можна обробити запуск з перешкод (є винятком виключення виключення C ++, але принаймні, програма може відобразити деяке обґрунтоване повідомлення про помилку і, можливо, продовжувати певним чином, навіть якщо це не вдалося з тим, що він намагався зробити, коли він пробіг вичерпаний простір)

Звичайно, "C ++ шлях" полягає в тому, щоб не писати код, який маніпулює розмірами масиву вручну, але використовуйте один із заздалегідь визначених типів контейнерів, таких як std :: vector та подібні.

Edit Note that once an array is allocated from the heap, it remains whatever size it was when it was allocated. What can be done to alter its size is to allocate ANOTHER lump of memory, for a second array, of a different size, and then copy the contents of the "old" array into the "new" array - and as long as this is done in a way where the code can only ever see the "current" value of the array address [pointer to first element], nobody will know that it wasn't the same array.

3
додано

Стек має обмежений розмір, і що-небудь на ньому втрачається, коли ваша функція повертається після зміни покажчика стека. Кеп пам'яті може бути набагато більшим і буде жити до тих пір, поки прикладна програма працює, або хтось називає функцію вилучення пам'яті.

Проте в Windows все-таки можна виділити "динамічно розмір" пам'яті на стек, використовуючи alloca. Це буде очищено так само, як і будь-які інші місцеві жителі, що базуються на стеку, очищені, отже, вам не доведеться явно вільний пам'ять.

See here: http://msdn.microsoft.com/en-US/library/wb1s57t5(v=vs.80).aspx

0
додано
Тож, що я мав на увазі, це означає, що функція locals/alloc вирівняється, коли функція повертається
додано Автор paulm, джерело
_alloca виділяє розміри байтів з стеку програми. Виділений пробіл автоматично звільняється, коли функція виклику виходить (не тоді, коли розподіл просто виходить із сфери дії). Тому не передайте значення покажчика, яке _alloca повертає як аргумент для вільного
додано Автор paulm, джерело
"і очищається, коли ваша функція повертається". Неправильно змінюється значення покажчика стека, але стек не очищено. "alloca", але це неможливо перерозподілити, тому що не існує переолко
додано Автор SigTerm, джерело
@pualm: також невірно. Раніше зберігаються дані все ще містяться на тій же адресі без змін. Звичайно, вона буде перезаписана наступною операцією стека, але вона не "очищена". Єдине, що відбувається, полягає в тому, що зміни покажчика стека змінюються, і все.
додано Автор SigTerm, джерело
IT KPI C/С++ новым годом
IT KPI C/С++ новым годом
747 учасників

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