Не могу понять, как сложить строки?
std::string to_string( const char* format, ... ) {
va_list args;
va_start( args, format );
const std::size_t len = _vscprintf( format, args ) + 1;
std::string str( len, '\0' );
vsprintf_s( &str[0], len, format, args );
str.resize( len );
return ( str );
}
int main() {
std::string num( "num = " );
for ( size_t i = 0; i < 10; i++ ) {
//num += to_string( "%d", i ).c_str(); так оно работает
num += to_string( "%d", i ); // num = 0 и все
}
printf_s( "%s\n", num.c_str() );
return 0;
}
У вас [почти] все работает прекрасно, но именно так как вы и написали. В конце вашей функции to_string
вы делаете
str.resize( len );
где len
включает и нулевой терминатор тоже. То есть из вашей функции вы возвращаете строки
"0\0"
"1\0"
"2\0"
"3\0"
...
и т.д. А потом вы эти строки конкатенируете в одну и получаете
0 \0 1 \0 2 \0 3 \0 ...
Все работает, как и должно работать. Строки std::string
не являются нуль-терминированными и в их составе символ '\0'
является обыкновенным символом.
Однако при попытке печати такой последовательности через printf
, разумеется, печать идет только до первого '\0'
. Напечатайте ваш результат через
std::cout << num << std::endl;
и вы увидите, что все элементарные строки в составе вашей строки присутствуют. То есть все у вас прекрасно соединяется, только вы зачем-то напихали внутрь вашей строки ненужных нулей.
Память для каждого нуля внутри вашей функции изначально выделять нужно (ибо вы пользуетесь vsprintf_s
), но перед возвращением результирующего значения этот нуль из строки надо убрать, т.е. в вашем случае сделать
str.resize( len - 1 );
Также не забывайте делать va_end
и перезапускать va_list
(даже если майкрософтовские примеры иногда "забывают" это делать).
(Максимально сохраняя ваш подход)
std::string to_string( const char* format, ... ) {
va_list args;
va_start( args, format );
std::size_t len = _vscprintf( format, args );
va_end( args );
std::string str( len + 1, '\0' );
va_start( args, format );
vsprintf_s( &str[0], len + 1, format, args );
va_end( args );
str.resize( len );
return str;
}
Функциональность, которую вы пытаетесь реализовать (раз уж вы хотите сделать это именно так), уже давно можно реализовать стандартными средствами через vsnprintf
, без привлечения нестандартных майкрософтовских средств
std::string to_string( const char* format, ... ) {
va_list args;
va_start( args, format );
std::size_t len = std::vsnprintf( nullptr, 0, format, args );
va_end( args );
std::string str( len + 1, '\0' );
va_start( args, format );
std::vsnprintf( &str[0], len + 1, format, args );
va_end( args );
str.resize( len );
return str;
}
Откровенно говоря - это какое-то извращение, в С++ так работать... Но если очень уж хочется, то я бы делал примерно так:
string to_string( const char* format, ... )
{
va_list args, copy;
va_start(args, format);
va_copy(copy,args);
char * buf = new char[vsnprintf(0,0,format,args)+1];
vsnprintf(buf, len+1, format, copy );
va_end(args);
va_end(copy);
string str(buf);
delete[] buf;
cout << str << endl;
return str;
}
int main()
{
string num( "num = " );
for ( size_t i = 0; i < 10; i++ ) {
num += to_string( "%d", i ); // num = 0 и все
}
cout << num << endl;
}
А вообще - ну лучше уж стандартной to_string
обойтись. Или, для сложного форматирования - stringstream
. А так получается - какое-то натягивание пиджака на осьминога. Уж лучше тогда средствами C изначально пользоваться, не привлекая никакие string
.
Так работает*
template<typename ... Args>
__inline std::string to_string( const char* format, Args ... args ) {
int len = _scprintf( format, args ... );
std::string str( len + 1, '\0' );
sprintf_s( &str[0], len + 1, format, args ... );
str.resize( len );
return ( str );
}
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
В чем суть self в ООП языка Python и this в C++ (лучше в примерах)?
Как написать код, который выдает содержимое указанного каталога подобно команде ls??