#c #arrays #pointers
#c #массивы #указатели
Вопрос:
Я воссоздаю класс string, используя массивы char. Моя проблема в том, что когда я выделяю память для большего массива, он генерирует массив совершенно неправильного размера.
Например:
int allocated = 4;
char * reservedString = new char[allocated];
cout << strlen(reservedString);
Вместо создания массива символов размером 4, reservedString указывает на массив символов с 14 ячейками, содержащими случайные символы.
Это то, что показывает мне отладка. Зарезервированная строка теперь имеет неправильный размер с кучей случайных символов в ней. Когда я пытаюсь использовать strcpy или strcpy_s, это выводит память за пределы, потому что новые размеры массива неправильные.
Как я могу создать массив символов с неизвестной длиной, которая обеспечивается переменной правильного размера. Я не могу использовать std::string class или std::vector.
Комментарии:
1. Вы хотите использовать
std::vector
илиstd::string
.2. Я бы сделал, если бы мог, но это для проекта класса, и я не могу использовать векторы или строки, только массивы.
3. Читайте здесь: cplusplus.com/reference/cstring/strlen . Функция выполняет поиск символа завершения. Ваша строка неинициализирована.
4. Вы не инициализируете свой массив, поэтому он содержит случайный мусор. Как отметил Chiel,
strlen
будет искать null-terminator, он не может знать, сколько байтов вы выделили.5. Нет, потому что вы записываете один символ после конца выделенной памяти, а также
strlen
пытаетесь прочитать неинициализированные значения в середине массива — это неопределенное поведение (насколько мы знаем, там может просто оказаться нулевой символ). Вам необходимо правильно инициализировать весь ваш массив. Почему вам в любом случае нужно определять размер вновь выделенного массива с помощьюstrlen
? Если вы не собираетесь помещать в него строку, заканчивающуюся нулем, вам следует отслеживать ее размер.
Ответ №1:
Когда вы создаете объект с помощью оператора new, ваши данные остаются неинициализированными. Предоставляемый вами код в основном представляет собой массив байтов.
В документации о strlen
говорится:
вычисляет длину строки str с точностью до, но не включая завершающий нулевой символ.
Здесь нет нулевого ограничителя.
Вы должны сделать:
int allocated = 4;
char * reservedString = new char[allocated]();
Это инициализирует ваш массив и установит все элементы в
Комментарии:
1. Поскольку для каждого элемента установлен завершающий нулевой символ, strlen вернет 0, но я могу отслеживать размер самостоятельно. С точки зрения памяти, даже если strlen возвращает 0, потому что первый символ теперь является нулевым завершающим символом, по-прежнему ли он резервирует 4 байта памяти?
2. @EmptyStuff вы правы, память была выделена правильно. Теперь вы можете проверять размер должным образом каждый раз, когда вы изменяете строку, вам просто нужно отслеживать размер.
3. @EmptyStuff Да.
strlen
выдает длину строки, заканчивающейся нулем, которая может отличаться от размера массива, используемого для хранения строки.4. @mohabouje Или просто правильно завершите его обнулением. Строковые функции должны обрабатывать остальное, пока массив достаточно велик.
5. @FeiXiang не могли бы вы пояснить, что вы подразумеваете под правильным завершением его нулем.
Ответ №2:
strlen
ожидает строку, заканчивающуюся нулем, что означает строку, которая заканчивается нулевым символом (
). Вы передаете ему указатель, указывающий на недавно выделенную память, которая содержит неинициализированные значения, и его чтение вызывает неопределенное поведение. Поэтому, когда strlen
выполняется поиск символа null для определения длины строки, что-то идет не так.
Вы не можете определить размер массива, учитывая только указатель на него, если вы не знаете, что он будет заканчиваться нулевым символом или чем-то подобным. Поэтому либо правильно инициализируйте массив строкой, заканчивающейся нулем, либо следите за длиной самостоятельно.