Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Заполнить выделенную динамическую память нулями


Автор: Alca 21.8.2008, 15:57
Заполнить выделенную динамическую память нулями ('\0')?
например буфер можно обнулить так:
Код

BYTE buf[2048];
memset(buf, '\0', 2048);

Можно ли делать так?
Код

char *pszText  = new char[2048];
memset(pszText, '\0', 2048);
//...
delete [] pszText;

Заполниться ли выделенная память нулями?

Автор: cutwater 21.8.2008, 16:01
Естественно можно

Автор: UnrealMan 21.8.2008, 17:26
Цитата(Alca @  21.8.2008,  16:57 Найти цитируемый пост)
например буфер можно обнулить так

А можно и так:

Код

BYTE buf[2048] = {};


В случае с new стандарт позволяет записывать так:

Код

int *p = new int[10]();

Но не все современные компиляторы соблюдают стандарт в этом плане (например, MinGW 3.4.5 тупо не инициализирует массив).

Автор: Alek86 21.8.2008, 17:41
кстати, вопрос немного филогсофский

обычно не рекомендуют смешивать сишный стиль и плюсовой
кто из программистов тогда использует вместо memset std::uninitialized_fill?

Автор: UnrealMan 21.8.2008, 18:03
Цитата(Alek86 @  21.8.2008,  18:41 Найти цитируемый пост)
обычно не рекомендуют смешивать сишный стиль и плюсовой
кто из программистов тогда использует вместо memset std::uninitialized_fill? 

std::uninitialized_fill, применяемый к уже существующим объектам, - это типа C++-стиль? smile

Автор: Alek86 21.8.2008, 18:07
лучше чем memset

Автор: UnrealMan 21.8.2008, 18:13
Цитата(Alek86 @  21.8.2008,  19:07 Найти цитируемый пост)
лучше чем memset 

О-о-о, да, мы избавились от необходимости умножения на sizeof(тип элемента массива). Аллилуйя! Мегадостижение. А что мсье будет делать, если тип элементов массива сменится с POD на не POD?

Автор: andrew_121 21.8.2008, 18:32
Цитата(UnrealMan @  21.8.2008,  17:26 Найти цитируемый пост)
Но не все современные компиляторы соблюдают стандарт в этом плане (например, MinGW 3.4.5 тупо не инициализирует массив).

Просто немного не так:
Код

BYTE buf[2048] = "\0";


Автор: UnrealMan 21.8.2008, 18:44
Цитата(andrew_121 @  21.8.2008,  19:32 Найти цитируемый пост)
Просто немного не так:

Я про второй свой пример говорил (с new который). Первый, к счастью, работает и в MinGW.

Добавлено через 12 минут и 43 секунды
Цитата(andrew_121 @  21.8.2008,  19:32 Найти цитируемый пост)
BYTE buf[2048] = "\0";

Кстати, по стандарту, в отличие от

Код

BYTE buf[2048] = {};

код

Код

BYTE buf[2048] = "\0";

гарантированно инициализирует лишь первые два элемента символьного массива.

Автор: vinter 21.8.2008, 19:13
Цитата(UnrealMan @  21.8.2008,  19:13 Найти цитируемый пост)
 А что мсье будет делать, если тип элементов массива сменится с POD на не POD?

ну тогда исчезнет необходимость в обнулении, спор то как раз о POD типах

Автор: Alca 21.8.2008, 19:16
Код

char *pszText  = new char[2048];
memset(pszText, '\0', 2048);
char cTemp = 'w';
cTemp = pszText[0];    //<-- здесь 0
cTemp = pszText[1];    //<-- здесь 0
cTemp = pszText[2];    //<-- здесь 0
cTemp = pszText[3];    //<-- здесь 0
cTemp = pszText[2047];    //<-- здесь ещё 0
cTemp = pszText[2048];    //<-- здесь мусор
cTemp = pszText[2049];    //<-- здесь мусор
cTemp = pszText[2050];    //<-- здесь мусор
//...
delete [] pszText;

