Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Динамический массив структур
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
YChebisheva
К примеру у меня есть структура и я хочу работать с динамическим массивом, правильно ли будет:
Код
typedef struct {
            DWORD               Debug;
            char               *Oerr;
            char                Oerr_num;
            WORD                Data_FC;
                char                Nfunc;
          } SProba;
...
int num = 3;
SProba *dat = (SProba*) malloc(sizeof(SProba) * num);
SProba *elem = &dat[1];
elem->Oerr = (char*) malloc(10);
....
for(i = 0; i < num; i++)
   free(dat[i]->Oerr;
free(dat);
Oldring
Цитата(YChebisheva @ May 5 2009, 13:25) *
free(dat[i]->Oerr;


Нет.
YChebisheva
Oldring, описалась. Понятно, что скобку не закрыла.
А по существу, всё таки не ясно.
Забыла сказать, пишу в Cross Studio 1.7.13 для LPC2214
Палыч
Цитата(YChebisheva @ May 5 2009, 14:15) *
А по существу, всё таки не ясно.
Так, по существу - и неправильно! Что выделялось по malloc, то и должно быть освобождено c помощью free...

P.S. В Вашем примере кода Вы выделяете два участка памяти, а освобождаете - четыре...
Злодей
Простите, а разве нельзя? Типа было под него выделено ни сколько памяти, и освободиться ни сколько....
Если это неправильно, то уже есть в структуре размер массива Oerr: Oerr_num. Освобождая проверять его...

Код
for(i = 0; i < num; i++)
{
     if ( dat[i]->Oerr_num > 0 )
     {
          free(dat[i]->Oerr);
     }
}
free(dat);


Но это непринципиально, интересно, почему нельзя освобождать память если её не выделяли.
Палыч
Цитата(Злодей @ May 5 2009, 15:05) *
интересно, почему нельзя освобождать память если её не выделяли.
Наверное, потому, что при выделении памяти её (память) никто не обнуляет, и там - некий мусор, который может быть воспринят как "правильные" данные, и таки память будет "освобождена" (о чем менеджер кучи будет уведомен; к этой памяти "пришиты" указатели на другие участки кучи, которые (указатели) будут изменены; при этом, по-видимуму, испортятся некие нужные Вам данные (уж куча разрушится точно!) и т.д.)...

P.S. Прочитал что написал - сумбурно получилось... Другими словами: при освобождении памяти с помощью free менеджер кучи не имеет возможности проверить - точно ли выделялся этот участок памяти или программист ошибся; и, скорее всего, его "освободит" с непредсказуемыми последствиями.
Сергей Борщ
Цитата(Злодей @ May 5 2009, 15:05) *
Простите, а разве нельзя? Типа было под него выделено ни сколько памяти, и освободиться ни сколько....
Нельзя. Вам не было "выделено нисколько памяти" - вам память не выделялась вообще. В free() нужно передавать указатель на то же место, который вернул вам malloc(). Дело в том, что перед выделенным вам участком менеджер памяти хранит служебную информацию об этом участке. Когда вы вызываете free(), менеджер использует эту информацию для возврашения освобожденной памяти в кучу и объединения ее с другими свободными участками. Если вы вызовете free() с каким-то другим адресом - совершенно случайная информация перед этим указателем разрушит данные менеджера кучи. Единственное исключение - допускается вызов free с указателем равным 0, в таком случае он просто ничего не делает. У вас в примере память выделяется только для одного элемента из трех. Поэтому вы должны либо выделить память и для остальных, либо обнулить остальные указатели.
_Pasha
Цитата(YChebisheva @ May 5 2009, 12:25) *
К примеру у меня есть структура и я хочу работать с динамическим массивом, правильно ли будет:

правильно так:


Код
int num = 3;
SProba *dat = (SProba*) calloc(num,sizeof(SProba));
for(i = 0; i < num; i++)
   free(dat[i]->Oerr;
free(dat);


но только в случае, если NULL == 0
Палыч
Цитата(_Pasha @ May 5 2009, 16:22) *
но только в случае, если NULL == 0
Разве malloc/calloc обнуляет выделенный участок памяти?
YChebisheva
Ребята это я виновата, Вас всех запутала.
Понятно, что в примере выделено меньше, чем освобождается, и надо делать проверку на нул.
Меня интересесовал другой вопрос.
Создание массива должно проходить так:
Код
int num = 3;
SProba *dat = (SProba*) malloc(sizeof(SProba) * num);

Обращение к элементу можно или так делать:
Код
SProba *elem = &dat[1];
elem->Debug  = 123;
//или так:
dat[1].Debug = 123;

А освобождение:
Код
free(dat)

А по части Oerr я просто хотела спросить, что разницы не будет, что я динамически выделяю память на структуру, в которой есть указатель на другую переменную, под которую я также выделю память.
И соотвественно, если я в SProba, к примеру у dat[0], выделила память под Oerr, я ее должна в конце и освободить free(dat[0]->Oerr), а потом уже освободить free(dat). Ну а где не юзаю Oerr, просто у остальных элементов Oerr = NULL...
Палыч
Цитата(YChebisheva @ May 5 2009, 17:02) *
Меня интересесовал другой вопрос.
Всё - верно. Для массива "красивее" использовать calloc. И маленькая ошибка в коде, нужно free(dat[i].Oerr), а не free(dat[i]->Oerr)

P.S. Повторюсь: В выделенной памяти - мусор. Не забудьте очистить (проинициализировать) Ваш массив - занести нули или "пустые"("безопасные") значения.
_Pasha
Цитата(Палыч @ May 5 2009, 16:31) *
Разве malloc/calloc обнуляет выделенный участок памяти?
calloc обязан обнулить
YChebisheva
Как понимаю особой разницы malloc и calloc нет, просто во втором случае весь массив обнуляется, плюс в первом случае указываешь общий объем: размер элемента * кол.элемента, а в calloc - просто раздельно это сделано.
А удаление одинаково - через free(dat)?
_Pasha
Цитата(YChebisheva @ May 6 2009, 09:31) *

Совершенно ага.
YChebisheva
у меня ещё вопрос возник по части объема, которая занимает структура.
Есть, к примеру, структура:
Код
typedef struct {              
                long   *Debug;
                char    Nfunc;
               } SGfuncBAK;

Показывает, что 8 байт, 4 понятно на указатель, а куда ещё 4, а не 1? или там выравнивание?
Палыч
Цитата(YChebisheva @ May 6 2009, 11:28) *
или там выравнивание?
Выравнивание. Обычно его можно уменьшить с потерей скорости доступа, но не на всех платформах.
Злодей
Здесь сказано:
Цитата
Размер структуры выравнивается до размера, кратному размеру его максимального элемента.
_Pasha
Если мы(Вы) имеем дело с С99 и gnu99, можно смело отменять выравнивание и пользоваться типами uint_fast**_t . Имхо, вручную проконтролировать оптимальное выравнивание гораздо лучше, чем потом носиться с прагмами и ком.строкой от компилера к компилеру.


Тогда

Цитата(Палыч @ May 6 2009, 12:07) *
Выравнивание. Обычно его можно уменьшить с потерей скорости доступа, но не на всех платформах.


приобретет другой смысл, а именно: выравнивание на разных платформах будет разным, без потери скорости доступа.

Разумеется, для ввода/вывода за пределы системы, надо придерживаться детерминированных размеров, т.е. применять типы uint_**_t
YChebisheva
А как определить, какой у меня компилятор, если пишу в Cross Works для мк LPC2214?
И типов, начинающихся на uint_fast не нашла sad.gif
zltigo
Цитата(_Pasha @ May 6 2009, 13:25) *
Если мы(Вы) имеем дело с С99 и gnu99, можно смело отменять выравнивание и пользоваться типами uint_fast**_t . Имхо, вручную проконтролировать оптимальное выравнивание гораздо лучше, чем потом носиться с прагмами и ком.строкой от компилера к компилеру.

В огороде бузина, ну а дядька соответственно в Киеве. Паковка/не паковка структур не зависит от использования в структурах свежих С99 типов входящих в нее переменных. Любую мысль следует выражать максимально прямо, даже если для этого pragma требуется sad.gif. fast, least зачастую очень странно интерпретируются компиляторами - получал в практически одинаковых условиях и 8 и 32bit переменные sad.gif. На данный момент предпочитаю создавать свои собственные типы и явно переопределять их в зависимости от платформы.
YChebisheva
с типами разобралась.
А может лучше объявить всю структуру как packed?
zltigo
Цитата(YChebisheva @ May 6 2009, 14:56) *
А как определить, какой у меня компилятор, если пишу в Cross Works для мк LPC2214?

Это сложно, поскольку это еще зависит от географических координат Вашего местоположения, возраста,.... А если серьезно, то посмотрите САМИ какой конкретно из GNU компиляторов запускаете из, полагаю, Rowley-евской оболочки.
YChebisheva
.

А как определить, какой у меня компилятор, если пишу в Cross Works для мк LPC2214?
_Pasha
Цитата(zltigo @ May 6 2009, 13:54) *
fast, least зачастую очень странно интерпретируются компиляторами - получал в практически одинаковых условиях и 8 и 32bit переменные sad.gif .
С точки зрения гнуся несложно представить себе ситуацию, когда в stdint.h какого-нить ГЦЦ для АРМа появится к примеру такое:
Код
typedef int __attribute__((special_treatment_for_8bit)) int_fast8_t;

где special_treatment_for_8bit - гипотетический атрибут, позволяющий опробовать новую стратегию оптимизатора. Не вижу ничего плохого. 
Цитата(YChebisheva @ May 6 2009, 15:33) *
А как определить, какой у меня компилятор, если пишу в Cross Works для мк LPC2214?

запустите компилятор с ключем --verbose 
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.