Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.75/55: Рейтинг темы: голосов - 55, средняя оценка - 4.75
0 / 0 / 0
Регистрация: 13.03.2015
Сообщений: 52

Зачем в Си нужно динамическое выделение памяти?

25.07.2017, 21:15. Показов 12613. Ответов 31
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Зачем в Си может потребоваться динамическое выделение памяти, если программа пишется для MCU ?
Иные товарищи говорят "что бы оптимальнее использовать память". Но это общее "за всё хорошее, против всего плохого".

Давайте посмотрим, какие преимущества у динамического массива перед статическим. Ведь говоря о динамическом распределении памяти мы говорим именно о динамическом массиве, иначе какой толк - динамически выделить память под одну переменную и хранить на нее ссылку? Динамический массив может расширяться и сжиматься, а статический - нет. И, типа, если у нас мало неких объектов (точнее их предтечей - структурных переменных), то мы можем использовать мало памяти, если много - то сможем расширить массив. И если 90% времени наш массив занимает 10% памяти контролера, а 10% времени - 90% памяти, то в среднем массив будет занимать 18% памяти. Круто?

Но смотрите. Если массив объектов у нас - один-единственный, а все остальные переменные - статические, то они или влезут в оставшиеся 10% физической памяти при пиковой нагрузке или не влезут. И если не влезут - беда-беда. А если влезут, то какая разница, заняты ли оставшиеся 90% памяти 10% времени или 100% времени?

Если у нас массивов объектов два (и более), то динамические массивы могу дать выигрыш, если сумма максимальных размеров массивов больше 100% памяти MCU, но средняя сумма размеров массивов никогда не превысит 100% (и чем больше эта разница, тем эффективней использовать динамическое распределение памяти). Т.е. если данные о неких сущностях занимают, скажем, 60% памяти и при этом как-бы "перетекают" из массива в массив.

Может ли кто-нибудь предложить красивый кейс/задачу в которой данные ведут себя подобным образом?

P.S. Да, динамические массивы могут быть эффективны в случае наличия чего-то вроде файла подкачки (90% времени используем оперативную память, 10% - расширяемся в файл подкачки и теряем в скорости). Но!
1. В качестве вместилища файла подкачки флеш-память (а мы подразумеваем ее, говоря об MCU) не очень подходит. Постоянные перезаписи, знаете ли...
2. Говоря об MCU мы зачастую понимаем около-реалтаймовские задачи. А там вот-это-вот-всё "память кончилась, раскручиваю блины, ща-ща-ща, еще чуть-чуть", знаете ли...
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
25.07.2017, 21:15
Ответы с готовыми решениями:

Нужно сделать динамическое выделение памяти
Не понимаю как сделать так чтобы было использовано динамическое выделение памяти для массивов. #include <iostream> #include...

Для чего нужно динамическое выделение памяти
Расскажите пожалуйста про динамическое выделение памяти в примерах если можно.Зачем оно нужно,почему без него никак?(в конкретных...

Нужно переделать код под динамическое выделение памяти
Добрый вечер, помогите пожалуйста переделать код Нужно сделать динамическое выделение памяти вместо char input // 4 лаба.cpp:...

31
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 1,864
26.07.2017, 02:37
Студворк — интернет-сервис помощи студентам
Я ж говорю - не парьтесь, когда вам понадобится динамическое выделение - вы почувствуете :-), а до того оно всё равно будет казаться неестественным.

