Как memset char массив с нулевым завершающим символом?

Каков правильный и безопасный способ memset всего массива символов с нулевым завершающим символом? Я могу указать несколько способов использования:

...
char* buffer = new char [ARRAY_LENGTH];

//Option 1:             memset( buffer, '\0', sizeof(buffer) );
//Option 2 before edit: memset( buffer, '\0', sizeof(char*) * ARRAY_LENGTH );
//Option 2 after edit:  memset( buffer, '\0', sizeof(char) * ARRAY_LENGTH );
//Option 3:             memset( buffer, '\0', ARRAY_LENGTH );
...
  • Есть ли у любого из них существенное преимущество перед другими (-ами)?
  • С какими проблемами я могу столкнуться с обычаями 1, 2 или 3?
  • Каков наилучший способ обработки этого запроса?

Ответ 1

Варианты один и два просто неправильны. Первый использует размер указателя вместо размера массива, поэтому он, вероятно, не будет писать весь массив. Второй использует sizeof(char*) вместо sizeof(char), поэтому он будет писать за конец массива. Вариант 3 в порядке. Вы также можете использовать этот

memset( buffer, '\0', sizeof(char)*ARRAY_LENGTH );

но sizeof(char) гарантированно будет 1.

Ответ 2

Идиоматический способ инициализации массива:

char* buffer = new char [ARRAY_LENGTH]();

Вариант 1 устанавливает только первые sizeof(char*) байты в 0 или выполняет undefined поведение, если ARRAY_LENGHT < sizeof(char*).

Вариант 2 работает в undefined, потому что вы пытаетесь установить больше байтов ARRAY_LENGTH. sizeof(char*) почти наверняка больше 1.

Так как это С++ хотя (нет new в C), я предлагаю вместо этого использовать std::string.

Для C (предполагая malloc вместо new[]), вы можете использовать

memset( buffer, 0, ARRAY_LENGTH );

Ответ 3

Поскольку вопрос продолжает меняться, я определяю:

1: memset( buffer, '\0', sizeof(buffer) );

2a: memset( buffer, '\0', sizeof(char*) * ARRAY_LENGTH );

2b: memset( buffer, '\0', sizeof(char) * ARRAY_LENGTH );

3: memset( buffer, '\0', ARRAY_LENGTH );

Если вопрос просто: "Каков правильный способ вызвать memset", а не "что является наилучшим способом обнуления этого массива", то 2b или 3 верны. 1 и 2a являются неправильными.

У вас может быть война за стиль над 2b против 3: включить ли sizeof(char) или нет - некоторые люди ее оставляют, потому что это избыточно (я обычно делаю), другие люди вкладывают его в создание своего рода согласованности с тем же кодом задает массив int. То есть они всегда умножают размер на несколько элементов, даже если они знают, что размер равен 1. Один возможный вывод состоит в том, что "самый безопасный" способ memset массива, на который указывает buffer, это:

std::memset(buffer, 0, sizeof(*buffer) * ARRAY_LENGTH);

Этот код остается верным, если тип буфера изменяется, при условии, что он продолжает иметь ARRAY_LENGTH элементы любого типа, который есть, и при условии, что все бит-ноль остается правильным начальным значением.

Другой вариант, любимый программистами С++ не C,:

/* never mind how buffer is allocated */
std::fill(buffer, buffer + ARRAY_LENGTH, 0);

Если вам небезразлично, вы можете сами убедиться, что ваш компилятор оптимизирует этот код для того же кода, на который он оптимизирует эквивалентный вызов std::memset.

char *buffer = new char [ARRAY_LENGTH](); является изящным, но практически бесполезным в С++ на практике, потому что вы почти никогда не выделяете массив с new в первую очередь.

std::string buffer(ARRAY_LENGTH, 0); вводит конкретный способ управления буфером, который может или не может быть тем, что вы хотите, но часто. В некоторых случаях многое можно сказать о char buffer[ARRAY_LENGTH] = {0};.

Ответ 4

  • Есть ли у любого из них существенное преимущество перед другими (-ами)?
  • С какими проблемами я могу столкнуться с обычаями 1, 2 или 3?

1-ая неверна, потому что sizeof(buffer) == sizeof(char*).

2nd и 3rd в порядке.

  • Каков наилучший способ обработки этого запроса?

Почему не просто:

buffer[0] = '\0';

Если это массив char, зачем беспокоиться с остальными персонажами? Если первый байт установлен на ноль, у вас есть эквивалент "" в buffer.

Конечно, если вы действительно настаиваете на том, чтобы все buffer были обнулены, используйте ответ с std::fill - это правильный способ. Я имею в виду std::fill(buffer, buffer + ARRAY_LENGTH, 0);.

Ответ 5

Если вы абсолютно должны использовать необработанный массив в С++ (это очень непростая идея), сделайте это так:

char* buffer = new char [ARRAY_LENGTH]();

Для С++ memset, как правило, последнее убежище некомпетентного, хотя я узнал за последние несколько месяцев, что для приемлемой производительности, с текущими инструментами, необходимо перейти на тот уровень, когда один реализует один собственный класс строк.

Вместо этих необработанных массивов и т.д., которые могут казаться нуждающимися memset, используйте, например, std::string (для вышеуказанного случая), std::vector, std::array и т.д.

Ответ 6

Option 3: memset( buffer, '\0', ARRAY_LENGTH ): даст вам только длину массива, но на самом деле этот параметр является общим количеством байтов памяти.

Option 1: memset( buffer, '\0', sizeof(buffer) ): даст неверный ответ, потому что buffer - char*. sizeof(buffer) не даст вам размер всего массива только размера переменной указателя.

Вариант 2 прав.