Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как в си объявить массив с возможностью изменения его размера?
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2, 3, 4
011119xx
Необходимо в Кейле объявить массив без указания его размера. А потом по необходимости использования массива задать размер в зависимости от условий. Можно ли это сделать на си и как?
V_G
За Кейл не скажу, а в Винде делал указатель на указатель (**)
ukpyr
без выделения памяти - никак, объявите массив максимальной емкости и переменную с текущим размером.
с выделением памяти через malloc/free - при каждом изменении размера в большую сторону нужно выделять новый массив, копировать содержимое старого и освобождать старый, в меньшую - изменять переменную с текущим размером
XVR
В C99 можно задать размер массива в момент его описания (через переменную). Так же можно выделить массив на стеке, через alloca. Что из этого поддерживает Keil мне неведомо sm.gif
GetSmart
Цитата(011119xx @ Jul 7 2011, 08:36) *
А потом по необходимости использования массива задать размер в зависимости от условий.

Си же вроде не контролирует индексацию внутри массивов. Значит реальный размер массива ему "до лампочки". Лишь бы размер был больше константной индексации.
Поэтому имхо вопрос заключается в создании указателя на пустой массив, потом по ходу проги присваивание указателю адреса (на статик, динамик или прочий буфер) и хранение размера массива во второй целочисленной переменной.
011119xx
Не могли бы привести код в качестве примера?
skripach
Цитата
Как в си объявить массив с возможностью изменения его размера?

Никак. ..остальное изврат.
Использовать динамическое выделение памяти и указатель.
011119xx
Цитата(GetSmart @ Jul 7 2011, 13:00) *
Поэтому имхо вопрос заключается в создании указателя на пустой массив, потом по ходу проги присваивание указателю адреса (на статик, динамик или прочий буфер) и хранение размера массива во второй целочисленной переменной.

В данном случае это должно быть как-то так?
Код
uint16_t Buffer[];
uint16_t *ptr_buffer;
uint16_t index_buffer;
uint16_t value;

void main(void)
{
ptr_buffer = &Buffer;
index_buffer = 32;
value = ptr_buffer + 32;
}

zltigo
QUOTE (011119xx @ Jul 8 2011, 10:27) *
В данном случае это должно быть как-то так?

Абсолютный ужас. Полное непонимание не только языка, но и собственно физического смысла творимого sad.gif
НЕМЕДЛЕННО! Бросить "программировать" и ЧИТАТЬ учебники, иначе дальше без осознания хоть какой-то основы будет только хуже.
GetSmart
Цитата(011119xx @ Jul 7 2011, 08:36) *
Необходимо в Кейле объявить массив без указания его размера. А потом по необходимости использования массива задать размер в зависимости от условий. Можно ли это сделать на си и как?

Приведите пример того, что хотите делать с массивом (использование массива). Для начала для массива константного размера.
Я покажу как это сделать с массивом переменной длины.

Не слушайте zltigo. У него плохое настроение sm.gif
jorikdima
Цитата(zltigo @ Jul 8 2011, 11:53) *
Абсолютный ужас. Полное непонимание не только языка, но и собственно физического смысла творимого sad.gif
НЕМЕДЛЕННО! Бросить "программировать" и ЧИТАТЬ учебники, иначе дальше без осознания хоть какой-то основы будет только хуже.

Поддержу, пожалуй.
XVR
Цитата(zltigo @ Jul 8 2011, 11:53) *
Абсолютный ужас. Полное непонимание не только языка, но и собственно физического смысла творимого sad.gif

bb-offtopic.gif
Публичный дом, молодая проститутка выбегает из номера клиента в растрепанных чувствах и с воплями
- УЖАС, УЖАС, УЖАС!!!!
Мадам успокаивает проститутку и сама идет к клиенту. Через некоторое время выходит, и говорит
- Ну да, ну ужас. Ну уж никак не УЖАС, УЖАС, УЖАС!
011119xx
Не много поправлюсь:
Код
uint16_t Buffer[50];
uint16_t *ptr_buffer;
uint16_t index_buffer;
uint16_t value;

void main(void)
{
ptr_buffer = &Buffer;
index_buffer = 32;
Buffer[index_buffer] = 0х0010;
value = *(ptr_buffer + index_buffer);
}


