質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

2572閲覧

C言語で3桁ごとにカンマ区切りするプログラム

komori_k

総合スコア2

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2024/05/16 02:46

実現したいこと

「数値Nが入力します。 位の小さい方から 3 けたごとにカンマ区切りで出力してください。
ただし、Nのけた数は 3 の倍数とは限らない」この実現方法がわかりません

発生している問題・エラーメッセージ

以下のようなコードを書いてみたのですが、
入力が123456789の場合
期待する出力としては123,456,789で
以下のコードで一応出力としては正しく出るのですが、
自分的にあまり納得のいく綺麗なコードとは言えず、
もっといい実現方法があれば教えていただきたいです。

該当のソースコード

C

1#include <stdio.h> 2#include <string.h> 3 4int main(void){ 5 char n[256]; 6 scanf("%s",n); 7 int len=1; 8 for(int i=0;i<strlen(n);i++){ 9 if(len%3==0){ 10 if(n[i+1]!=NULL){ 11 printf("%c,",n[i]); 12 }else{ 13 printf("%c",n[i]); 14 } 15 }else{ 16 printf("%c",n[i]); 17 } 18 len=len+1; 19 } 20 return 0; 21}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

melian

2024/05/16 03:13

※ 質問文を読むと何らかの課題の様なので、参考までに… そちらの環境が POSIX 2008 に準拠している場合、printf(3) が '(アポストロフィ) フォーマット指示子に対応しているかもしれません。 fprintf - The Open Group Base Specifications Issue 7, 2018 edition IEEE Std 1003.1-2017 (Revision of IEEE Std 1003.1-2008) https://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html > (The <apostrophe>.) The integer portion of the result of a decimal conversion ( %i, %d, %u, %f, %F, %g, or %G ) shall be formatted with thousands' grouping characters. For other conversions the behavior is undefined. The non-monetary grouping character is used.  #include <stdio.h> #include <locale.h> int main(void) { setlocale(LC_NUMERIC, ""); printf("%'d\n", 123456789); return 0; }
jimbe

2024/05/16 03:14

>自分的にあまり納得のいく綺麗なコードとは言えず 個人的な感覚では他人にはどうすれば納得なのか分かりません。 基準を示していただけますか?
guest

回答3

0

ベストアンサー

位の小さい方から 3 けたごとにカンマ区切りで出力してください。

ひとつの数字を出力した後にカンマが必要となる条件は「未出力の数字があり,かつその個数が 3の倍数」と考えられます。そして,全個数が leni 番目(最初は 0番目)を出力した後の未出力の個数は r = len - i - 1 になります。

これを基にした記述例を下記に示します。

C

1#include <stdio.h> 2#include <string.h> 3 4int main(void) { 5 char n[256]; 6 int len, i, r; 7 8 scanf("%s", n); 9 len = strlen(n); 10 11 for (i = 0; i < len; i++) { 12 printf("%c", n[i]); 13 r = len - i - 1; 14 if (r > 0 && r % 3 == 0) 15 printf(","); 16 } 17 printf("\n"); 18 19 return 0; 20}

投稿2024/05/16 09:16

little_street

総合スコア435

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

komori_k

2024/05/16 09:33

わかりやすい回答ありがとうございます!
guest

0

仕様を満たしているかでは無く単にコードを変形させるだけしてみます。方向性としては「同じことは何度も書かない」「短い」です。

目立つのはループ内に 3 つある n[i] を表示する printf 。

c

1 if(len%3==0){ 2 if(n[i+1]!=NULL){ 3 printf("%c,",n[i]); 4 }else{ 5 printf("%c",n[i]); 6 } 7 }else{ 8 printf("%c",n[i]); 9 }

どの if のルートを通っても n[i] を表示するのは変わらず、一箇所後ろに "," があるだけですので if の前でまず n[i] を表示してしまいます。

c

1 printf("%c",n[i]); 2 if(len%3==0){ 3 if(n[i+1]!=NULL){ 4 printf(","); 5 } 6 }

すると "," を表示するかの判断の if は一つに出来ます。

c

1 printf("%c",n[i]); 2 if(len%3==0 && n[i+1]!=NULL){ 3 printf(","); 4 }

