При текущем стандарте (здесь стандарт отличается), нет никакой гарантии, что буфер внутренней памяти, управляемый std::string
, будет непрерывным или что метод .c_str()
возвращает указатель на внутреннее представление данных (Реализация может генерировать непрерывный блок только для чтения для этой операции и возвращать в нее указатель. Указатель на фактические внутренние данные можно получить с помощью метода .data()
member, но обратите внимание, что он также возвращает постоянный указатель:оно не предназначено для изменения содержимого. Буфер, возвращаемый .data()
, не обязательно завершается нулем, реализация должна гарантировать нулевое завершение только при вызове c_str()
, так что даже в реализациях, где .data()
иПри вызове .c_str()
реализация может добавить \0
в конец буфера, когда вызывается последний.
Стандарт, предназначенный для реализации веревок, поэтому в принципе небезопасно делать то, что выпытаемся и из роВ соответствии со стандартом вы должны использовать промежуточное значение std::vector
(гарантированное смежность, и есть гарантия, что &myvector[0]
является указателем на первый выделенный блок реального буфера).
Во всех реализацияхЯ знаю, что внутренняя память, обработанная std::string
, на самом деле является непрерывным буфером, и использование .data()
- это неопределенное поведение (запись в постоянную переменную), но даже если оно некорректно, оно может работать (я бы этого избегал).Вам следует использовать другие библиотеки, разработанные для этой цели, например boost::format
.
Об окончании NULL.Если вы наконец решите пойти по пути неопределенного ... вам нужно будет выделить дополнительное пространство для нулевого терминатора, так как библиотека запишет его в буфер.Теперь проблема в том, что в отличие от строк в стиле C, std::string
s может содержать нулевые указатели внутри, поэтому вам придется изменить размер строки так, чтобы она соответствовала наибольшему непрерывному блоку памяти с самого начала, который не содержит \0
.Вероятно, это проблема, которую вы обнаруживаете с ложными нулевыми символами.Это означает, что за неправильным подходом использования vsnprintf
(или семейства) должен следовать str.resize( strlen( str.c_str() ) )
, чтобы отбросить все содержимое строки после первого \0
.
В целом, я бы посоветовал противэтот подход, и настаивайте на том, чтобы либо привыкнуть к способу форматирования C ++, используя сторонние библиотеки (boost - сторонняя, но также является самой стандартной нестандартной библиотекой), используя векторы или управляя памятью, как в C ...но этого последнего варианта следует избегать, как чумы.
// A safe way in C++ of using vsnprintf:
std::vector<char> tmp( 1000 ); // expected maximum size
vsnprintf( &tmp[0], tmp.size(), "Hi %s", name.c_str() ); // assuming name to be a string
std::string salute( &tmp[0] );