Это работает. Но это вариант с явным указанием размера буфера при объявлении. Я так понял иначе и нельзя.
GetSmart
Цитата(jorikdima @ Jul 8 2011, 13:01) *
Поддержу, пожалуй.

Если у форума одна из задач - интерактивное обучение, естественно в такой форме чтобы у вопрошающего не отбивалось желание вообще заниматься, то это не лучший подход. Старческое брюзжание. Представьте такого человека в роли препода в любом заведении и учиться сразу расхочется.

Ветка называется "в помощь начинающему". Расслабьтесь, профи sm.gif

Цитата(011119xx @ Jul 8 2011, 13:06) *
Код
...

слегка подправил:
Код
void main(void)
{
ptr_buffer = &Buffer;
index_buffer = 32;
ptr_buffer[index_buffer] = 0х0010;
value = ptr_buffer[index_buffer];
}


Цитата
Это работает. Но это вариант с явным указанием размера буфера при объявлении. Я так понял иначе и нельзя.

Иначе буферов может быть много и разных. Хоть с заданным размером на этапе компиляции, хоть с неявным, выделенным в динамической памяти (куче).
И по ходу проги, одному общему указателю (ptr_buffer) можно присваивать разные адреса (адреса разных буферов). Тогда один общий алгоритм будет фактически "шарить" по разным буферам. Частный случай переменной-указателя - параметр функции.
zltigo
QUOTE (011119xx @ Jul 8 2011, 11:06) *
Не много поправлюсь:

Ничего себе немного - каждой строчке были ошибки, поменяли все строчки, кроме одной:
CODE
ptr_buffer = &Buffer;

В этой, естественно осталась полная лажа, посему вот это:
QUOTE
Это работает.

Неправда.

При всем этом попытались исправить (но не исправили) только формальные ошибки не позволявшие сие даже скомпилировать.
011119xx
Не ожидал господа от вас таких ответов. Извините, если чем то разозлил. Но последний код, который я привел, работает. Можете хоть головой об стенку биться
sergeeff
Может автор ветки откроет великую тайну, зачем ему понадобились массивы переменной длины? Так, для нашего понимания.
zltigo
QUOTE (GetSmart @ Jul 8 2011, 11:14) *
Если у форума одна из задач - интерактивное обучение

Задачи обучения ставят, как в младшей ясельной группе детского сада, так и в Аспирантуре. Весь вопрос в том, как позиционировать этот форум, как ясельную группу, или хотя-бы как начальную школу?
AHTOXA
Цитата(011119xx @ Jul 8 2011, 14:06) *
Это работает. Но это вариант с явным указанием размера буфера при объявлении. Я так понял иначе и нельзя.


Есть ещё вариант. Стандарт C99 поддерживает автоматические переменные-массивы переменной длины:
Код
int mean_of_N_samples(int N)
{
    int arr[N];
    for (int i = 0; i < N; i++)
    {
        arr[i] = get_sample();
    }
    return mean(arr, N);
}

Массив (обычно) создаётся на стеке. То есть, если вам ваш массив переменной длины нужен временно, то это отличный вариант.
011119xx
Например в шрифте символы имеют разную ширину при одинаковой высоте. При перемножении ширины на высоту получаем массив, причем его размер меняется в зависимости от ширины символа.
sergeeff
Цитата(011119xx @ Jul 8 2011, 11:49) *
Например в шрифте символы имеют разную ширину при одинаковой высоте. При перемножении ширины на высоту получаем массив, причем его размер меняется в зависимости от ширины символа.


Вы собираетесь шрифт динамически генерить из, например, true type, или собираетесь использовать готовый? В готовом уже все в массивах лежит.

Пример не катит.
GetSmart
Цитата(011119xx @ Jul 8 2011, 13:49) *
Например в шрифте символы имеют разную ширину при одинаковой высоте. При перемножении ширины на высоту получаем массив, причем его размер меняется в зависимости от ширины символа.

Для работы понадобится указатель на один элемент массива (первый) и один или несколько переменных-описалово данных внутри массива.
С указателем, как я уже подкорректировал внутри CODE можно работать как с массивом.
zltigo
QUOTE (011119xx @ Jul 8 2011, 11:29) *
Можете хоть головой об стенку биться

