Правильно ли используется выделение памяти и пользование
От: vis1979  
Дата: 18.11.06 08:57
Оценка:
Уважаемые мастера! просветите пожалуйста все ли правильно я делаю, и если нет укажите наошибки:

Есть Функция
void * TimerAdd(набор параметров)
{
struct TimerStruct * tempTimerEl = (struct TimerStruct *) malloc (sizeof(struct TimerStruct));
...
тело функции
...
return tempTimerEl;
}

далее определяется массив (подразумевается массив указателей на void)
void ** TimerKLZ;

выделяется память под массив указателей на void
if (CountKLZ > 0)
if ((TimerKLZ= (void **) malloc(sizeof(void *)*CountKLZ))==NULL)
{
free(Data);
return 0;
}

и далее собственно вызов и присвоение
for (i=0; i<CountKLZ; i++)
{
TimerKLZ[i]=TimerAdd(параметры);
}
Re: Правильно ли используется выделение памяти и пользование
От: Андрей Тарасевич Беларусь  
Дата: 18.11.06 09:09
Оценка:
Здравствуйте, vis1979, Вы писали:

V>Уважаемые мастера! просветите пожалуйста все ли правильно я делаю, и если нет укажите наошибки:


Ну раз уж ты сам просишь: "на ошибки" пишется раздельно

V>Есть Функция

V>void * TimerAdd(набор параметров)
V>{ 
V> struct TimerStruct * tempTimerEl = (struct TimerStruct *) malloc (sizeof(struct TimerStruct));
V> ...
V> тело функции
V> ...
V> return tempTimerEl;
V>}


Это, похоже, именно С... Если это именно C, то

...
  struct TimerStruct* tempTimerEl = malloc(sizeof *tempTimerEl);
...


Т.е. во-первых, никакого приведения типа не надо, и, во-вторых, 'sizeof' лучше натравить на указатель-получатель, а не на тип.

Не понятно почему тип возврата — 'void*', а не 'struct TimerStruct*'.

V>далее определяется массив (подразумевается массив указателей на void)

V> void ** TimerKLZ;

V>выделяется память под массив указателей на void

V>if (CountKLZ > 0)
V> if ((TimerKLZ= (void **) malloc(sizeof(void *)*CountKLZ))==NULL)
V> {
V>  free(Data);
V>  return 0;
V> }


Опять же

...
  if ((TimerKLZ = malloc(CountKLZ * sizeof *TimerKLZ)) == NULL)
...


V>и далее собственно вызов и присвоение

V> for (i=0; i<CountKLZ; i++)
V> {
V> TimerKLZ[i]=TimerAdd(параметры);
V> }

По-прежнему не понятно, почему массив именно 'void*'-ов...
Best regards,
Андрей Тарасевич
Re[2]: Правильно ли используется выделение памяти и пользова
От: vis1979  
Дата: 18.11.06 10:00
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Это, похоже, именно С...


Да, это С, компиляция производиться на Borland C++ 3.1

АТ>Если это именно C, то

АТ>
АТ>...
АТ>  struct TimerStruct* tempTimerEl = malloc(sizeof *tempTimerEl);
АТ>...
АТ>

АТ>Т.е. во-первых, никакого приведения типа не надо, и, во-вторых, 'sizeof' лучше натравить на указатель-получатель, а не на тип.

Понятно, спасибо, это я учту, но вот что сказано в helpe на malloc
     char *str;

     /* allocate memory for string */
     if ((str = (char *) malloc(10)) == NULL)
     {
        printf("Not enough memory to allocate buffer\n");
        exit(1);  /* terminate program if out of memory */
     }

то есть приведение типа явно указано, как я понимаю ошибки в моем описании нет,
и вы представили лишь улучшение или я не до конца что то понимаю?

АТ>Не понятно почему тип возврата — 'void*', а не 'struct TimerStruct*'.

Да собственно и не знаю почему просто tempTimerEl это элемент списка, для которого
выделяется память и заполняются поля, далее возращается в качестве результата функции

чтобы потом по идентификатору tempTimerEl его можно было найти в списке и удалить
вот такой функцией unsigned char DeleteTimer(void * ID_Timer) опять же с типом void *

то есть по сути TimerKLZ[i] используется в следующем виде DeleteTimer(TimerKLZ[i]);

на самом деле в качестве void* подразумевался просто возвращаемый адрес элемента
в принципе все работает и вроде стабильно, но посто закрались смутные сомнения
правильно ли я выделяю память для списка указателей на void в таком виде:

