C에서 1123456789에서 1,123,456,789로 숫자를 포맷하는 방법은 무엇입니까?


83

C 언어 형식으로 숫자를에서 1123456789까지 어떻게 할 수 1,123,456,789있습니까? 나는 사용해 printf("%'10d\n", 1123456789);보았지만 작동하지 않습니다.

조언 해 주시겠습니까? 솔루션이 간단할수록 좋습니다.


1
FYI : printf()형식화 된 IO 함수 제품군에 대한 '수천 구분 기호'플래그 (작은 따옴표 문자 : ')는 일부 라이브러리 구현에서만 지원되는 비표준 플래그입니다. 표준이 아니라는 것이 너무 나쁩니다.
Michael Burr

1
로케일에 따라 다릅니다. 에 따르면 리눅스 맨 페이지 , 그것은 본다 LC_NUMERIC. 그러나 어떤 로케일이 이것을 지원하는지 모르겠습니다.
Joey Adams

1
@Joey, LC_NUMERIC로케일을 현재로 설정하면 Mac과 방금 확인한 Linux 시스템 ""에서 '작동합니다.
Carl Norum

printf()함수 계열의 POSIX 2008 (2013) 버전은 '십진수 형식화 변환 사양과 함께 (작은 따옴표 또는 아포스트로피) 문자 사용을 표준화 하여 숫자가 천 단위 구분 기호로 형식화되어야 함을 지정합니다.
Jonathan Leffler 2015

2
또한 기본 "C"로케일에서 비 화폐 천 단위 구분 기호는 정의되지 않으므로 로케일 "%'d"에서 쉼표를 생성하지 않습니다 "C". 천 단위가 아닌 적절한 구분 기호를 사용하여 로케일을 설정해야합니다. 종종 setlocale(LC_ALL, "");작업을 수행합니다. 로케일 이름에 대한 다른 값 (빈 문자열 제외)이 구현으로 정의됩니다.
Jonathan Leffler 2015

답변:


83

printf가 '(POSIX 2008에서 요구하는대로) 플래그를 지원한다면 printf(), 당신의 로케일을 적절하게 설정함으로써 가능할 것입니다. 예:

그리고 빌드 및 실행 :

Mac OS X 및 Linux (Ubuntu 10.10)에서 테스트되었습니다.


1
나는에이 테스트 한 sprintf()임베디드 시스템에서 당신이 말한대로, 그것은 '플래그를 지원하지 않기 때문에 그것은 분명히 (일을하지 않습니다.
gbmhunter

나는 당신이 너무 많은 문제없이 그것을 지원할 C 라이브러리를 찾을 수 있다고 확신합니다.
Carl Norum

나는 훑어 보았지만 적합한 것을 찾지 못했고 위의 아이디어 중 일부를 사용하여 내 자신의 것을 구현했습니다. 실제 라이브러리를 찾아서 소수 자리가있는 부동 소수점과 문자열에 사용할 수 있으면 좋을 것입니다.
gbmhunter 2013 년

1
FWIW AtmelStudio 의 임베디드 시스템 printf () 는 수정자를 지원 하지 않는 비극적으로 보입니다 '. 헤더에서 : Copyright ... 2007 Joerg Wunsch ... 1993 Regents of the University of California즉 BSD 파생물.
Bob Stein

2
이것은 편리하지만이 기능 (setlocale)에 대한 상태를 반드시 변경하고 싶지는 않습니다.
ideasman42

46

다음과 같이 재귀 적으로 수행 할 수 있습니다 ( INT_MIN2의 보수를 사용하는 경우이를 관리하려면 추가 코드가 필요합니다).

요약 :

  • 사용자 printfcomma는 정수로 호출합니다. 음수의 특수한 경우는 단순히 "-"를 인쇄하고 숫자를 양수로 만들어 처리합니다 (이는에서 작동하지 않는 비트입니다 INT_MIN).
  • 를 입력하면 printfcomma21,000 미만의 숫자 만 인쇄되고 반환됩니다.
  • 그렇지 않으면 1,000 미만의 숫자를 찾을 때까지 다음 레벨에서 재귀가 호출됩니다 (따라서 1,234,567은 1,234로 호출 된 다음 1).
  • 그런 다음 그 숫자가 인쇄되고 재귀 트리로 돌아가서 쉼표와 다음 숫자를 인쇄합니다.

모든 수준 에서 음수를 검사 할 때 불필요한 처리를 수행하지만 더 간결한 버전도 있습니다 (제한된 수의 재귀 수준을 고려할 때 중요하지 않음). 이것은 테스트를위한 완전한 프로그램입니다.

출력은 다음과 같습니다.


재귀를 신뢰하지 않는 사람들을위한 반복적 인 솔루션 (재귀의 유일한 문제는 스택 공간이되는 경향이 있지만 64 비트 정수의 경우에도 몇 수준 만 깊기 때문에 여기서는 문제가되지 않습니다) :

이 두 생성 2,147,483,647을 위해 INT_MAX.


위의 모든 코드는 3 자리 그룹을 쉼표로 구분하기위한 것이지만 공백과 같은 다른 문자도 사용할 수 있습니다.


나는 문제가 재귀 적 ( "나머지에서 세 번째 자릿수를 분리 한 다음 나머지에서 이것을 반복")보다 더 자연스럽게 반복적 ( "세 번째 자릿수마다 분리")이기 때문에이 문제를 반복적으로 해결해야한다고 생각합니다.
Joren

MIN_INT에 대해 제안 된 수정 사항 : 서명되지 않은 정수를 사용하도록 printfcomma2를 변경하십시오. 그게 다야. 그다지 "추가 코드"는 아닙니다. :-)
Steve Jessop

