C++ toString() с помощью sprintf()
В C++ я пытаюсь реализовать функцию toString() для моего класса:
void ClassName::toString(string& returnString)
{
sprintf(returnString.c_str(), "Position: (%f, %f, %f)\n", position.x, position.y, position.y);
}
Однако я продолжаю получать эту ошибку: аргумент типа const char* несовместим с параметром типа char *
Как мне исправить это и сделать аргумент больше не постоянным?
5 ответов
Как это исправить?
Используйте другой подход, используйте stringstream
вместо или вспомогательный буфер.
void ClassName::toString(string& returnString)
{
std::stringstream ss;
ss << "Position: (" << position.x << ", " << position.y << ", "
<< position.z << ")\n");
returnString = ss.str();
}
и сделать аргумент больше не постоянным?
Не. Ад перестанет проигрывать, если ты изменишься c_str
к неконстантному типу. Товарищи программисты будут плакать. Ангелы потеряют свои крылья. Котята умрут. Цены на нефть будут расти. Обвал фондового рынка. Зомби-апокалипсис.
Это const
по причине - чтобы вы не изменили его. Это может привести к неопределенному поведению.
Сделайте буфер для sprintf. Затем присвойте returnString назад.
void ClassName::toString(string& returnString)
{
char buffer[64] = {}; // expect the length of `Position Info` will not exceed 63
sprintf(buffer, "Position: (%f, %f, %f)\n", position.x, position.y, position.y);
returnString = buffer;
}
c_str()
возвращает const char *
потому что, как правило, не стоит менять значение строки, используя указатель, возвращаемый c_str()
функция.
Кстати, то, что вы пытаетесь сделать, бессмысленно. Вы должны просто использовать returnString.append()
метод.
Но если вы должны сделать это с помощью sprintf, вы должны убедиться, что в вашей строке есть место для хранения вывода sprintf.
Первый метод: вы можете сделать это с .reserve()
метод, но он не изменит счетчик внутреннего размера строки, который возвращается .size()
если вы напрямую измените строковый буфер с sprintf()
метод (append()
сделаем правильную регулировку размера). Там не будет никаких проблем, если вам не нужно использовать .size()
метод, насколько я знаю.
Второй метод (лучше): это лучший способ, если вы знаете точную длину вывода sprintf. Вам следует позвонить .resize()
метод вместо .reserve()
, .resize()
правильно настроит счетчик размера строки.
Наконец, вы должны использовать: sprintf(const_cast<char *>(returnString.data()), ...
Кстати, все это не очень хорошая идея.
PS.data()
такой же как .**c**_str()
за исключением того, что он не добавляет нулевой терминатор, чтобы сделать его строкой в стиле c.
В современном C++ вы могли бы сказать:
std::string ClassName::toString() const
{
return "Position: (" + std::to_string(position.x) + ", "
+ std::to_string(position.y) + ", "
+ std::to_string(position.z) + ")\n";
}
Если вы должны использовать printf
, вы все еще можете использовать строку, но вы должны сначала изменить ее размер.
std::string ClassName::toString() const
{
static const int initial_size = 1024;
std::string s(initial_size);
int ret = std::snprintf(&s[0], s.size(), "Position: (%f, %f, %f)\n", position.x, position.y, position.y);
s.resize(ret);
// handle overflow: print again
if (s.size() > initial_size)
{
std::snprintf(&s[0], s.size(), "Position: (%f, %f, %f)\n", position.x, position.y, position.y);
}
return s;
}
Обратите внимание, что &s[0]
дает вам указатель на изменяемый символ, и на самом деле на первый элемент целого массива с размером s.size()
,
http://www.cplusplus.com/reference/string/string/c_str/
Возвращенный массив указывает на внутреннее местоположение с требуемым пространством хранения для этой последовательности символов плюс его завершающий нулевой символ, но значения в этом массиве не должны изменяться в программе и гарантированно останутся неизменными только до следующего вызова непостоянная функция-член строкового объекта.
вам не разрешено изменять содержимое возвращенного символа *
попробуйте что-то вроде:
void ClassName::toString(string& returnString)
{
char tmp[256];
sprintf(tmp, "Position: (%f, %f, %f)\n", position.x, position.y, position.y);
returnString=tmp;
}