void ** TimerKLZ;
 
 if ((TimerKLZ= (void **) malloc(sizeof(void *)*CountKLZ))==NULL)
 {
  return 0;
 }


для использования в виде
 TimerKLZ[i]=TimerAdd(параметры);


АТ>По-прежнему не понятно, почему массив именно 'void*'-ов...

вопрос а как мне объявить массив указателей на TimerStruct?
таким же образом? "struct TimerStruct ** TimerKLZ;" — ???
и потом выделение
 if ((TimerKLZ= (struct TimerStruct **) malloc(sizeof(struct TimerStruct *)*CountKLZ))==NULL)
 {
  return 0;
 }

Так???
Re[2]: Правильно ли используется выделение памяти и пользова
От: Roman Odaisky Украина  
Дата: 18.11.06 11:22
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>никакого приведения типа не надо


...но лучше его всё же писать. Для forward compatibility
До последнего не верил в пирамиду Лебедева.
Re: Правильно ли используется выделение памяти и пользование
От: vis1979  
Дата: 19.11.06 07:58
Оценка:
Неужели никто не может ответить на элементарный вопрос?
помогите пожалуйста!

Определение типа void ** TimerKLZ;
подразумевает массив указателей на void?

Правильно ли дальнейшее выделение памяти для него:

выделяется память под массив указателей на void
TimerKLZ= (void **) malloc(sizeof(void *)*CountKLZ)

и работа с ним:

TimerKLZ[i]= (значение типа void*)
Re[3]: Правильно ли используется выделение памяти и пользова
От: Андрей Тарасевич Беларусь  
Дата: 19.11.06 08:15
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

АТ>>никакого приведения типа не надо


RO>...но лучше его всё же писать. Для forward compatibility


Как раз таки наоборот. Лучше его не писать, ибо явное приведение типа в такой ситуации может привести к маскированию грубой ошибки. А именно, если автор кода забудет включить заголовочный файл с корректным объявлением 'malloc', то компилятор С выполнит неявное объявление 'malloc' с подразумеваемым типом возврата 'int'. Без приведения типа попытка присваивания этого 'int' указателю сразу приведет к ошибке компиляции, а с приведением типа код будет принят и ошибка окажется замаскированной. На платформе с одинаковым размером указателя и 'int' это еще может худо-бедно "работать", но в общем случае — беда.

Поэтому существует достаточно известный совет — никогда не приводите тип возврата 'malloc'.
Best regards,
Андрей Тарасевич
Re[3]: Правильно ли используется выделение памяти и пользова
От: Андрей Тарасевич Беларусь  
Дата: 19.11.06 08:31
Оценка:
Здравствуйте, vis1979, Вы писали:

АТ>>Это, похоже, именно С...


V>Да, это С, компиляция производиться на Borland C++ 3.1


АТ>>Если это именно C, то

АТ>>
АТ>>...
АТ>>  struct TimerStruct* tempTimerEl = malloc(sizeof *tempTimerEl);
АТ>>...
АТ>>

АТ>>Т.е. во-первых, никакого приведения типа не надо, и, во-вторых, 'sizeof' лучше натравить на указатель-получатель, а не на тип.

V>Понятно, спасибо, это я учту, но вот что сказано в helpe на malloc

V>
V>     char *str;

V>     /* allocate memory for string */
V>     if ((str = (char *) malloc(10)) == NULL)
V>     {
V>        printf("Not enough memory to allocate buffer\n");
V>        exit(1);  /* terminate program if out of memory */
V>     }
V>


В стародавние времена в языке С не было указателей на 'void' и функция 'malloc' возвращала 'char*'. По этой причине в те времена было принято всегда применять приведение типа к результату 'malloc' (даже если нужен был именно 'char*'). Вот этот пример их help-а как раз и демонстирурует эту давно устаревшую манеру. Старинный пример забыли подправить. Или было просто лень.

Сейчас наоборот выполнять такое приведение типа весьма и весьма не рекомендуется. По причинам, описанным в моем соседнем сообщении.

V>то есть приведение типа явно указано, как я понимаю ошибки в моем описании нет,

V>и вы представили лишь улучшение или я не до конца что то понимаю?

Ошибки нет, есть избыточность. И потенциальная опасность.

АТ>>Не понятно почему тип возврата — 'void*', а не 'struct TimerStruct*'.

V> Да собственно и не знаю почему просто tempTimerEl это элемент списка, для которого
V>выделяется память и заполняются поля, далее возращается в качестве результата функции
V>чтобы потом по идентификатору tempTimerEl его можно было найти в списке и удалить
V>вот такой функцией unsigned char DeleteTimer(void * ID_Timer) опять же с типом void *