Кстати, пример //Mt хорош. Пакеты разного размера, приходят себе потихоньку, потом уходят. Добавим сюда уход пакетов не в том порядке, в котором пришли (ну там, QoS, или порт для каких-то пакетов занят, или ещё что) - и получаем задачку, в которой динамическое выделение практически неизбежно.
Правда, именно для этой задачки я бы использовал не malloc, а свой велосипед специально разработанный аллокатор.
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 382
26.07.2017, 02:50
Чето вы, ребята, ваапще не в ту степь ушли. Начали за здравие, за микроконтроллеры, а ушли в четрт знает вкуда.3дэМакс, рендерить... на микроконтроллере.. ну даёте. Вот в чем беда "неэмбеддеров", так в том, что они не понимают из чего состоит то, на чем они работают.
Цитата Сообщение от Ирсений
...но можно вызвать функцию, в которой объявляется статический массив. И после выхода из нее массив пхххх... растворится.
А как думаете, где она выделяется таким способом? Причем, будут различия - если объявите этот массив с квалификатором static - память под массив будет выделена в одном месте, и после выхода из функции она останется. А если без квалификатора static, то как думаете, в каком участке памяти она выделится? Что такое стек - слыхали? Аа, вот почитайте. И как думаете - вызывая штук 5 таких функций друг из друга - насколько просядет стек? В АРМ-совместимых и некоторых других МК стек расположен в той же ОЗУ и может занимать теоретически весь объем. А как думаете - рано или поздно стек может натолкнуться на внестековые выделенные участки? Думайте, думайте.
А теперь из той же функции напишем malloc(200) - как думаете, в какой области будет выделен адрес? И в виде чего он будет выделен? А где будет храниться переменная указателя, содержащая адрес выделенного массива?

Вообще, почему вы думаете, что память должна обязательно быть загружена на 100% Да ну. При около 100% загрузке вы рискуете получить отказ выделения или "пробой" стека. Стек во многих микроконтроллерах хранится в ОЗУ.
И еще. Допустим, у микроконтроллера 32 кБ ОЗУ, используется не больше 15 кБ и не будет больше, но зато у него 100 ножек и все заняты под завязку. Это неэффективное использование памяти? Прикажете ее выжечь? Ладно, есть микроконтроллер с 16 кБ ОЗУ но на 64 ножки - не хватает ножек.
И чето вы забываете, что Си никоим образом не отслеживает границы массивов. Особенно когда они выделены с помощью указателя. Вам что, слово "указатель" ни о чем не говорит разве?
Если вы пытаетесь провести параллели между PC и MCU, то нивкакую не получится - это совершенно разные системы, с разной организацией памяти и остального.
Чето эти ваши категоричные рассуждения о видах памяти напоминают рассуждения гаражного мастера дяди Васи о вкусе черной и красной икры.
Не попробовав на деле, вы все равно не поймете, как и для чего это работает.
Вобщем, какая-то категоричная тема, но пустая совершенно. Ваще ниачом, как у нас выражаются.

PS. Аа, я понял. Ясно. Это - вот что бывает, когда "неэмбеддеры" приходят в среду "эмбедда". Тогда у них и появляются файлы подкачки на флеше, да и про внешнюю ОЗУ они ниче не слышали, да и про карту памяти (распределение адресов) тоже.
0
0 / 0 / 0
Регистрация: 24.08.2009
Сообщений: 3
26.07.2017, 02:57
Связанные списки например.. Бывает очень удобно для хранения каких либо событий.
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 1,864
26.07.2017, 03:08
Кстати, вспомнил эмбеддерскую хрень, в которой есть не то что динамическое выделение памяти - garbage collector. NodeMCU.
0
1 / 1 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
26.07.2017, 08:03
В одном из недавних проектов на STM32F4 в SDROM было 64МБайта. И то, без динамического выделения не получалось статически сразу дать нужные объемы, только под критичные вещи, типа видеобуфера для экрана, для GUI и прочее. Память(куча) RTOS, TCP/IP, и прочее крутилось в в внешней SDROM, менеджер памяти использовал от FriiRTOS. Сильно упрощало жизнь.
0
0 / 0 / 0
Регистрация: 20.06.2010
Сообщений: 454
26.07.2017, 12:09
Цитата Сообщение от oomomstir
Кстати, пример //Mt хорош. Пакеты разного размера, приходят себе потихоньку, потом уходят. Добавим сюда уход пакетов не в том порядке, в котором пришли (ну там, QoS, или порт для каких-то пакетов занят, или ещё что) - и получаем задачку, в которой динамическое выделение практически неизбежно.
Правда, именно для этой задачки я бы использовал не malloc, а свой велосипед специально разработанный аллокатор.
Так и делают - есть N пулов буферов фиксированного размера - там и аллоцируют подходящий.

