Преобразование числа в строку с указанной длиной в C++

У меня есть несколько чисел разной длины (например, 1, 999, 76492 и т. д.), И я хочу преобразовать их все в строки с общей длиной (например, если длина равна 6, то эти строки будут: '000001' , 000999, 076492).

Другими словами, мне нужно добавить к числу правильное количество ведущих нулей.

int n = 999;
string str = some_function(n,6);
//str = '000999'

Есть ли такая функция в C++?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
51
0
60 062
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Есть много способов сделать это. Самый простой:

int n = 999;
char buffer[256]; sprintf(buffer, "%06d", n);
string str(buffer);

в этом случае вы действительно можете захотеть использовать: sprintf (buffer, "% 06d", n); обратите внимание на 0 перед 6, которое вам нужно дополнить нулями

Nathan Fellman 22.10.2008 15:35

Буфер размером 256 является излишним путь для этой цели. Несмотря на то, что число может превышать 7 символов (с чем связан ответ Исака с помощью snprintf), тем не менее, ни один известный мне int не занимает 256 символов. :-П

Chris Jester-Young 22.10.2008 15:45

Хорошее замечание, Крис. Я думаю, что самый большой int на самом деле чуть больше 999 999 999 999 999, поэтому char buffer [17] совершенно безопасен, учитывая \ 0 и, возможно, знак (хотя я не думаю, что самый большой отрицательный int будет где-то рядом с таким длинным).

Matt Curtis 22.10.2008 15:52

Самый большой int зависит от реализации. Большинство современных компиляторов используют 32-битное двоичное дополнение int, что означает, что наибольший int равен 2 147 483 647, а самый длинный int - min int, -2 147 483 648. Это 12 символов, считая завершающий NUL. Для переносимого кода int может иметь ЛЮБУЮ длину.

Steve Jessop 22.10.2008 16:01

Во-первых, это не С ++, а самый большой int - 2147483648, длина которого составляет всего 10 символов. Откуда у вас 999 999 999 999 999, я понятия не имею. Без знака он больше, но все равно имеет то же количество символов.

graham.reeds 22.10.2008 16:02

@graham: для целого числа со знаком вы также должны учитывать знак. Самый длинный номер - 2147483648, состоит из 11 символов (не считая нулевого байта).

Leon Timmermans 22.10.2008 16:04

Несмотря на предполагаемую простоту, sprintf - плохое решение. snprintf или stringstream предпочтительнее.

Kristopher Johnson 22.10.2008 16:08

Пространство стека можно выделить бесплатно, и если вы собираетесь переполнить стек только потому, что вы выделили буфер размером 256 байт, у вас большие проблемы. Хотя snprintf действительно безопаснее, он есть только в C99. Stringstream должен будет выделить некоторое количество памяти под капотом, поэтому он немного медленнее.

Pramod 22.10.2008 16:48

Я думаю, вы были отвергнуты пуристами C++ с большим «лабораторным» опытом ... у вас все было хорошо, пока кто-то не упомянул omfgstringstreams.

Matt Curtis 22.10.2008 17:06

@Pramod: он все равно хочет строку в конце, поэтому там требуется выделение памяти. Я подозреваю (но не могу позаботиться о том, чтобы убедиться в этом) реализации STL не будут выделять больше памяти в решении xtofl, чем в вашем. Ваш просто сохраняет его на последнюю строчку.

Steve Jessop 22.10.2008 18:45

sprintf - это способ, подобный C, который также работает в C++.