Автор: UnrealMan 21.8.2008, 19:34
Цитата(vinter @  21.8.2008,  20:13 Найти цитируемый пост)
ну тогда исчезнет необходимость в обнулении

... и ради достижения корректности программы возникнет необходимость в устранении существующего обнуления, причём компилятор на эту необходимость не укажет. Коли уж наша программа разваливается, стоит нам на шаг отойти от POD-типов, о каком C++-стиле может идти речь?

Цитата(vinter @  21.8.2008,  20:13 Найти цитируемый пост)
спор то как раз о POD типах 

Я тут никакого спора не вижу. Если некое средство считается более крутым лишь потому, что оно из STL, а не из стандартной библиотеки C, то это не что иное, как детский сад. Над псевдоинтеллектуальными рассуждениями я обычно просто стебусь, а не спорю с ними.

Автор: bsa 21.8.2008, 20:53
Цитата(Alca @ 21.8.2008,  19:16)
Код

char *pszText  = new char[2048];
memset(pszText, '\0', 2048);
char cTemp = 'w';
cTemp = pszText[0];    //<-- здесь 0
cTemp = pszText[1];    //<-- здесь 0
cTemp = pszText[2];    //<-- здесь 0
cTemp = pszText[3];    //<-- здесь 0
cTemp = pszText[2047];    //<-- здесь ещё 0
cTemp = pszText[2048];    //<-- здесь мусор
cTemp = pszText[2049];    //<-- здесь мусор
cTemp = pszText[2050];    //<-- здесь мусор
//...
delete [] pszText;

Этот код может вызвать ошибку Access Violation или Segmentation fault, в зависимости от ОС.
Это типичная ошибка новичка - выход за границы массива.

Автор: Alek86 21.8.2008, 21:25
немного оффтоп

если не заметил, у меня стоял знак вопроса
а это значит, что я задавал вопрос и ожидал ответа а не ржачки
(кстати нормального ответа, почему все так любят memset и ни разу не используют std::uninitialized_fill)

Цитата(UnrealMan @  21.8.2008,  19:34 Найти цитируемый пост)
 Над псевдоинтеллектуальными рассуждениями я обычно просто стебусь, а не спорю с ними.

а поскольку ты над всеми стебешься, кто с тобой не согласен, то... smile

и по теме

Цитата(UnrealMan @  21.8.2008,  18:13 Найти цитируемый пост)
А что мсье будет делать, если тип элементов массива сменится с POD на не POD?

насколько я вижу в примерной реализации std::uninitialized_fill там вообще не идет речи ни о ПОД ни о каком-то конкретном куске памяти. есть только 2 итератора и значения. что ты имел в виду, когда писал о ПОД? (только, пожалуйста, если можно, ответь серьезно, без клоунады)

Автор: andrew_121 21.8.2008, 21:36
Цитата(Alek86 @  21.8.2008,  21:25 Найти цитируемый пост)
только, пожалуйста, если можно, ответь серьезно, без клоунады

Респект и уважуха smile 

Автор: bsa 21.8.2008, 21:43
Подозреваю, что об uninitialized_fill мало кто знает, поэтому и не используют. Все-таки это низкоуровневая функция. С другой стороны, она может быть удобна в случае "нестандартного" для С++ выделения памяти (malloc) - не нужно городить огород с размещающими new. Но я бы остерегся от использования этих нестандартных методов без крайней необходимости.

Автор: cutwater 21.8.2008, 21:53
По поводу uninitialized_fill, могу высказать свое имхо
memset работать должен все таки быстрее

Автор: Alek86 21.8.2008, 22:08
Цитата(cutwater @  21.8.2008,  21:53 Найти цитируемый пост)
memset работать должен все таки быстрее

думаю, так и есть - в дебаге
в релизе с оптимизацией с указателями должно быть то же самое
хотя - кто знает (пробовать лень smile )