len 変数。

c

1 int len=1; 2 for(int i=0;i<strlen(n);i++){ 3 //処理 4 len=len+1; 5 }

ループの中でしか使用せず、その値は常に i+1 ですので処理の中の len を (i+1) に変更します。

c

1 for(int i=0;i<strlen(n);i++){ 2 printf("%c",n[i]); 3 if((i+1)%3==0 && n[i+1]!=NULL){ 4 printf(","); 5 } 6 }

i+1 が 2 か所あることと for に i++ があるので纏めることも出来ます。

c

1 for(int i=0;i<strlen(n);){ 2 printf("%c",n[i++]); 3 if(i%3==0 && n[i]!=NULL){ 4 printf(","); 5 } 6 }

一応文字列の終端は NULL でなくヌル文字 '\0' (のはず)ですので、気にする向きには n[i]!='\0' とかいっそ n[i] だけとか。


出題通りの結果を得た上で、 c ライクな感じに。
最初の "," までの桁を表示した後は ","+3桁の繰り返しとします。
※ printf の format に "*" が使えるコンパイラが必要

c

1#include <stdio.h> 2#include <string.h> 3 4int main(void) { 5 char n[256]; 6 scanf("%s", n); 7 8 for(char *p=n,w="\3\1\2"[strlen(n)%3];*p;p+=w,w=3){ 9 printf(",%.*s"+(p==n),w,p); 10 } 11 printf("\n"); 12 13 return 0; 14}

投稿2024/05/16 04:16

編集2024/05/17 11:31
jimbe

総合スコア13318

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

位の小さい方から 3 けたごとにカンマ区切りで出力してください

とされているのに,
「位の大きい側から3桁出力する毎にカンマを追加で出力する」という処理では,求められていることと違うことをしていますよね.

例えば 1234 という入力に対する出力結果が 123,4 になってしまいますよね.
(求められている結果とは 1,234 という出力であるハズ.)


とりあえず以下のコード(関数)は入力を単にそのまま(先頭から1文字ずつ)出力するだけです.

C

1void Output( const char *Input ) 2{ 3 const int len = strlen( Input ); 4 for( int i=0; i<len; ++i ) 5 {//i番目の文字を出力する 6 putchar( Input[i] ); 7 } 8}

このコードの //i番目の文字を出力する のところを,条件次第では カンマとi番目の文字 を出力する という話に変えてみるとどうでしょうか.

C

1void Output( const char *Input ) 2{ 3 const int len = strlen( Input ); 4 for( int i=0; i<len; ++i ) 5 { 6 //条件次第では先にカンマを出力する 7 if( ??? ) 8 { putchar( ',' ); } 9 //i番目の文字を出力する 10 putchar( Input[i] ); 11 } 12}

あとは ??? の条件を,題意に沿うように考えてやれば良さそうです.

  • i というのは先頭側(位の大きい側)から数えている値なわけですが,これを「後ろ側(位の小さい側)から何番目の場所か?」という値にうまく読替えてやれば,題意を満たす方法を考えることができそうですよね.
    例えば,入力の長さが4桁であるとき,i の値は {0,1,2,3} なわけですが,len - i という値を考えれば { 4,3,2,1 } になりますよね.この値を用いればとても考えやすそうに思えます.
  • 出力結果の先頭にいきなりカンマが出てくるのはまずいので「先頭文字の場合にはカンマを付けない」みたいな条件が必要かもしれません.

……とか考えてみた結果をコードに反映するならば,以下のようになります.

C

1void Output( const char *Input ) 2{ 3 const int len = strlen( Input ); 4 for( int i=0; i<len; ++i ) 5 { 6 //先頭ではなくて,且つ,後ろ側から数えた位置(len-i)が3の倍数であるならば, 7 //先にカンマを出力する 8 if( (i>0) && ( (len-i)%3 == 0 ) ) 9 { putchar( ',' ); } 10 11 putchar( Input[i] ); 12 } 13}

※まぁ,この例が

納得のいく綺麗なコード

と言えるのかは否か? についてはわかりませんが.

投稿2024/05/16 03:25

編集2024/05/16 03:30
fana

総合スコア12151

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問