С++ Создание массива с переменной в качестве длины генерирует массив случайного размера

Я воссоздаю класс строк, используя массивы символов. Моя проблема в том, что когда я выделяю память для большего массива, он генерирует массив совершенно неправильного размера.

Например:

int allocated = 4;
char * reservedString = new char[allocated];
cout << strlen(reservedString);

Вместо создания массива символов размером 4, зарезервированная строка указывает на массив символов с 14 точками, содержащими случайные символы.

С++ Создание массива с переменной в качестве длины генерирует массив случайного размера

Это то, что показывает мне отладка. Зарезервированная строка теперь имеет неправильный размер с кучей случайных символов. Когда я пытаюсь использовать strcpy или strcpy_s, память записывается за пределы границ, потому что новые размеры массива неверны.

Как я могу создать массив символов неизвестной длины, который предоставляется переменной правильного размера. Я не могу использовать класс std::string или std::vector.

Вы хотите использовать std::vector или std::string.

πάντα ῥεῖ 06.04.2019 22:31

Я бы сделал это, если бы мог, но это для проекта класса, и я не могу использовать векторы или строки, только массивы.

EmptyStuff 06.04.2019 22:32

Читать здесь: cplusplus.com/reference/cstring/strlen. Функция ищет завершающий символ. Ваша строка не инициализирована.

Chiel 06.04.2019 22:34

Вы не инициализируете свой массив, поэтому он содержит случайный мусор. Как отметил Chiel, strlen будет искать нуль-терминатор, он не может знать, сколько байтов вы выделили.

Yksisarvinen 06.04.2019 22:35

Будет ли уместно, чтобы мой код сделал это: зарезервированоString[allocated] = '\0'; так что, когда я создаю массив, его правильный размер?

EmptyStuff 06.04.2019 22:38

Нет, потому что вы пишете один символ после конца выделенной памяти, а также имеете strlen попытку прочитать неинициализированные значения в середине массива, что является поведением undefined (насколько мы знаем, может просто быть нуль персонаж там). Вам нужно правильно инициализировать весь массив. Почему вам все равно нужно находить размер вновь выделенного массива с помощью strlen? Если вы не собираетесь помещать в него строку с нулевым завершением, вам следует следить за ее размером.

eesiraed 06.04.2019 22:39
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
6
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Когда вы создаете объект с помощью нового оператора, ваши данные остаются неинициализированными. Код, который вы предоставляете, в основном представляет собой массив байтов.

В документации о 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 06.04.2019 22:42

@EmptyStuff, вы правы, память была выделена правильно. Теперь вы можете правильно проверять размер каждый раз, когда вы изменяете строку, вам просто нужно отслеживать размер.

mohabouje 06.04.2019 22:44

@EmptyStuff Да. strlen дает длину строки с завершающим нулем, которая может отличаться от размера массива, используемого для хранения строки.

eesiraed 06.04.2019 22:44

@mohabouje Или просто правильно завершите его нулем. Строковые функции должны обрабатывать все остальное, пока массив достаточно велик.

eesiraed 06.04.2019 22:45

@FeiXiang, не могли бы вы уточнить, что вы подразумеваете под правильным завершением нуля.

EmptyStuff 06.04.2019 22:48

@EmptyStuff Убедитесь, что он заканчивается нулевым символом? Сейчас так тяжело. Строковые литералы должны автоматически заканчиваться нулем, и входные функции также завершают строку нулем. Вам следует беспокоиться об этом только тогда, когда вы создаете строку, устанавливая каждый из символов по отдельности, и в этом случае просто установите символ после последнего в значение null и убедитесь, что ваш массив достаточно велик для хранения дополнительного символа.

eesiraed 06.04.2019 22:50

"память была правильно выделена" - очень вероятно, но не подтверждено. Вам нужно проверить результат распределения. Рассмотрите возможность добавления строки «assert ( nullptr != ReservedString );» после нового и перед инициализацией;

2785528 06.04.2019 23:08

strlen ожидает строку с завершающим нулем, что означает строку, заканчивающуюся нулевым символом (\0). Вы передаете ему указатель, указывающий на недавно выделенную память, которая содержит неинициализированные значения (в основном случайные, но технически «промежуточные», и их чтение вызывает неопределенное поведение). Поэтому, когда strlen ищет нулевой символ, чтобы определить длину строки, все пойдет не так.

Вы не можете определить размер массива, имея только указатель на него, если не знаете, что он будет завершен нулевым символом или чем-то подобным. Поэтому либо правильно инициализируйте массив строкой с нулевым завершением, либо следите за длиной самостоятельно.

Другие вопросы по теме