Автор: UnrealMan 21.8.2008, 22:33
Создание массива из n объектов определённого типа и выделение n байт сырой памяти - это разные задачи, и у каждой будет своё наиболее подходящее (хотя бы с точки зрения самодокументируемости кода) решение. В первом случае подходящим решением будет использвание new-expression, std::vector или иного контейнера, если первые два не подходят. Во втором случае подходящим решением будет явный вызов operator new. В первом случае при использовании new-expression для заполнения массива n элементами подходящим средством будет std::fill_n. Во втором случае для размещения n объектов в сырой памяти подходящим средством будет std::uninitialized_fill_n. При следовании такому принципу (каждой задаче - соответствующий метод решения) по коду по крайней мере будет видно, какая задача решается.

Автор: MTWizard 21.8.2008, 23:36
unitialized_fill - более общее решение, т.к. работает и для подов, и для не-подов.

Тем более, для типа signed/unsigned char unitialized_fill (по крайней мере в STLPort) превращается в memset
Значит, эффективность она тоже обеспечивает.

Автор: UnrealMan 22.8.2008, 00:25
Цитата(Alek86 @  21.8.2008,  22:25 Найти цитируемый пост)
насколько я вижу в примерной реализации std::uninitialized_fill там вообще не идет речи ни о ПОД ни о каком-то конкретном куске памяти. есть только 2 итератора и значения. что ты имел в виду, когда писал о ПОД?

Изначальный пример выглядел так:

Код

char *pszText  = new char[2048];
memset(pszText, '\0', 2048);

Если заменить здесь memset на std::uninitialized_fill, а после char заменить на не POD класс, то получишь двойное конструирование объекта в одной и той же области памяти. Затея смешивания относительно высокоуровневого new-expression с низкоуровневым конструированием объекта поверх памяти в качестве замены "смешиванию плюсового и сишного стиля" достойна похвал.

Автор: Alek86 22.8.2008, 11:20
Цитата(UnrealMan @  22.8.2008,  00:25 Найти цитируемый пост)
Изначальный пример выглядел так

тогда моя ошибка
я говорил не об этом примере, а вообще
стоило создать новую тему...


в общем, насколько я понял, в тех случаях когда надо, программисты используют memset вместо std::uninitialized_fill в основном потому, что о таком не знают.

Цитата(UnrealMan @  22.8.2008,  00:25 Найти цитируемый пост)
Если заменить здесь memset на std::uninitialized_fill, а после char заменить на не POD класс, то получишь двойное конструирование объекта в одной и той же области памяти.

а в случае, если не менять memset на std::uninitialized_fill, а сразу менять чар на не ПОД класс?
вроде тогда вообще ж... будет

Автор: cutwater 22.8.2008, 11:29
Обычно таких проблем не возникает. Они решаются на стадии проектирования, и там где нужен char - он нужен. Если в последствии приходится менять тип и замена memset на uninitialized_fill окажется трудоемкой, то проект хренов по определению.

Добавлено через 21 секунду
Все вышесказанное опять же мое ИМХО

Автор: Alca 22.8.2008, 11:58
А если структура объявленатак:
Код

typedef struct {
    //объявление членов;
} *Pимя_структуры;    //<-- указатель

Как ее обнулить?

Автор: W4FhLF 22.8.2008, 12:18
Alca, смотря как ты её создаёшь. Выше было приведено как минимум два характерных способа. Попробуй. 

Автор: Alek86 22.8.2008, 12:42
Alca, старайся не смешивать С и С++
что значит "обнулить" структуру?
привести к дефолтному состоянию?

тогда тебе поможет доюбавление в структуру функции Reinit(), которая будет вызываться также и в конструкторе.

и структура потихоньку начнет превращаться в класс smile

Автор: Alca 22.8.2008, 12:59
Обнулить (сорри за такие термины) - значит инициализировать выделяемую память '\0'.
Создаю так:
Код

PHOSTENT  pHost;  // pHost - указатель

Надо через memset.

Автор: bsa 22.8.2008, 13:12
PHOSTENT - Это что? макрос? Что он определяет? Это указатель или структура? POD или не POD? Язык программирования Си или С++?

Автор: Alca 22.8.2008, 13:23
Плюсы.
Код

