Я воссоздаю класс строк, используя массивы символов. Моя проблема в том, что когда я выделяю память для большего массива, он генерирует массив совершенно неправильного размера.
Например:
int allocated = 4;
char * reservedString = new char[allocated];
cout << strlen(reservedString);
Вместо создания массива символов размером 4, зарезервированная строка указывает на массив символов с 14 точками, содержащими случайные символы.
Это то, что показывает мне отладка. Зарезервированная строка теперь имеет неправильный размер с кучей случайных символов. Когда я пытаюсь использовать strcpy или strcpy_s, память записывается за пределы границ, потому что новые размеры массива неверны.
Как я могу создать массив символов неизвестной длины, который предоставляется переменной правильного размера. Я не могу использовать класс std::string или std::vector.
Я бы сделал это, если бы мог, но это для проекта класса, и я не могу использовать векторы или строки, только массивы.
Читать здесь: cplusplus.com/reference/cstring/strlen. Функция ищет завершающий символ. Ваша строка не инициализирована.
Вы не инициализируете свой массив, поэтому он содержит случайный мусор. Как отметил Chiel, strlen
будет искать нуль-терминатор, он не может знать, сколько байтов вы выделили.
Будет ли уместно, чтобы мой код сделал это: зарезервированоString[allocated] = '\0'; так что, когда я создаю массив, его правильный размер?
Нет, потому что вы пишете один символ после конца выделенной памяти, а также имеете strlen
попытку прочитать неинициализированные значения в середине массива, что является поведением undefined (насколько мы знаем, может просто быть нуль персонаж там). Вам нужно правильно инициализировать весь массив. Почему вам все равно нужно находить размер вновь выделенного массива с помощью strlen
? Если вы не собираетесь помещать в него строку с нулевым завершением, вам следует следить за ее размером.
Когда вы создаете объект с помощью нового оператора, ваши данные остаются неинициализированными. Код, который вы предоставляете, в основном представляет собой массив байтов.
В документации о strlen
говорится:
computes the length of the string str up to, but not including the terminating null character.
Здесь нет нулевого терминатора.
Ты должен сделать:
int allocated = 4;
char * reservedString = new char[allocated]();
Это инициализирует ваш массив и установит для всех элементов значение \0
Поскольку для каждого элемента задан завершающий нулевой символ, strlen вернет 0, но я могу сам отслеживать размер. С точки зрения памяти, несмотря на то, что strlen возвращает 0, потому что первый символ теперь является нулевым завершающим символом, резервирует ли он по-прежнему 4 байта памяти?
@EmptyStuff, вы правы, память была выделена правильно. Теперь вы можете правильно проверять размер каждый раз, когда вы изменяете строку, вам просто нужно отслеживать размер.
@EmptyStuff Да. strlen
дает длину строки с завершающим нулем, которая может отличаться от размера массива, используемого для хранения строки.
@mohabouje Или просто правильно завершите его нулем. Строковые функции должны обрабатывать все остальное, пока массив достаточно велик.
@FeiXiang, не могли бы вы уточнить, что вы подразумеваете под правильным завершением нуля.
@EmptyStuff Убедитесь, что он заканчивается нулевым символом? Сейчас так тяжело. Строковые литералы должны автоматически заканчиваться нулем, и входные функции также завершают строку нулем. Вам следует беспокоиться об этом только тогда, когда вы создаете строку, устанавливая каждый из символов по отдельности, и в этом случае просто установите символ после последнего в значение null и убедитесь, что ваш массив достаточно велик для хранения дополнительного символа.
"память была правильно выделена" - очень вероятно, но не подтверждено. Вам нужно проверить результат распределения. Рассмотрите возможность добавления строки «assert ( nullptr != ReservedString );» после нового и перед инициализацией;
strlen
ожидает строку с завершающим нулем, что означает строку, заканчивающуюся нулевым символом (\0
). Вы передаете ему указатель, указывающий на недавно выделенную память, которая содержит неинициализированные значения (в основном случайные, но технически «промежуточные», и их чтение вызывает неопределенное поведение). Поэтому, когда strlen
ищет нулевой символ, чтобы определить длину строки, все пойдет не так.
Вы не можете определить размер массива, имея только указатель на него, если не знаете, что он будет завершен нулевым символом или чем-то подобным. Поэтому либо правильно инициализируйте массив строкой с нулевым завершением, либо следите за длиной самостоятельно.
Вы хотите использовать
std::vector
илиstd::string
.