@Joren : 반복 솔루션을 추가했으며 어느 정도 재귀 솔루션이 장점이있는 이유를 보여줍니다. 많은 경우에 재귀를 피하는 것이 코딩 표준 문제입니다.
Clifford

@ 스티브 : 그냥 UB 곧 당신이 부정으로로 호출했기 때문에 인수의 형태가 해결되지 않습니다 변화 nprintfcomma. 부정하기 전에 unsigned 변환을 강제해야합니다.
R .. GitHub의 STOP 돕기 ICE

1
@Nehal, 현재 진행 상황이 모두 손실된다는 의미에서 다시 시작하지 않습니다. 자신을 재귀 적으로 호출 한 다음 다음 문인 printf.
paxdiablo

11

다음은 매우 간단한 구현입니다. 이 함수는 오류 검사를 포함 하지 않으며 버퍼 크기는 호출자가 확인해야합니다. 음수에도 작동하지 않습니다. 이러한 개선 사항은 독자를위한 연습으로 남겨집니다.


나는 이것을 좋아한다. 그것은 임베디드 시스템에 유용한 printf 대신 sprintf를 사용한다.
gbmhunter 2013 년

1
꽤 좋지만 음수로 작동하려면 약간의 조정이 필요합니다.
ideasman42

(음수 지원을위한 수정 된 버전 stackoverflow.com/a/24795133/432509 )
ideasman42

5

Egads! 저는 리눅스에서 gcc / g ++와 glibc를 사용하여 항상이 작업을 수행합니다. 그렇습니다. '연산자는 비표준 일 수 있지만 단순함이 마음에 듭니다.

다음의 출력을 제공합니다.

큰 숫자 : 12,345,678

거기에있는 'setlocale'호출을 기억해야합니다. 그렇지 않으면 아무것도 형식화하지 않습니다.


2
안타깝게도 Windows / gcc 4.9.2에서는 작동하지 않는 것 같습니다.
rdtsc

잘 Drat! 나는 어떤 플랫폼의 gcc가 OS에 관계없이 비슷한 결과를 줄 것이라고 생각했을 것입니다. 알아서 반가워요, 왜 그런지 궁금합니다. Hmmmmm .....
lornix

사용중인 C 라이브러리가 '플래그를 지원 하지 않으면 원하는 출력을 얻지 못하며 컴파일러와 무관합니다. 컴파일러는에 대한 라이브러리 함수 printf()가 형식 문자열로 호출 되는지 확인 합니다. 그것을 해석하는 것은 라이브러리 함수에 달려 있습니다. Windows에서는 CRT 라이브러리가 필요한 지원을 제공하지 않을 수 있으며 사용하는 컴파일러는 중요하지 않습니다.
Jonathan Leffler

3

로케일 인식 버전이 흥미로울 것입니다.

이것은 버그가 있습니다 (하지만 상당히 사소하다고 생각하는 버그입니다). 2의 보수 하드웨어에서는 음수를 N = -N;2의 보수에서 동등한 양수로 변환하려고 시도하기 때문에 가장 음수를 올바르게 변환 하지 않습니다. 더 큰 유형으로 승격하십시오. 이 문제를 해결하는 한 가지 방법은 해당하는 서명되지 않은 유형으로 숫자를 승격하는 것입니다 (그러나 다소 사소하지 않습니다).


나는 더 많은 형식의 크로스 플랫폼 구현을 향한 질문 요청 '여기 -flag을 : stackoverflow.com/q/44523855/2642059는 내가 완벽하게, 더하고 이제 테스트 주소를이 대답을 생각합니다. 그렇다면 나는 그 질문을 속임수로 표시해야한다고 생각한다.
Jonathan Mee

