Я пытаюсь запустить простую программу на C++, которая в основном подсчитывает количество символов, используя функцию length()
из библиотеки <string>
C++.
Вот моя пользовательская функция:
#include <iostream>
#include <string>
using namespace std;
string TrimTextFunction() {
string Text = "Hello I am your program!";
cout << "String size is: " << Text.length();
return 0;
}
Затем я просто запускаю эту пользовательскую функцию внутри main()
через отладчик в Visual Studio:
int main()
{
cout << TrimTextFunction();
}
В конце концов я получаю этот код ошибки:
Исключение, возникающее по адресу 0x00007FFE67837A41 (ucrtbased.dll)
Затем он перенаправляет меня во внутренний файл под названием xstring
, показывающий саму ошибку.
Без отладчика код возвращает нужное мне значение.
Но когда я запускаю тот же код внутри main()
с помощью того же отладчика (или без него), ошибок не возникает.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string Text = "Hello I am your program!";
cout << "String size is: " << Text.length();
}
Кажется, мне что-то не хватает в пользовательских функциях, особенно когда я что-то отлаживаю.
Почему функция main()
позволяет мне получить нужный мне результат без ошибок, а пользовательская функция — нет?
Я использовал пользовательскую функцию, и мне нужно ожидать результата string
, который возвращает длину переменной string
, равную 24.
Я отредактировал заголовок «постфактум». В нем содержится подсказка об ответе. Я надеюсь, что это никого не смущает.
На этапе отладки вы упустили одну вещь: после краткого изучения переменных в xstring вокруг места сбоя вы переключили «Кадр стека» на ваш код, чтобы увидеть, где что-то пошло не так. В этом небольшом примере это не особо помогло бы, но в более крупной нетривиальной программе это может очень помочь.
Ваша функция определяется как
string TrimTextFunction() {
string Text = "Hello I am your program!";
cout << "String size is: " << Text.length();
return 0;
}
В этом случае использование 0
для создания std::string
вызывает конструктор
std::string(const char* s, const Allocator& alloc = Allocator())
Создает строку с содержимым, инициализированным копией символьной строки с нулевым завершением, на которую указывает s. Длина строки определяется первым нулевым символом. Поведение не определено, если [s, s + Traits::length(s)) не является допустимым диапазоном (например, если s — нулевой указатель). Этот конструктор не используется для вывода аргументов шаблона класса, если выводимый тип распределителя не соответствует требованиям распределителя.
Обратите внимание, что начиная с C++23 этот конструктор объявлен удаленным, поэтому он даже не компилируется.
std::string(std::nullptr_t) = delete;
Если вы просто хотите, чтобы ваша вспомогательная функция выводила данные на стандартный вывод, ей не нужно ничего возвращать, поэтому тип возвращаемого значения будет void
, и вы можете опустить оператор return
.
void TrimTextFunction() {
string Text = "Hello I am your program!";
cout << "String size is: " << Text.length();
}
int main() {
TrimTextFunction();
}
Давайте упростим пример. Версия со всем кодом в основном
#include <iostream>
int main() {
std::cout << 42;
}
Вы хотите поместить 42
внутри функции. Функция должна вернуть это значение. Это было бы:
#include <iostream>
int foo() { return 42; }
int main() {
std::cout << foo();
}
Но вместо этого вы сделали что-то вроде этого:
#include <iostream>
int foo() {
std::cout << 42;
return 0;
}
int main() {
std::cout << foo();
}
Вам необходимо решить: является ли функция выводом значения на экран. Или функция возвращает значение, чтобы main
мог его распечатать. Вы также можете сделать и то, и другое: функцию распечатать и позволить main
распечатать. Однако ваш код находится где-то посередине.
Здесь
string TrimTextFunction() { string Text = "Hello I am your program!"; cout << "String size is: " << Text.length(); return 0; } int main() { cout << TrimTextFunction(); }
Вы позволяете TimeTextFunction
распечатать результат и вернуть какой-то несвязанный 0. К сожалению, std::string
имеет конструктор, который можно вызвать с литералом 0
, но при этом он вызывает неопределенное поведение, поскольку ожидает указатель на строку, завершающуюся нулем, а 0
преобразуется в nullptr
.
main
с другой стороны, похоже, что функция возвращает restul для печати, она использует возвращенный результат для его печати.
Решение, как упоминалось выше, состоит в том, чтобы не путать печать на экране с возвратом из функции. Решите, должна ли функция или main
или оба печатать его, и когда вы объявляете функцию возвращающей std::string
, убедитесь, что она возвращает правильный std::string
(я полагаю, вы действительно хотите вернуть size_t
, длину строки).
Понял, большое спасибо. В общем, я пытался поймать рыбу там, где я ожидал по количеству рыб (скажем, к концу рыбалки мне нужно было 24 рыбы) — это моя функция. Но вместо того, чтобы вытаскивать рыбу из воды с помощью удочки, я просто смотрел на закат в надежде получить нужный мне результат (а это 24 рыбины), но единственное, что у меня получилось - это загар на коже. И это было неожиданно :)
вы путаете вывод чего-либо на экран с возвратом чего-либо из функции. Это совершенно отдельные понятия.