//winsock2.h
struct  hostent {
        char    FAR * h_name;           /* official name of host */
        char    FAR * FAR * h_aliases;  /* alias list */
        short   h_addrtype;             /* host address type */
        short   h_length;               /* length of address */
        char    FAR * FAR * h_addr_list; /* list of addresses */
#define h_addr  h_addr_list[0]          /* address, for backward compat */
};
typedef struct hostent *PHOSTENT;

Автор: mrbrooks 22.8.2008, 14:30
Я вообще предпочтаю обнулять все через макрос ZeroMemory(); в винде.

Автор: Alca 22.8.2008, 14:51
И как через ZeroMemory()?

Автор: UnrealMan 22.8.2008, 14:58
Обнулить поля POD-структуры можно не прибегая к библиотечным функциям:

Код

PodStruct object = {}; // на этапе инициализации
...
object = PodStruct(); // с помощью присваивания

Автор: mrbrooks 22.8.2008, 15:03
Alca, 
к примеру 
Код

#include <windows.h>
char *buf = new char[1028];
ZeroMemory(buf, 1028);
delete [] buf;


Добавлено через 1 минуту и 36 секунд
так же можно обнулить любую структуру

Автор: Alca 22.8.2008, 15:06
Надо заполнить структуру:
Код

//winsock2.h
struct  hostent {
        char    FAR * h_name;           /* official name of host */
        char    FAR * FAR * h_aliases;  /* alias list */
        short   h_addrtype;             /* host address type */
        short   h_length;               /* length of address */
        char    FAR * FAR * h_addr_list; /* list of addresses */
#define h_addr  h_addr_list[0]          /* address, for backward compat */
};
typedef struct hostent *PHOSTENT;

//инициализация
PHOSTENT  pHost;  // pHost - указатель

Автор: mrbrooks 22.8.2008, 15:16
Код

ZeroMemory(pHost, sizeof(hostent));

Автор: Alca 22.8.2008, 15:22
Код

sizeof(pHost);    //получаем размер указателя а не структуры

Автор: mrbrooks 22.8.2008, 15:23
Alca, согласен но где это ты у меня видел?  smile

Добавлено через 1 минуту и 48 секунд
есесно что указатель вернет 4 байта. 

Автор: UnrealMan 22.8.2008, 15:25
Цитата(mrbrooks @  22.8.2008,  16:03 Найти цитируемый пост)
так же можно обнулить любую структуру 

Никогда не понимал тех, кто так делает в плюсовых проектах.

Цитата(mrbrooks @  22.8.2008,  16:16 Найти цитируемый пост)
Код
ZeroMemory(pHost, sizeof(hostent));

Код
*pHost = hostent();

Какой вариант короче?

Автор: Alca 22.8.2008, 15:26
Не досмотрел, сорри... А можно получить размер структуры через указатель?

Автор: mrbrooks 22.8.2008, 15:26
но я то беру размер основной струтуры.

Добавлено через 1 минуту и 27 секунд
Цитата(Alca @ 22.8.2008,  15:26)
НА можно получить размер структуры через укащатель?

наврятли, но 100% утверждать не буду

Добавлено через 2 минуты и 43 секунды
UnrealMan, в  smile твой вариант короче, но для меня мой более наглядней для меня же  smile 

Автор: UnrealMan 22.8.2008, 15:30
Цитата(Alca @  22.8.2008,  16:26 Найти цитируемый пост)
А можно получить размер структуры через укащатель? 

Код

sizeof(boost::remove_pointer<твой_указательный_тип>::type)

Автор: mrbrooks 22.8.2008, 15:34
UnrealMan,  имхо но для этого нужно прикрутить boost! А это целая эпопея. По крайней мере у \me так было.

Автор: Alca 22.8.2008, 15:35
Код

PHOSTENT pHost;
ZeroMemory(pHost, sizeof(hostent));

Код

warning C4700: uninitialized local variable 'pHost' used

Boost, конечно вещь классная, но тягать её за собой чёта нехо....

Автор: Partizan 22.8.2008, 15:38
Alca, вы объявили указатель, а память не выделили...