По прежнему не понятно, почему не сделана типизация...

V>то есть по сути TimerKLZ[i] используется в следующем виде DeleteTimer(TimerKLZ[i]);

V>на самом деле в качестве void* подразумевался просто возвращаемый адрес элемента
V>в принципе все работает и вроде стабильно, но посто закрались смутные сомнения
V>правильно ли я выделяю память для списка указателей на void в таком виде:

V>
V>void ** TimerKLZ;
 
V> if ((TimerKLZ= (void **) malloc(sizeof(void *)*CountKLZ))==NULL)
V> {
V>  return 0;
V> }
V>


Формально правильно, но опять же — в такой записи содержатся ненужные инварианты и избыточные приведения. Если завтра ты решишь перейти с типа 'void*' на какой-нибудь другой, тебе придется сделать исправления в трех местах: объявление 'TimerKLZ', приведение типа и "параметр" 'sizeof'. В моем варианте исправление пришлось бы делать только в первом месте а строчку с 'malloc' вообще исправлять бы не надо было.

АТ>>По-прежнему не понятно, почему массив именно 'void*'-ов...

V>вопрос а как мне объявить массив указателей на TimerStruct?
V>таким же образом? "struct TimerStruct ** TimerKLZ;" — ???

Да.

V>и потом выделение

V>
V> if ((TimerKLZ= (struct TimerStruct **) malloc(sizeof(struct TimerStruct *)*CountKLZ))==NULL)
V> {
V>  return 0;
V> }

V>


...
if ((TimerKLZ = malloc(CountKLZ * sizeof *TimerKLZ)) == NULL)
...
Best regards,
Андрей Тарасевич
Re[4]: Правильно ли используется выделение памяти и пользова
От: vis1979  
Дата: 19.11.06 09:01
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>>>никакого приведения типа не надо


RO>>...но лучше его всё же писать. Для forward compatibility


АТ>Как раз таки наоборот. Лучше его не писать, ибо явное приведение типа в такой ситуации может привести к маскированию грубой ошибки. А именно, если автор кода забудет включить заголовочный файл с корректным объявлением 'malloc', то компилятор С выполнит неявное объявление 'malloc' с подразумеваемым типом возврата 'int'. Без приведения типа попытка присваивания этого 'int' указателю сразу приведет к ошибке компиляции, а с приведением типа код будет принят и ошибка окажется замаскированной. На платформе с одинаковым размером указателя и 'int' это еще может худо-бедно "работать", но в общем случае — беда.


АТ>Поэтому существует достаточно известный совет — никогда не приводите тип возврата 'malloc'.


Большое спасибо за то что просветили, но
вопрос такой, а я вроде и не включаю никакой заголовочный файл с коректным описанием,
я думал что по умолчанию malloc возвращает указатель на воид так и в хелпе объявлено, или это не так?
при этом без приведения типа также компилируется
Re[5]: Правильно ли используется выделение памяти и пользова
От: Андрей Тарасевич Беларусь  
Дата: 19.11.06 09:30
Оценка:
Здравствуйте, vis1979, Вы писали:

V>вопрос такой, а я вроде и не включаю никакой заголовочный файл с коректным описанием,

V>я думал что по умолчанию malloc возвращает указатель на воид так и в хелпе объявлено, или это не так?
V>при этом без приведения типа также компилируется

Хм... Компилятор-то не знает, что там в хелпе объявлено. Более того, компилятор сам по себе ни о каком 'malloc' и слыхом не слыхивал. Чтобы он узнал о существовании 'malloc' надо в транслируемые фалы включать стандартный заголовочный файл 'stdlib.h'.

Вполне возможно, что в твоем случае этот файл как-то неявно включился, через посредство других заголовочных файлов. Поэтому без приведения типа и компилируется. Тем не менее рекомендуется включить его явно.
Best regards,
Андрей Тарасевич
Re[6]: Правильно ли используется выделение памяти и пользова
От: vis1979  
Дата: 19.11.06 09:45
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Хм... Компилятор-то не знает, что там в хелпе объявлено. Более того, компилятор сам по себе ни о каком 'malloc' и слыхом не слыхивал. Чтобы он узнал о существовании 'malloc' надо в транслируемые фалы включать стандартный заголовочный файл 'stdlib.h'.


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


Действительно, в каждый модуль проекта добавлен некий файл.h в котором порписан #include <stdlib.h>
достаточно ли такого описания либо нужно указать его явно в модуле, не будет ли в таком случае
перекресного вызова заголовочных файлов?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.