좋아, 내가 처음 알아 본 것은 로케일이 조정될 때 조정되지 않는다는 것입니다. 왜 유지 tsep, place_str그리고 neg_str전혀? 님 fmt_info의 회원을 직접 사용하지 않으 시겠습니까?
Jonathan Mee

좋아요, 두 번째로,이 코드는 음수를 처리 할 수 ​​없습니다. 어떻게 할 수 있는지 정확히 모르겠습니다 while (*ptr-- = *neg_str++). 역순으로 음수 문자열 문자를 삽입합니다.
Jonathan Mee

그래서 ... 메모리 누수를 제거하고 음수로 버그를 수정했습니다. ideone.com/gTv8Z4 불행히도 여러 문자 구분 기호 또는 여러 문자 음수 기호가 문자열에 거꾸로 쓰여지는 문제가 여전히 있습니다. 그 다음 ... 해결하려고하는거야
조나단 미는

@JonathanMee : 코드를 업데이트했습니다 (음수를 포함하여 적어도 몇 가지 테스트 사례를 추가했습니다).
제리 관

2

재귀 또는 문자열 처리없이 수학적 접근 방식 :

원칙적으로 Pax의 재귀 솔루션과 유사하지만 사전에 크기 순서를 계산하면 재귀를 피할 수 있습니다 (아마도 상당한 비용이 듭니다).

천 단위를 구분하는 데 사용되는 실제 문자는 로케일에 따라 다릅니다.

편집 : 개선 사항은 아래 @Chux의 의견을 참조하십시오.


1
을 수행 할 때 2의 칭찬 오류 abs(n)fabs(n)방지 하도록 변경 합니다 print_number(INT_MIN).
chux - 분석 재개 모니카