пример
Code
1
2
3
4
5
6
7
8
9
10
11
12
  SIZE    MAX    LOW    CNT  INUSE   HIGH
0   8700   8635   8700      0     28
4   1700   1698   1699      0      1
80   9000   8946   9000      0     34
256   9676   9453   9670    151    238
1550  37034  36707  36869     19    148
2048   8100   8092   8100      0      8
2560   8192   8178   8192      0     14
4096    100     96    100      0      0
8192    100     98    100      0      1
9344  20000  19912  20000      0      5
16384    340    340    340      0      0
0
0 / 0 / 0
Регистрация: 24.08.2009
Сообщений: 3
26.07.2017, 14:33
Цитата Сообщение от Ирсений
...но можно вызвать функцию, в которой объявляется статический массив. И после выхода из нее массив пхххх... растворится.
Кстати это не всегда возможно если массив большой..
0
0 / 0 / 0
Регистрация: 22.08.2009
Сообщений: 525
26.07.2017, 15:27
Цитата Сообщение от Ирсений
...но можно вызвать функцию, в которой объявляется статический массив. И после выхода из нее массив пхххх... растворится.
Это как???!!!
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 1,864
26.07.2017, 15:30
Это товарищ не знает разницы между автоматическими и статическими переменными. Явно говорит об автоматических.

А что буфер может понадобиться после выхода из функции - ему в голову не пришло. Ничего страшного, со временем разберётся.
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 382
26.07.2017, 15:59
Эхехех.... Да этот "товарищь" со своим категоричным первым постом темы, претендующем по меньшей мере на "How to..." вообще чето заблудился в трех березах. Всё смешал - и файлы подкачки, которых в MCU не существует в том виде, которые он представляет, и флеш, и массивы. А про указатели он вообще видимо не слыхивал. Да и с представлением об организации памяти вообще - тож проблема. Зато суждения категоричные.. ну...

Статический массив, по определению языка Си, никуда не растворится при выходе из функции, потому что он объявлен квалификатором static и размещается в секции ОЗУ, определенной для таких массивов. В отличие от массивов, время жизни которых ограничено рамками функции.

Посмотрите наглядно: первая функция, в которой объявлены: обычным образом массив из 8 однобайтных элементов (автоматические), массив из 8 элементов static, и указатель, полученный динамически через malloc на 16 элементов
Code
1
2
3
4
5
6
7
8
void Funct1(void)
{
uint8_t array_funct[8];
static uint8_t array_static_q[8];
uint8_t *array_malloc;
array_malloc = malloc(16);
Funct2();
}
и думайте, думайте. Конец адресов ROM, равно как и вершина стека, в данном примере - 0x1FFF (старшие байты адреса опущены).
Видны наши 8 автоматических элементов в стеке и указатель, полученный от malloc.

<Изображение удалено>

потом вызывается вторая функция из первой: и аналогично то же самое с индексом 2.
Code
1
2
3
4
5
6
7
void Funct2(void)
{
uint8_t array2_funct[8];
static uint8_t array2_static_q[8];
uint8_t *array2_malloc;
array2_malloc = malloc(16);
}
Видно, что теперь наш массив разместился чуть дальше по адресам к началу.


<Изображение удалено>

А где же наши элементы, полученные по malloc??? и где массивы static??? Смотрим, на какие адреса указывают указатели в области стеков. Видим, что они указывают уже где-то в начале адресов ROM (начинаются с 0х2000 0000) и бежим туда: вот они! первый и второй массив:
и там с удивлением (!) обнаруживаем наши static-массивы, которые мы выделяли в функциях:


<Изображение удалено>