Биться головой о стенку, причем дооолго и безрезультатно предстоит Вам, ибо при таком подходе к делу (думать не будем, учиться понимать язык не будем, будем сразу "программировать") это неизбежно sad.gif.
Утверждать, Вы можете, что угодно, но приведенная мною Ваша строчка
CODE
uint16_t Buffer[50];
uint16_t *ptr_buffer;
.....
ptr_buffer = &Buffer;

не имеет право даже быть откомпилированной.
Ибо бред. И тут уж либо так
ptr_buffer = &Buffer[0];
либо так:
ptr_buffer = Buffer;
sergeeff
Цитата(GetSmart @ Jul 8 2011, 11:55) *
Для работы понадобится указатель на один элемент массива (первый) и один или несколько переменных-описалово данных внутри массива.
С указателем, как я уже подкорректировал внутри CODE можно работать как с массивом.


Вы, надеюсь, понимаете, что ваш подход, кроме изврата, ничего не содержит? Если в вашей функции виден сам массив, на кой лишний указатель и ненужная переменная, в качестве индекса?
011119xx
Это
Код
ptr_buffer = &Buffer;

как раз и заносит в указатель адрес нулевого элемента массива.
Код
ptr_buffer = &Buffer;

и
Код
ptr_buffer = &Buffer[0];

одно и тоже biggrin.gif
GetSmart
Цитата(zltigo @ Jul 8 2011, 13:55) *
...
Ибо бред.

А почему сразу бред? А проверить?

А почему не УЖАС, УЖАС, УЖАС!!! ??? sm.gif
zltigo
QUOTE (011119xx @ Jul 8 2011, 12:00) *
Это
CODE
ptr_buffer = &Buffer;

как раз и заносит в указатель адрес нулевого элемента массива.
CODE
ptr_buffer = &Buffer;

Разумеется нет. "это" бессмысленное выражение которое любой вменяемый компилятор обязан послать нафиг.

011119xx
Цитата(sergeeff @ Jul 8 2011, 15:00) *
Вы, надеюсь, понимаете, что ваш подход, кроме изврата, ничего не содержит? Если в вашей функции виден сам массив, на кой лишний указатель и ненужная переменная, в качестве индекса?

Дело в том что когда я читаю ширину и высоту символа мне нужно создать массив размером = ширина*высота и в этот массив скопировать некую картинку такого размера. Это скажем так: фон для символа. Потом в этот массив копируется сам символ, но при этом затирает только очертания символа. Потом из этого массива данные выводятся в дисплей

Цитата(zltigo @ Jul 8 2011, 15:08) *
Разумеется нет. "это" бессмысленное выражение которое любой вменяемый компилятор обязан послать нафиг.

Да ну вас! Ни один компилятор никогда не посылал.
sergeeff
Цитата(011119xx @ Jul 8 2011, 12:00) *
Это
Код
ptr_buffer = &Buffer;

как раз и заносит в указатель адрес нулевого элемента массива.
Код
ptr_buffer = &Buffer;

и
Код
ptr_buffer = &Buffer[0];

одно и тоже biggrin.gif


Хоть меня частенько критикуют за любовь к печатным изданиям, но вам, любезный, книги надобно почитать.
Если объявлен массив abc[10], то

abc - это указатель на массив и его значение в точности равно адресу первого элемента, т.е. &abc[0]. А &abc - дает адрес указателя на массив, что, согласитесь, совсем не то, что вы хотите получить и использовать.

на что вам и указал уважаемый zltigo.
AHTOXA
Цитата(011119xx @ Jul 8 2011, 15:08) *
Дело в том что когда я читаю ширину и высоту символа мне нужно создать массив размером = ширина*высота и в этот массив скопировать некую картинку такого размера.
...
Потом из этого массива данные выводятся в дисплей


Вы случайно в пылу полемики не пропустили мой пост (№19)? sm.gif По идее как раз подходит.
zltigo
QUOTE (GetSmart @ Jul 8 2011, 12:05) *
А почему сразу бред? А проверить?

Что проверить? Что указатель на int не является кирпичом?
QUOTE
А почему не УЖАС, УЖАС, УЖАС!!! ??? sm.gif

Потому,что я это уже сказал ранее.
GetSmart
Цитата(011119xx @ Jul 8 2011, 14:09) *
Дело в том что когда я читаю ширину и высоту символа мне нужно создать массив размером = ширина*высота и в этот массив скопировать некую картинку такого размера. Это скажем так: фон для символа. Потом в этот массив копируется сам символ, но при этом затирает только очертания символа. Потом из этого массива данные выводятся в дисплей