@chux : 좋은 지적이지만 % 표현식에서 LHS는 int로 다시 캐스팅되고 여전히 손상됩니다. 허용 가능한 입력의 범위가 약간 더 작거나 INT_MIN (또는 해당 플랫폼에있는 INT_MIN이 무엇이든간에 테스트 및 출력 "-2,147,483,647"을 직접 추가하는 것이 더 간단 할 수 있습니다. 그 안에 또 다른 웜 캔이 있습니다.
Clifford

제안하기 전에 성공적으로 테스트했습니다. 흠. 내 아이디어는 log10(abs(n))다른 곳이 아닌를위한 것이 었습니다 . 흥미롭게도, 당신의 솔루션에 하나의 변화와 함께 작동 log10(fabs(n))하고 print_number(INT_MIN)있기 때문에의 printf(..., abs(n / order_of_magnitude))수단이되는 n = abs(INT_MIN) % order_of_magnitude부정적 OK입니다. 우리가 INT_MIN에 접속을 제공하는 경우가 printf(..., abs(n / order_of_magnitude))될 수 있습니다 printf(..., n / order_of_magnitude). 하지만 "abs (INT_MIN)"라는 웜으로 작업하는 것은 일반적으로 나쁜 일이라고 생각합니다.
chux-Monica 복원

새로운 생각 : 3 명 변경을 제안 log10(fabs(n)), n = abs(n% order_of_magnitude)하고 printf(",%03d", n/order_of_magnitude). BTW : 솔루션이 좋다고 생각하지 않는 한이 노력을 기울이지 않을 것입니다. INT_MIN에도 UB가 없습니다.
chux-Monica 복원

2

@Greg Hewgill을 기반으로하지만 음수를 고려하여 문자열 크기를 반환합니다.


1

내 대답은 질문의 그림과 똑같은 결과를 형식화하지 않지만 경우에 따라 간단한 한 줄 또는 매크로로 실제 요구충족시킬 수 있습니다 . 필요에 따라 더 많은 천 그룹을 생성하도록 확장 할 수 있습니다.

결과는 다음과 같이 표시됩니다.

Value: 0'000'012'345

코드:


'A와 표준 표기법과 동등한 ,세계 (수학적으로, 적어도) 어떤 부분 (들)?
ysap

1
@ysap 세계의 일부 지역에서는 천 단위 구분 기호입니다.
Roland Pihlakas

0

C에서이 작업을 수행하는 실제 간단한 방법은 없습니다. int-to-string 함수를 수정하여 수행합니다.


0

또 다른 반복 함수


배열의 차원을 결정하는 데 사용되는 표현에 흥미가 있습니다!? 그것에 대한 수학적 정당성이 있습니까?
Clifford

각 십진수에 대한 ld (10) 비트. 3으로 내림하여 3을 다시 나눌 수 있습니다 (한 번에 최대 3 자리를 저장한다는 사실을 설명하기 위해). 그러나 나는 그것을 상한선으로 유지하고 싶었습니다.
Johannes Schaub-litb

0

다음은 이러한 종류의 10 진수 형식을 가장 얇고, 크기 및 속도 효율적으로 구현 한 것입니다.

다음과 같이 사용하십시오 :

산출:

몇 가지 장점 :

  • 역순 포맷으로 인해 문자열 버퍼의 끝을 차지하는 함수입니다. 마지막으로 생성 된 문자열 (strrev)을 고려할 필요가 없습니다.

  • 이 함수는 모든 알고리즘에서 사용할 수있는 하나의 문자열을 생성합니다. 끔찍하게 느리고 항상 상황에 따라 달라지는 여러 printf / sprintf 호출에 의존하거나 필요하지 않습니다.

  • 나누기 연산자의 최소 수 (/, %).

무엇입니까 unlikely?
Dan Bechard

1
@Dan : unlikely조건이 참일 가능성이 낮다는 최적화 프로그램에 대한 힌트 일 수 있습니다. 자세한 내용 은 Linux 커널의 likely()/ unlikely()매크로 를 참조하십시오.
Jonathan Leffler

@JonathanLeffler 오, 허. 링크 주셔서 감사합니다.
Dan Bechard

0

음수로 안전한 format_commas :

VS <2015는 snprintf를 구현하지 않으므로 이렇게해야합니다.

그리고

사용 예 :


0

@paxdiablo 솔루션의 수정 된 버전이지만 WCHAR및 사용 wsprinf:


0

저는 C 프로그래밍이 처음입니다. 여기 내 간단한 코드가 있습니다.


0

내 솔루션은. 대신, 이것을 변경하는 것은 독자의 책임입니다.


0

이것은 오래되었고 많은 답변이 있지만 질문은 "쉼표를 추가하는 루틴을 어떻게 작성할 수 있습니까?"가 아니라 "C에서 어떻게 할 수 있습니까?"였습니다. 의견은이 방향을 지적했지만 GCC가있는 Linux 시스템에서는 다음과 같이 작동합니다.

이것이 실행되면 다음을 얻습니다.

LC_ALL프로그램을 실행하기 전에 변수를 설정 해제하면 unsetenv필요하지 않습니다.


0

직접 인쇄하기보다는 직접 비슷한 작업을 수행해야하고 버퍼로 이동해야했습니다. 여기에 제가 생각 해낸 것이 있습니다. 거꾸로 작동합니다.

부호없는 정수용으로 만 설계되었으며 버퍼가 충분히 큰지 확인해야합니다.


0

또 다른 솔루션은 결과를 int배열 에 저장하여 최대 크기가 7입니다. long long int유형이 9,223,372,036,854,775,807 에서 -9,223,372,036,854,775,807 범위의 숫자를 처리 할 수 있기 때문 입니다. (부호없는 값이 아닙니다).

비 재귀 인쇄 기능

주요 기능 호출

테스트 출력

main () 함수에서 :

인쇄가 필요한 모든 것이면 int numberSeparated[8];함수 내부 로 이동 getNumWcommas하여 이렇게 호출하십시오 getNumWcommas(number).


-1

아주 쉽게 할 수 있습니다 ...

통화 예 :


-1

1
코드를 게시 할 때 최소한 적절한 들여 쓰기를 사용하십시오. 또한 기존 답변이 아직 수행하지 않은 작업에 대한 설명을 추가 할 수도 있습니다.
EWit

이것은 단순함의 미덕을 가지고 있으며 한눈에 쉽게 이해할 수 있습니다.
steve newman 2014-07-15

1
가짜 솔루션 은 ,아래의 숫자에 대한 추가 인쇄, 날아갈 곳 을 100사용 printf()하고 putchar(), 오해의 소지가있는 이름, 혼란스러운 들여 쓰기 및 너무 많은 코드를 사용합니다.
chqrlie

-1

1
이 코드에는 다양한 문제가 있습니다. 사용하지 않는 변수 idx는 갈 수 있습니다. 코드는 0에 대해 아무것도 생성하지 않습니다. 음수를 처리하지 않습니다. 변수 를 만들어야 buffer하는 명백한 이유가 없습니다 static(코드의 재진입을 제한 함). 그것이 무엇을하는지에 대한 설명이 없거나 코드가 완료된 후로 가리키는 p문자열에 형식이 지정된 문자열이 포함되어 있다고 언급하지 않습니다 . 가장 심각한 문제는 천 단위 구분 기호로 쉼표 대신 공백을 사용한다는 것입니다. 하지만 제로를 처리하지 못한다는 사실이 킬러 문제입니다.
Jonathan Leffler 2015
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.