Автор: bsa 22.8.2008, 15:40
можно и проще:
Код
struct MyStruct
{
     ....
};

MyStruct *p;

size_t size = sizeof(*p);
Но надо иметь в виду, что если структура определена так:
Код
struct SomeDynamicSizeStruct
{
...
     DWORD data[0];
};
А затем под нее выделена память так:
Код
SomeDynamicSizeStruct *p = malloc(sizeof(SomeDynamicSizeStruct) + sizeof(DWORD)*10);
То sizeof (*p) возвратит то же, что и sizeof(SomeDynamicSizeStruct)

Автор: UnrealMan 22.8.2008, 15:41
Цитата(mrbrooks @  22.8.2008,  16:34 Найти цитируемый пост)
имхо но для этого нужно прикрутить boost!

Существует не так уж много объективных причин, чтобы его не прикручивать.
Добавлено @ 15:46
Цитата(bsa @  22.8.2008,  16:40 Найти цитируемый пост)
можно и проще:

Можно.

Код

sizeof(*PointerType())

Автор: mrbrooks 22.8.2008, 15:47
UnrealMan, имхо ты прав. я и спорить не буду. boost это та вещь которую стоит осваивать. smile 

Автор: Alca 22.8.2008, 15:48
Я память динамически кажись не выделяю...
Цитата

Alca, вы объявили указатель, а память не выделили...

Я не объявлял указатель, тока дефайнил.

Автор: mrbrooks 22.8.2008, 15:52
Alca, любопытно если переменну pHost объявить глобально - варнинг проподает.

Добавлено @ 15:54
либо как 
Код

static PHOSTENT pHost;

 smile 

Автор: Alca 22.8.2008, 15:56
Код

sizeof(pHost);  //возвращает 4 байта
sizeof(hostent);  //возвращает 16 байт
sizeof(*pHost);  //возвращает 16 байт

Код

static PHOSTENT pHost;

Ворнинг улетел!  smile 

Автор: mrbrooks 22.8.2008, 16:01
кстати если не ошибаюсь глобальные и статические переменные по умолчанию инициализируются нулем.

Автор: bsa 22.8.2008, 16:02
Цитата(mrbrooks @ 22.8.2008,  16:01)
кстати если не ошибаюсь глобальные и статические переменные по умолчанию инициализируются нулем.

так оно и есть

Автор: Partizan 22.8.2008, 16:05
Цитата(Alca @ 22.8.2008,  15:48)
Цитата

Alca, вы объявили указатель, а память не выделили...

Я не объявлял указатель, тока дефайнил.

 smile 

Код

PHOSTENT pHost;
ZeroMemory(pHost, sizeof(hostent));



PHOSTENT pHost; - это чтоли дефайн?

Автор: Alca 22.8.2008, 16:06
Ворнинг улетел!  А прога слетела!!!
У меня 2 потока юзают эту функцию...
Дефайнил так:
Код

typedef struct hostent *PHOSTENT;

Автор: Lazin 22.8.2008, 16:15
Цитата(Alca @  22.8.2008,  16:06 Найти цитируемый пост)
У меня 2 потока юзают эту функцию

пардон за офтопик, ИМХО рано тебе еще потоки использовать smile 

Автор: Alca 22.8.2008, 16:17
Код

рано тебе еще потоки использовать

Надо использовать! Заодно и научюсь.

Автор: bsa 22.8.2008, 17:55
Код
PHOSTENT pHost;
...
ZeroMemory(pHost, sizeof(hostent));
Данный код содержит ошибку, даже если pHost - глобальная переменная. прежде чем работать со стуктурой, на которую указывает указатель, нужно выделить под нее память.

Автор: Lazin 22.8.2008, 19:29
Цитата(bsa @  22.8.2008,  17:55 Найти цитируемый пост)
Данный код содержит ошибку, даже если pHost - глобальная переменная. прежде чем работать со стуктурой, на которую указывает указатель, нужно выделить под нее память.

и не забыть освободить ее когда нужно smile

Добавлено через 22 секунды
хотя глобальную иногда можно не освобождать...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)