Так создайте сразу статичный массив с размером под максимально большой символ, который потребуется. При работе с малыми символами конец массива использоваться не будет. Велика беда. Иначе можно выделять место в стеке, как предлагал AHTOXA.

Цитата(zltigo @ Jul 8 2011, 14:11) *
Потому,что я это уже сказал ранее.

Так это были Вы? sm.gif
sergeeff
Цитата(GetSmart @ Jul 8 2011, 12:13) *
Так создайте сразу статичный массив с размером под максимально большой символ, который потребуется. При работе с малыми символами конец массива использоваться не будет. Велика беда. Иначе можно выделять место в стеке, как предлагал AHTOXA.


Да уж, прав наш гуру zltigo, надо бы все-таки, научиться голову включать. На кой нужен этот вспомогательный массив автору топика? Маску наложить на байт из массива? Ту и кто мешает это делать при побайтном копировании тела буквы на дисплей?
011119xx
Цитата(AHTOXA @ Jul 8 2011, 15:11) *
Вы случайно в пылу полемики не пропустили мой пост (№19)? sm.gif По идее как раз подходит.

Не пропустил. Спасибо. Хороший вариант. Буду пробовать
GetSmart
Цитата(sergeeff @ Jul 8 2011, 14:11) *
А &abc - дает адрес указателя на массив, что, согласитесь, совсем не то, что вы хотите получить и использовать.

на что вам и указал уважаемый zltigo.

Право, какая глупость. Это что за адрес несуществующего "указателя" на массив?
011119xx
Цитата(GetSmart @ Jul 8 2011, 15:18) *
Так создайте сразу статичный массив с размером под максимально большой символ, который потребуется. При работе с малыми символами конец массива использоваться не будет. Велика беда.

Сейчас так и делаю... А если у меня не один шрифт? Выделять буфер размером с самый большой символ самого крупного шрифта? Это весьма расточительно будет. Представьте символ высотой 40 и шириной 35. На каждый цвет приходится 16 бит. Получаем буфер 2800 байт. Причем большой шрифт будет использоваться очень редко, а память будет потрачена.
sergeeff
Цитата(GetSmart @ Jul 8 2011, 13:30) *
Право, какая глупость. Это что за адрес несуществующего "указателя" на массив?


Что вы подразумеваете под несуществующим указателем на массив?
GetSmart
Цитата(011119xx @ Jul 8 2011, 14:35) *
Причем большой шрифт будет использоваться очень редко, а память будет потрачена.

В стеке нужно будет иметь гарантированно нужный объём памяти при самом наихудшем случае. А вдруг не хватит? В статике же один раз выделил и не напрягаешься. По этому поводу есть рассуждения в умных книжках.
011119xx
Цитата(AHTOXA @ Jul 8 2011, 14:45) *
Есть ещё вариант. Стандарт C99 поддерживает автоматические переменные-массивы переменной длины:
Код
int mean_of_N_samples(int N)
{
    int arr[N];
    for (int i = 0; i < N; i++)
    {
        arr[i] = get_sample();
    }
    return mean(arr, N);
}

Массив (обычно) создаётся на стеке. То есть, если вам ваш массив переменной длины нужен временно, то это отличный вариант.

В данном случае массив объявляется внутри функции. Мне нужно чтобы массив был глобальным, он потом используется в другой функции.
GetSmart
Цитата(sergeeff @ Jul 8 2011, 14:37) *
Что вы подразумеваете под несуществующим указателем на массив?

Код
u16 abc[10];
void *p;

main()
{
p = &abc;
...
}

Чему равен p?
Цитата
А &abc - дает адрес указателя на массив

Что такое адрес указателя на массив?
vvs157
Цитата(ukpyr @ Jul 7 2011, 08:44) *
без выделения памяти - никак, объявите массив максимальной емкости и переменную с текущим размером.
с выделением памяти через malloc/free - при каждом изменении размера в большую сторону нужно выделять новый массив, копировать содержимое старого и освобождать старый, в меньшую - изменять переменную с текущим размером
А чем realloc не устраивает?
sergeeff
Цитата(GetSmart @ Jul 8 2011, 13:42) *
В стеке нужно будет иметь гарантированно нужный объём памяти при самом наихудшем случае. А вдруг не хватит? В статике же один раз выделил и не напрягаешься. По этому поводу есть рассуждения в умных книжках.


