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;
}
Другие вопросы по тегам