Как 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 прав.