В C++ комбинация строкового потока и форматирования вывода потока (см. http://www.arachnoid.com/cpptutor/student3.html) выполнит свою работу.

char str[7];
snprintf (str, 7, "%06d", n);

См. snprintf

Хотя рекомендуется всегда использовать snprintf (), это одно из немногих мест, где вы можете безопасно использовать sprintf ().

Mark Baker 22.10.2008 16:27

Да, знаю. Но я всегда использую snprintf, потому что на самом деле нет причин не делать этого (разница в производительности незначительна).

Isak Savo 22.10.2008 18:04

arg # 2 - это size_t, а не len, поэтому это 7, а не 6. Однако лучше использовать sizeof.

PW. 22.10.2008 18:43

Не уверен, что мне что-то не хватает, но я думаю, что ему также нужен тип в строке формата, поэтому "% 06d" или аналогичный

JSoet 18.11.2015 03:05

Первым аргументом snprintf должен быть str, а не buf.

Duncan 04.05.2017 10:08
Ответ принят как подходящий

или используя строковые потоки:

#include <sstream>
#include <iomanip>

std::stringstream ss;
ss << std::setw(10) << std::setfill('0') << i;
std::string s = ss.str();

Я собрал информацию, которую нашел на arachnoid.com, потому что мне больше нравится типобезопасный способ iostreams. Кроме того, вы можете использовать этот код в любом другом потоке вывода.

К вашему сведению - для этого требуются включаемые файлы sstream и iomanip.

Gareth 21.03.2014 00:21

И stringstream, setw и setfill (а также string) находятся в пространстве имен std.

rafalcieslak 09.01.2015 16:32

В подобных ответах я всегда показываю результат. В данном случае, если int i=1;, это 0000000001.

thenakulchawla 30.04.2018 03:17

К вашему сведению, вы должны написать std::setfill('0'), как это делает этот ответ, вместо std::setfill("0"). (Я использую C++ 11)

Scott Yang 25.01.2019 19:36

Что делать, если i больше 10 цифр?

georgeliatsos 27.12.2019 14:37

stringstream будет делать (как указал xtofl). Формат повышения - более удобная замена snprintf.

Этот метод не использует ни потоки, ни sprintf. Помимо проблем с блокировкой, потоки несут накладные расходы на производительность и действительно являются излишними. Для потоков накладные расходы возникают из-за необходимости создания буфера пара и потока. Для sprintf накладные расходы возникают из-за необходимости интерпретировать строку формата. Это работает, даже когда п отрицательно или когда строковое представление п длиннее, чем len. Это САМОЕ БЫСТРОЕ решение.

inline string some_function(int n, int len)
{
    string result(len--, '0');
    for (int val=(n<0)?-n:n; len>=0&&val!=0; --len,val/=10)
       result[len]='0'+val%10;
    if (len>=0&&n<0) result[0]='-';
    return result;
}

Одна вещь, о которой вы должны знать май, - это потенциальная блокировка, которая может происходить, когда вы используете подход stringstream. В STL, который поставляется с Visual Studio 2008, по крайней мере, есть много снятых и выпущенных блокировок, поскольку во время форматирования используется различная информация о локали. Это может быть, а может и не быть проблемой для вас, в зависимости от того, сколько у вас потоков, которые могут одновременно преобразовывать числа в строки ...

Версия sprintf не принимает никаких блокировок (по крайней мере, в соответствии с инструментом мониторинга блокировок, который я разрабатываю в данный момент ...), и поэтому может быть «лучше» для использования в параллельных ситуациях.

Я заметил это только потому, что мой инструмент недавно заявил, что блокировки «локали» являются одними из наиболее часто используемых для блокировок в моей серверной системе; это стало немного неожиданностью и может заставить меня пересмотреть подход, который я использовал (т. е. вернуться к sprintf от stringstream) ...

Имеет смысл использовать локаль, но на самом деле она заблокирована ... Ценная информация!

xtofl 22.10.2008 23:31

Это может быть только Visual Studio STL, я не проверял тестовую программу, созданную с помощью STLPort. Я также не исследовал, почему он блокируется.

Len Holgate 23.10.2008 01:19

STLPort 5.1.5 не демонстрирует эту проблему конкуренции между потоками, но стиль преобразования sprintf все еще примерно в 3 раза быстрее ...

Len Holgate 20.12.2008 01:26

Вот интересный пост Лена Холгейта: lenholgate.com/archives/000824.html

Alessandro Jacopson 21.12.2008 12:38

Это старый поток, но поскольку fmt может стать стандартом, вот дополнительное решение:

#include <fmt/format.h>

int n = 999;

const auto str = fmt::format("{:0>{}}", n, 6);

Обратите внимание, что fmt::format("{:0>6}", n) работает одинаково хорошо, когда желаемая ширина известна во время компиляции. Другой вариант - спуск:

#include <absl/strings/str_format.h>

int n = 999;

const auto str = absl::StrFormat("%0*d", 6, n);

Опять же, abs::StrFormat("%06d", n) возможен. формат повышения - еще один инструмент для решения этой проблемы:

#include <boost/format.hpp>

int n = 999;

const auto str = boost::str(boost::format("%06d") % n);

К сожалению, спецификатор переменной ширины в качестве аргументов, связанных с оператором %, не поддерживается, для этого требуется настройка строки формата (например, const std::string fmt = "%0" + std::to_string(6) + "d";).

Что касается производительности, abseil и fmt утверждают, что они очень привлекательны и быстрее, чем boost. В любом случае все три решения должны быть более эффективными, чем подходы std::stringstream, и, за исключением семейства std::*printf, они не жертвуют типовой безопасностью.

Другие вопросы по теме