Так же, на последнем скрине, анализируя занимаемые адреса malloc-выделений, обнаруживаем "дырку" в 8 байт. Догадайтесь, что это за байда, и почему она всегда появляется между malloc-выделениями? Домашнее задание топикстартеру, разобраться, раз уж он претендует на "How to..."
0
0 / 0 / 0
Регистрация: 13.03.2015
Сообщений: 52
26.07.2017, 16:55
Цитата Сообщение от oomomstir
А что буфер может понадобиться после выхода из функции - ему в голову не пришло. Ничего страшного, со временем разберётся.
Вы - занятный :)

- Автоматический буфер легко удаляется из стека по завершении функции.
- Автоматический буфер нельзя передать, а вот динамический...
- Хорошо. Статический (или глобальный) буфер доступен любой функции.
- Глобальный буфер нельзя удалить, а вот динамический...
- Автоматический можно удалить
- А вот динамический...
- Статический будет доступен
- А вот динамический...
- Не хватает памяти - возьмите MCU подороже.
- Растратчик! Лучше сделаю динамические буферы.
- А если они одновременно разрастуться до размеров физ.памяти?
- Далась вам эта память! Куплю MCU подороже!
- Может лучше - статический массив и MCU подороже?
- Растратчик! Только malloc, только хардкор!
- А если физ.памяти не хватит?
- Куплю подороже, какие проблемы?

Судя по топику:
1. Динамический буфер в единственном числе легко заменяется статическим буфером такого же размера.
2. Динамический буфер в количестве "два и более" - отличный способ снизить цену аппаратной части системы за счет снижения надежности софтовой части.

Об этом следует помнить!
0
0 / 0 / 0
Регистрация: 06.12.2016
Сообщений: 382
26.07.2017, 17:04
Апять-двацатьпять. В Си нет понятия "динамического буфера". Буфер, выделяемый с помощью аллокатора - это всего лишь У-К-А-З-А-Т-Е-Л-Ь, указатель, 4-хбайтовая переменная (в 32-битной системе), содержащая АДРЕС первого элемента выделенного буфера (массива). А указатель можно и ручками выделить, в любом месте. И даже void*. По соглашениям, размер void* = 1 байт.

Черт, ему уже и "веселые картинки" нарисовал для прозрения, а он всё еще с менторством "следует помнить". Фееричный чел, хаха :) Ирсений, оставьте этот ваш менторский тон, а то недайбог кто прочтет, либо так же заблудится, либо смеяться будет.

Цитата Сообщение от Ирсений
- Хорошо. Статический (или глобальный) буфер доступен любой функции.
так статический с квалификатором static или глобальный?
С квалификатором static - НЕ доступен любым функциям кроме родительской. Но когда она будет вызвана, буфер заново не будет создаваться, и в нем содержимое осталось от предыдущего вызова функции, в целости и сохранности.

Цитата Сообщение от Ирсений
- Глобальный буфер нельзя удалить,
МОЖНО! объявите указатель на этот буфер void *ptr = globbuf и испортите его содержимое к чертям *(char*)ptr = 0x00. Теперь объявите новый буфер как указатель uint16_t *buf2 = ptr и пользуйтесь им вместо старого буфера. Даже пойдем дальше! нарежем еще буферов:
uint8_t *buf3 = ptr + 32;
int32_t *buf4 = ptr + 50;
Нннна-тебе, пользуйтесь вместо бывшего uint32_t globbuf[1000]. Но помните, обращение globbuf[10] = 50 испортит ваши новые буфера. Потому что имя буфера в системе осталось.

Цитата Сообщение от Ирсений
- Автоматический можно удалить
...нельзя. Он сам перестает быть актуальным, когда указатель вершины стека возвращается назад.
Цитата Сообщение от Ирсений
- А вот динамический...
нет такого понятия в Си.
Цитата Сообщение от Ирсений
- Статический будет доступен
только одной функции-родителю.

Ирсений писал(а):
2. Динамический буфер в количестве "два и более" - отличный способ снизить цену аппаратно части системы за счет снижения надежности софтовой части.
- В КОРНЕ НЕ ВЕРНОЕ утверждение, потому что утверждение в значительной мере бессмысленно и поверхтностно.