Мы давайте "заср...м" глобальным массивом дефицитную память процессора, а пользоваться им будем где-то в процедуре. А кто мешает в этой самой функции объявлять такой же массив (если стека хватает)? Хотя я писал уже, что в данной задаче и массив то этот не нужен вовсе.

А по поводу &abc можете почитать у отцов основателей http://www.realcoding.net/article/view/1094

Цитата
Что такое адрес указателя на массив?


Указатель лежит в памяти. Адрес указателя - это адрес этой памяти.
GetSmart
Цитата(sergeeff @ Jul 8 2011, 14:49) *
А по поводу &abc можете почитать у отцов основателей http://www.realcoding.net/article/view/1094

Не читал, но осуждаю sm.gif
Но на элементарный вопрос не ответить - надо уметь.

Цитата(sergeeff @ Jul 8 2011, 14:49) *
Хотя я писал уже, что в данной задаче и массив то этот не нужен вовсе.

В названии топика есть вопрос. На него и отвечаем. Остальное вторично. Тем более, кто сказал, что память дефицитная. Если подобный массив в стеке будет только в одном месте выделяться, то статичный вариант лучше во всех отношениях. Точнее, если такая квазидинамическая память больше в программе не используется.
vvs157
Цитата(GetSmart @ Jul 8 2011, 13:45) *
Чему равен p?
Вообще-то в случае обявленного массива array[n] указатель &array, скорее всего будет равен указателю array. Скорее всего - потому что зависит от реализации компилятора. Но пользоваться этим очень плохо, так как в случае динамичесого массива, созданного через calloc/malloc это точно будет не так.
skripach
Цитата
А по поводу &abc можете почитать у отцов основателей http://www.realcoding.net/article/view/1094

От туда:
Цитата
Операция & применима только к переменным и элементам массива,

abc есть константа. Не? 05.gif
UPD:
Т.е. запись &abc просто нелогична, ну как получить адрес адреса.
GetSmart
Цитата(vvs157 @ Jul 8 2011, 15:02) *
.. в случае динамичесого массива, созданного через calloc/malloc это точно будет не так.

Потому как это совершенно разные вещи. Динамического массива в виде идентификатора не существует, существует указатель на него или просто пустой указатель. А это уже совсем другая история. Адрес функции, кстати, тоже можно брать через амперсанд, и у неё к сожалению или счастью нет индекса.

Цитата(skripach @ Jul 8 2011, 15:08) *
UPD:
Т.е. запись &abc просто нелогична, ну как получить адрес адреса.

Однако, компиляторописатели (хвала аллаху, что zltigo не из них) думают, что логична. Т.к. результат - всегда адрес. И глаз программера этот амперсанд так же примечает.
vvs157
Цитата(GetSmart @ Jul 8 2011, 14:15) *
Потому как это совершенно разные вещи.
Но вот именно поэтому в C++ фокус с ссылкой на адрес статического элемента уже не прокатит
zltigo
QUOTE (GetSmart @ Jul 8 2011, 12:45) *
void *p;
}

Замените КАК ЭТО СДЕЛАНО В ПЕРВОИСТОЧНИКЕ:

u16 *p

И компилятор ответит, что он думает "Чему равен p"
vvs157
Цитата(GetSmart @ Jul 8 2011, 14:15) *
Однако, компиляторописатели (хвала аллаху, что zltigo не из них) думают, что логична.
Это очень стремная радость. В один прекрасный момент решат, что это не "по фен-шую" и количество головной боли у тех, кто пользуется подобными недокументированными фичами будет весьма велико.
GetSmart
Цитата(zltigo @ Jul 8 2011, 15:23) *
Замените КАК ЭТО СДЕЛАНО В ПЕРВОИСТОЧНИКЕ:

u16 *p

И компилятор ответит, что он думает "Чему равен p"

Адресу массива, не сомневайтесь.
Но согласитесь, на УЖАС, УЖАС, УЖАС это не тянет. Так, мелкое хулиганство sm.gif
Причём меньшее, чем не посылка NAK в протоколе I2C.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.