Как записать в массив char символ с нулевым завершающим символом?
Какой правильный и самый безопасный способ запоминать весь массив символов с завершающим нулем символом? Я могу перечислить несколько случаев:
...
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?
- Каков наилучший способ обработать этот запрос?
8 ответов
Варианты один и два просто неверны. Первый использует размер указателя вместо размера массива, поэтому он, вероятно, не будет записывать весь массив. Второй использует sizeof(char*)
вместо sizeof(char)
поэтому он будет писать после конца массива. Вариант 3 в порядке. Вы также можете использовать это
memset( buffer, '\0', sizeof(char)*ARRAY_LENGTH );
но sizeof(char)
гарантированно будет 1.
Идиоматическим способом является инициализация значения массива:
char* buffer = new char [ARRAY_LENGTH]();
Вариант 1 устанавливает только первый sizeof(char*)
байтов до 0, или сталкивается с неопределенным поведением, если ARRAY_LENGHT < sizeof(char*)
,
Вариант 2 работает с неопределенным поведением, потому что вы пытаетесь установить больше, чем ARRAY_LENGTH байт. sizeof(char*)
почти наверняка больше 1.
Так как это C++, хотя (нет new
в с), я предлагаю вам использовать std::string
вместо.
Для С (при условии malloc
вместо new[]
), ты можешь использовать
memset( buffer, 0, ARRAY_LENGTH );
Поскольку вопрос постоянно меняется, я определяю:
1: memset( buffer, '\0', sizeof(buffer) );
2а: 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 неверны.
У вас может быть война стиля более 2б против 3: стоит ли включать sizeof(char)
или нет - некоторые люди пропускают это, потому что это избыточно (я обычно делаю), другие люди вставляют это, чтобы создать вид согласованности с тем же кодом, устанавливающим массив int
, То есть они всегда умножают размер на несколько элементов, даже если они знают, что размер равен 1. Один из возможных выводов состоит в том, что "самый безопасный" способ запоминания массива, на который указывает buffer
является:
std::memset(buffer, 0, sizeof(*buffer) * ARRAY_LENGTH);
Этот код остается правильным, если тип буфера изменяется, при условии, конечно, что он продолжает иметь ARRAY_LENGTH
элементы любого типа, и при условии, что все биты-ноль остаются правильными начальными значениями.
Другой вариант, любимый программистами "C++ is C", это:
/* never mind how buffer is allocated */
std::fill(buffer, buffer + ARRAY_LENGTH, 0);
Если вам не все равно, вы можете сами проверить, оптимизирует ли ваш компилятор тот же код, для которого он оптимизирует эквивалентный вызов std::memset
,
char *buffer = new char [ARRAY_LENGTH]();
изящен, но практически бесполезен в C++ на практике, потому что вы почти никогда не выделяете массив new
на первом месте.
std::string buffer(ARRAY_LENGTH, 0);
представляет особый способ управления буфером, который может или не может быть тем, что вы хотите, но часто это. Есть много чего сказать char buffer[ARRAY_LENGTH] = {0};
в некоторых случаях.
- Имеет ли какой-либо из них существенное преимущество перед другими?
- С какими проблемами я могу столкнуться при использовании 1, 2 или 3?
1-е неправильно, потому что sizeof(buffer) == sizeof(char*)
,
2 и 3 в порядке.
- Каков наилучший способ обработать этот запрос?
Почему не просто
buffer[0] = '\0';
Если это char
массив, зачем беспокоиться с остальными персонажами? Когда первый байт установлен в ноль, у вас есть эквивалент ""
в вашем buffer
,
Конечно, если вы действительно настаиваете на том, чтобы все buffer
обнулите, используйте ответ с std::fill
- это правильный путь. Я имею в виду std::fill(buffer, buffer + ARRAY_LENGTH, 0);
,
Если вам абсолютно необходимо использовать необработанный массив в C++ (это очень плохая идея), сделайте это следующим образом:
char* buffer = new char [ARRAY_LENGTH]();
Для C++ memset
обычно является последним прибежищем некомпетентных, хотя за последние несколько месяцев я узнал, что для приемлемой производительности с текущими инструментами необходимо опуститься до этого уровня, когда реализуется собственный строковый класс.
Вместо этих необработанных массивов и т. Д., Которые могут потребоваться memset
используйте например std::string
(для вышеуказанного случая), std::vector
, std::array
и т.п.
Ну лично мне нравится вариант 3:
memset( buffer, '\0', ARRAY_LENGTH )
ARRAY_LENGTH
это именно то, что я хотел бы заполнить в памяти.
Начиная с C++ 11, я бы выбрал:
#include <array>
std::array<char, ARRAY_LENGTH> buffer{ '\0' };
buffer.fill('\0');
Option 3: memset( buffer, '\0', ARRAY_LENGTH ):
даст вам только длину массива, но на самом деле этот параметр является общим, сколько байт памяти.
Option 1: memset( buffer, '\0', sizeof(buffer) ):
даст вам неправильный ответ, потому что, buffer
является char*
, sizeof(buffer)
не даст вам размер всего массива только размер переменной указателя.
Вариант 2 правильный.