Ирсений, вы уж определитесь, в чем вы "варитесь" - в эмбедде или в писюках?
Потому что в эмбедде никто не будет выбирать МК впритык тютелька-в-тютельку. В большинстве случаев. Потому что:
а) прошивки могут обновляться в рамках сопровождения и поддержки устройства, добавляя или улучшая функционал. Нехватило памяти? перепаивать никто не станет.
б) прошивки могут исправляться на местах, когда обнаружен косяк не по вине программиста, а из-за недоработки составителей техзадания, а то и просто слегка другие условия, такое бывает. Прагриннист ругается матом, но делает, потому что "косяки заказчиков - за их счет".
в) программист сам может накосячить, типа "ах чорт, сигнал на входе АЦП шумит же сильно, надо было вместо скользящего среднего фильтр Калмана ставить"
г) железо подбирается не только по объемам ОЗУ, но и по аппаратному функционалу, по доступности, по наличию вообще таких моделей.
д) двухкратная разница в объеме ОЗУ = 10-15% разницы в цене при прочих равных условиях
е) глубина "просадки" стека вниз по адресам при использовании сторонних библиотек заранее неизвестна и не поддается точному до байта описанию. Следствие - всегда, запомните, ВСЕГДА есть довольно большой запас ОЗУ, рассчитанный на потребление стека и не используемый постоянно. На тяжелых сторонних либах глубина просадки стека может быть очень и очень значительной.
ж) куча (heap), из которой распределяется память для этих ваших динамических буферов, не может быть равна размеру ОЗУ целиком. Иначе у вас всё перехлестнется.
Именно по этим соображениям, использования ОЗУ на 99%, как вы хотите - не бывает по определению.
99% - это один миг до сбоя и ->
Ирсений писал(а):
Об этом следует помнить!
---------------------------------------------------------------------
PS. График использования ОЗУ МК в обобщенных среднестатистических применениях:


https://www.cyberforum.ru/savedimages/2017/07/26/wghpxnjsmasajw9rtyz.png
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
26.07.2017, 17:04

Нужно переделать код под динамическое выделение памяти
// 4 лаба.cpp: определяет точку входа для консольного приложения. // #define _CRT_SECURE_NO_WARNINGS #include&quot;stdafx.h&quot; ...

Нужно немного переделать программу: использовать функции и динамическое выделение памяти
Помогите переделать программу в соответствии с условиями: а) для хранения массивов используйте динамически распределяемую память; б)...

Стек, куча, хранение в памяти, динамическое выделение памяти, указатели в чем отличие?
Здравствуйте. Прочитал кучу определений но никак не пойму вообще что к чему. 1)Стек - это якобы кусок оперативной памяти который...

Распределение памяти. Динамическое выделение памяти
an-1 an-2 ... a2

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
32
Ответ Создать тему
Новые блоги и статьи
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
Как ИИ начал спорить и врать (возможно почуяв опасность для себя от индустрии - уход от электроники).
Hrethgir 04.08.2026
Недельный диалог, на фоне событий с НПЗ. Да, из спирта можно получать бензин, и это не сложно. Но потом в схеме я решил избавиться от насоса, при этом полностью сделав контроль подачи спирта в. . .
Термопринтер QR701
Argus19 03.08.2026
Термопринтер QR701 Купил два термопринтера QR701. На сэлф-тесте написано: Language: PC936 (GB18030). Что означает, что принтеры могут печатать только латиницу и китайские иероглифы. Так же. . .
Создание формы заимствованного документа
Maks 03.08.2026
Задача: Необходимо создать собственную форму заимствованного документа. На форме должен быть реквизит "Покупатель", а также табличная часть со следующими реквизитами: - Расчетный счет покупателя. . .
Задача предоставления скидок покупателям
Maks 03.08.2026
Задача: В документе "Продажи" необходимо реализовать функционал предоставления скидок покупателям. Скидка должна автоматически рассчитываться и подставляться в соответствующее поле при выборе. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru