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

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

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

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

7回答

13892閲覧

【C言語の質問です】数値を貨幣単位に分解するプログラムの作成・・

退会済みユーザー

退会済みユーザー

総合スコア0

C

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

1グッド

1クリップ

投稿2016/02/25 02:04

編集2016/02/25 07:19

*たくさんの方よりご指摘をいただけてとてもありたいです。
引き続き、よろしくお願い致します。

C言語を勉強している初心者のものです。

今課題をいただき、その作成をしております。
先日提出(全18問)したのですが、大部分が間違っているので、
再度問題を見なおした上で提出してくれと言われてしまいました。

今回は課題なので、間違っている点を教えていただけませんでした。
個人的には、どの辺りが間違っているのかわからないため、
客観的な視点が欲しく、今回ご相談させていただきました。

18問の中の1つですが、
ソースが問題文との趣旨と外れているようでしたら
ご指摘いただけますと幸いです。

【問題】
入力した数値を貨幣単位(金種)に分解し、
それぞれの通貨が何枚必要かを表示するプログラムを作成せよ。

例)「12345」と入力した場合
10000円:1枚
5000円:0枚
1000円:2枚
500円:0枚
100円:3枚
50円:0枚
10円:4枚
5円:1枚
1円:0枚

【回答】

#include <stdio.h> int main (void) { int yen, th10, th5, th, hand5, hand, ten5, ten, five , one; printf("金額を入力してください。"); scanf("%d", &yen); if(yen <= 0) { printf("整数で再度入力してください"); return 0; } th10 = yen / 10000; yen = yen % 10000; th5 = yen / 5000; yen = yen % 5000; th = yen / 1000; yen = yen % 1000; hand5 = yen / 500; yen = yen % 500; hand = yen / 100; yen = yen % 100; ten5 = yen / 50; yen = yen % 50; ten = yen / 10; yen = yen % 10; five = yen / 5; one = yen % 5; printf("10000円札は%d枚です。\n", th10); printf(" 5000円札は%d枚です。\n", th5); printf(" 1000円札は%d枚です。\n", th); printf(" 500円玉は%d枚です。\n", hand5); printf(" 100円玉は%d枚です。\n", hand); printf(" 50円玉は%d枚です。\n", ten5); printf(" 10円玉は%d枚です。\n", ten); printf(" 5円玉は%d枚です。\n", five); printf(" 1円玉は%d枚です。\n", one); return 0; }
Odacchi👍を押しています

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

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

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

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

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

k1000

2016/02/25 06:46

「貨幣単位に分解」というタイトルを読んで最初に想像したのは円とドルとユーロとか……みたいなものでした。おそらく課題を出した人が言葉を知らないのだとは思うのですが、こういった「一万円札」とか「千円札」「五十円玉」といった額面による貨幣の種類のことを「金種」といいますので、今後検索される方の参考のためにこの単語も入れていただければと思います。 あと、「例)」で気になったのですが「12345」と入力したら五円玉が1枚で一円玉は0枚ですよね……?(もとの問題文が間違っていた?)
退会済みユーザー

退会済みユーザー

2016/02/25 07:20

ご指摘ありがとうございました。 間違っておりましたので、修正いたしました。 ありがとうございます!
guest

回答7

0

枚数を計算する部分と、枚数を画面出力する部分は分離させておくと、動作テストを書きやすくなります。
(ここではテストコードは示しませんが。)
1.c

c

1#include <stdio.h> 2#include <stdlib.h> 3 4void maisuu(int kingaku, const int size, const int * kinsyu, int * nums) { 5 for (int i = 0; i < size; i++) { 6 nums[i] = kingaku / kinsyu[i]; 7 kingaku %= kinsyu[i]; 8 } 9} 10void show_nums(const int size, const int * kinsyu, int * nums) { 11 for (int i = 0; i < size; i++) { 12 if (nums[i] > 0) { 13 printf("%5d円 %4d枚\n", kinsyu[i], nums[i]); 14 } 15 } 16} 17 18int main() { 19 const int KINSYU[] = {10000, 5000, 2000, 1000, 500, 100, 50, 10, 5, 1}; 20 const int KINSYU_SIZE = sizeof(KINSYU) / sizeof(KINSYU[0]); 21 int nums[KINSYU_SIZE]; 22 char buf[32]; 23 24 printf("金額を入力してください\n"); 25 fgets(buf, sizeof(buf), stdin); 26 int kingaku = (int)strtol(buf, 0, 10); 27 if (kingaku <= 0) { 28 printf("ERROR: 0より大きい値を入力してください。\n"); 29 return 1; 30 } 31 32 maisuu(kingaku, KINSYU_SIZE, KINSYU, nums); 33 show_nums(KINSYU_SIZE, KINSYU, nums); 34 return 0; 35}

実行例:

$ gcc 1.c $ ./a.out 金額を入力してください 12345.6 10000円 1枚 2000円 1枚 100円 3枚 10円 4枚 5円 1枚

投稿2016/04/08 23:35

katoy

総合スコア22324

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

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

0

雲を掴むような状態の手助けにはならないでしょうが、
コンピュータ計算に於ける、(古からの)3大問題というのがありまして、
1.板取問題(木材、合板、生地パターニング、鉄板のパターニングなど)
2.金種問題(今回の様に、金種を決めるもの、店舗現金残やレジ残を考慮したつり銭の用意、
毛色は違いますが、一括入金額から、請求金額を割当するものなど、)
3.シフト問題(シフト勤務表だけでなく、スケジュールに類するもの)
休暇、退職、突発事象、に、平等と我儘を加えると、不条理になる場合も。
があり、繰返し計算が必要になる事例です。
金種問題や、シフト問題は、不合理か、不条理な前程条件が有ったりして、
プログラミングに、苦しむ場合もあるようです。
(業務上の規定の実現で済まず、現状肯定をどうやって実現するかだったり。)
板取問題は、利益に直結するので、コンピュータ黎明期より、
数学的手法を駆使したりして、試みられてきましたが、
未だに、最適解が得られにくい場合もある様です。
(最近も、鉄板の切出し最適解アプリのニュースがでてましたっけ)
そんな、周辺情報をネット検索しながら、情報収集をすると、
気分が楽になるかもしれません。

投稿2016/03/20 02:21

編集2016/03/20 02:27
daive

総合スコア2028

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

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

退会済みユーザー

退会済みユーザー

2016/03/20 07:21

ご回答ありがとうございます。 そうなんですね! 3大問題初めて知りました! ご教示ありがとうございます!!
guest

0

ベストアンサー

目新しい事はありませんが・・・読み込み部分を変更しました。

c

1~/test/ctst >cat tst06.c 2#include <stdio.h> 3#include <stdlib.h> 4 5int main() 6{ 7 const int kinsyu[] = { 10000, 5000, 2000, 1000, 500, 100, 50, 10, 5, 1, 0 }; 8 char buf[32]; 9 10 printf("金額を入力してください\n"); 11 fgets( buf, sizeof buf, stdin ); 12 int kingaku= (int)strtol( buf, 0, 10 ); 13 // 14 if( kingaku < 0 ){ 15 puts("借金は計算できません ;-p\n"); 16 exit(1); 17 } 18 int inx= 0; 19 while( kinsyu[inx] ){ 20 int num= kingaku / kinsyu[inx]; 21 printf( "%d円 %d枚\n", kinsyu[inx], num ); 22 kingaku %= kinsyu[inx]; 23 inx++ ; 24 } 25 26 return 0; 27}

~/test/ctst >./a.out
金額を入力してください
12345
10000円 1枚
5000円 0枚
2000円 1枚
1000円 0枚
500円 0枚
100円 3枚
50円 0枚
10円 4枚
5円 1枚
1円 0枚
~/test/ctst >./a.out
金額を入力してください
0
10000円 0枚
5000円 0枚
2000円 0枚
1000円 0枚
500円 0枚
100円 0枚
50円 0枚
10円 0枚
5円 0枚
1円 0枚
~/test/ctst >./a.out
金額を入力してください
-12345
借金は計算できません ;-p

投稿2016/02/25 10:46

編集2016/02/25 10:48
cateye

総合スコア6851

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

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

退会済みユーザー

退会済みユーザー

2016/02/25 11:14

ご回答ありがとうございます! fgets関数はじめてみました! 他にもputs関数もはじめてみたものでしたので、 記載いただいたものを参考にしながら勉強させていただきます。 ありがとうございました!
cateye

2016/02/25 17:36 編集

fgets()はバッファサイズを指定できるので、オーバーフロー(変数やスタックを壊す現象:バッファより長い文字列を読み込んだ場合などに発生する)が起きません。今回は数字だけの読み込みなのでstrtol()を使っていますが、fgets()→sscanf()を使えばscanf()を使うより安全に処理が出来ます。詳しい事はfgets(),sscanf()の仕様を確認してみてください。 [捕捉]cの関数は必ず返り値があります。上記はチェックしていませんが、チェックするようにしましょう。printf()の返り値(出力文字数)って何か役に立つんだろうか・・・^^;
退会済みユーザー

退会済みユーザー

2016/02/26 05:15

ご回答ありがとうございます。 やはりfgets(),sscanf()を使ったほうが安全なんですね! 課題作成と併せて、勉強していきます! ありがとうございました! >[捕捉]cの関数は必ず返り値があります。上記はチェックしていませんが、チェックす>るようにしましょう。printf()の返り値(出力文字数)って何か役に立つんだろう^^; こちらはオーバーフロー等のチェックになりますでしょうか。
cateye

2016/03/01 20:43

出力(printf()等の画面、ファイルへの出力)は、私もあまり気にしないで使っています。相手がメモリならチェックするかもですが通常printf()は使いません。入力(sscanf()等)はちゃんと項目が読み込めているか?の判断に使います。scanf()関連は読み取った項目数が返ってきます。
guest

0

// 指定額に必要な通貨の枚数を表示する.
// money=入力された金額
void printKahei(int money) {
static const int kaheis[] = { 10000, 5000, 1000, 500, 100, 50, 10, 5, 1 };// 貨幣単位リスト.
for (int i = 0; i < sizeof(kaheis); ++i) {// 貨幣単位を順番に繰り返し調査.
int val = kaheis[i];// 今回調査する貨幣単位を参照.
int cnt = money / val;// 調査対象の貨幣単位がいくつあるか求める.
money = money % val;// 次の調査のために調査対象を今回の残りに更新.
printf("%d円 : %d枚\n", val, cnt);// 結果を表示する.
}
}

投稿2016/02/25 07:44

HiroshiWatanabe

総合スコア2160

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

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

kutsulog

2016/02/25 07:58 編集

intは4バイト(または8バイト)なので for(int i = 0; i < sizeof(kaheis); ++i)だと 9*4(または8)回ループが回ってしまいます やるならintのサイズで割る必要があります for(int i = 0; i < sizeof(kaheis) / sizeof(int); ++i)
HiroshiWatanabe

2016/02/25 10:07

あ、そうですね。うっかりしてました。失礼しました。
退会済みユーザー

退会済みユーザー

2016/02/25 11:11

ご回答ありがとうございます。 sizeofでサイズをみていく方法もできるんですね! 勉強になります! ありがとうございました!!
guest

0

こんにちは。

間違い探しとしては、前回hirohiroさんが指摘されてたscanf()で不正入力(例えばアルファベット)された時の対処が抜けているくらいしか見つかりませんでした。

ところで、2~3個くらいならループしない方が良いとは思いますが、これくらい回すならループした方が面倒がなくて良いですね。

後、私も最近知ったのですが、std:divという関数があります。商と余を同時に計算してくれます。
なお、負の数でも使うようなケースでは、定義に要注意です。-5を3で割った余りっていくつでしょ? たぶん数学的には四捨五入同様未定義だろうと思います。C言語的にも確か未定義だったような、標準ライブラリとしては定義されているかも知れません。

投稿2016/02/25 06:15

Chironian

総合スコア23272

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

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

cateye

2016/02/25 10:57

>-5を3で割った余りっていくつでしょ? ちょっと気になったのでやってみました。コンパイラはclang version 3.7.1です。 ~/test/ctst >cat tst07.c #include <stdio.h> int main() { printf("%d %d\n", -5/3, -5%3 ); return 0; } ~/test/ctst >./a.out -1 -2 ~/test/ctst >
退会済みユーザー

退会済みユーザー

2016/02/25 11:03

ご回答ありがとうございます。 scanfの件記事読みました! scanfでなく、業務では、fget+sscanf関数をメインに使われているとのことでしたが。 こちらでも浮動小数点数などに対してはエラーチェックができないと記載されていたので、正直どちらがいいのだろって感じではありました。 不正入力のところも含めて修正していきたいと思います。 ちなみにですが、 >後、私も最近知ったのですが、std:divという関数があります。 このような情報はどちらで入手されるんですか? やはりcommpassなどの勉強会や、リファレンスで情報を知るという感じでしょうか。
Chironian

2016/02/25 12:43

> こちらでも浮動小数点数などに対してはエラーチェックができない あれ? そうでしたっけ。sscanf()の戻り値も読み取れた項目数なので、それをチェックすれは良いような気がしてます。 ところで、C言語を極めるならこの辺も極める必要がありますが、もし、C++へ進化される予定があるな、極めない方が却って良いかも知れません。C++へ進む時はC言語の癖を余り付けない方がスムーズなので。 > このような情報はどちらで入手されるんですか? std::divは確かここで知ったと思います。どなたかが質問されてたような記憶があります。 オープン・ソース系のライブラリを使う時も多いです。結構ソースを読む必要があるのでその中で知らない関数が出てくるとかよく有ります。それをググって調べてます。大抵誰かが解説してくれています。本当にありがたいです。
yumetodo

2016/02/25 15:49

C言語においてscanf系関数を数値入力に使うのはどう転んでもダメです。なぜならオーバーフローやアンダーフローが発生しても検知することができないからです。 で、これに真面目に対処するためには http://qiita.com/yumetodo/items/238751b879c09b56234b こういう関数を作って上げる必要があります。C言語において、標準入出力は初心者がもっとも使いたいにもかかわらず、C言語への深い深い理解が求められるラスボスなので、要注意です。
退会済みユーザー

退会済みユーザー

2016/02/26 05:24

Chironianさん ご回答ありがとうございます。 >あれ? そうでしたっけ。sscanf()の戻り値も読み取れた項目数なので、それをチェッ>クすれは良いような気がしてます。 すいません、改めて確認してみます!! >ところで、C言語を極めるならこの辺も極める必要がありますが、もし、C++へ進化さ>れる予定があるな、極めない方が却って良いかも知れません。C++へ進む時はC言語の>癖を余り付けない方がスムーズなので。 そうですね・・ 実際にC言語とC++のお仕事どちらが多いかによりそうです。。 私が聞いた限りでは、C言語(C++のことも言っているのかもしれませんが・・)の お仕事が多いとのことでしたので、引き続き勉強していきたいと考えています。 >std::divは確かここで知ったと思います。 そうなんですね! 他の方の質問等も見て勉強していきたいと思います。 ありがとうございました!!
退会済みユーザー

退会済みユーザー

2016/02/26 05:27

yumetodoさん ご回答ありがとうございます。 >C言語において、標準入出力は初心者がもっとも使いたいにもかかわらず、 >C言語への深い深い理解が求められるラスボスなので、要注意です。 そうですね・・・ 気軽に使っていたのですが、皆さんからご指摘を頂いていると ホントラスボスだと感じました。。 fget+sscanfの勉強もしようと思うのですが、 今回の課題もfget+sscanfで作成したほうがよろしいでしょうか。 ただ、fget+sscanfに関しては、習っていません。。
yumetodo

2016/02/28 15:20

>fget+sscanfに関しては、習っていません。。 もしC言語を使うのに習った、習っていないなどという概念を持ち出すなら、直ちにそんな概念はゴミ箱に捨てるべきです。 C言語の標準入出力は十分な理解なしに使うと深刻なセキュリティリスクをもたらします。習っていない、では済まされないのです。 にも関わらず、安易にscanfやprintfといった危険な関数を使うようすすめたり、gets関数のように絶対に安全に使えずC99で非推奨、C11で廃止された物を未だに使えというような初心者向け教本、授業が後を立ちません。 繰り返しますが、Cの標準入出力はラスボスです。関数callがアセンブリレベルでどうなっているか、一般的にC処理系実装に用いられるstackとはなにか、ヒープとは何か、なぜ可変長引数は実現できるのか、ポインタとはetcをすべて、とは言いませんがある程度理解していることが求められます。なぜならば、C言語とは、プログラマは全知全能である、という前提のもとに設計された言語だからです。 とりあえず標準入出力を使いたいということだったら、他言語を強くおすすめします。 もちろん、授業なので制約がかけられた時はやむを得ないですが。 伝わっていると思いますが、念のため。数値入力にscanf系関数を用いてはいけません。 fget+sscanfでも問題は一つも解決しません。fget+sscanfが有用なのは、定形formatで文字列をsplitする時です 単に文字列を取得したい場合はgets_s(C11で追加)もしくはfgets+strchrを利用しましょう
yumetodo

2016/02/28 15:23

ちなみになんでCの標準入出力がラスボスなのかというと、文字列操作がラスボスだからです。 もう二度とCで文字列操作のコードを書きたくないです、私はC++11を使います。
Chironian

2016/02/28 17:04

tomo3さん。 ああ、今気が付きました。ごめんなさい。 > 実際にC言語とC++のお仕事どちらが多いかによりそうです。。 今ならもうC++の方が多いかもしれません。大きくて高速なアプリを高速性が必要だからと言ってC言語で開発するのはある意味ナンセンスです。生産性は確実にC++の方が高く速度も大差ないですから。そのようなアプリはプログラマも多数必要になります。 yumetodoさんも言ってますが、C言語での文字列処理はある意味悪夢です。 生産性が低いので、極めても使える局面は多くはないだろうと思います。 ところで、C言語自身はC++のサブセットですのでC言語自身に注力するのはためになると思いますよ。でも、C言語の標準ライブラリとC++の標準ライブラリは全く別物ですので要注意です。
guest

0

間違ってはいないですがループを使った方がすっきりかけると思います

C

1int main() 2{ 3 char input; 4 int yen = 0; 5 int index = 0; 6 int kahei[] = {10000, 5000, 1000, 500, 100, 50, 10, 5, 1} 7 printf("金額を入力してください。") 8 // scanf("%d", &yen); 9 // こっちの方が安全 10 while((input = getchar()) != '\n') 11 { 12 if(input < '0' || '9' < input) 13 { 14 yen = -1; 15 break; 16 } 17 yen = yen * 10 + input; 18 } 19 20 if(yen < 0) 21 { 22 printf("整数で再度入力してください"); 23 return 0; 24 } 25 26 do 27 { 28 if(kahei[index] >= 1000) 29 { 30 printf("%d円札は%d枚です\n", kahei[index], yen / kahei[index]); 31 }else{ 32 printf("%d円玉は%d枚です\n", kahei[index], yen / kahei[index]); 33 } 34 yen = yen % kahei[index]; 35 index++; 36 }while(kahei[index] > 1); 37} 38

あと0円は金額といえば金額ですが再入力の対象になっていますね

投稿2016/02/25 02:42

編集2016/02/25 02:55
kutsulog

総合スコア985

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

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

退会済みユーザー

退会済みユーザー

2016/02/25 10:57

ご回答ありがとうございます。 確かに皆さんからご指摘頂いている通り、この量であれば ループで書いたほうが良いという点がわかりました。 記載頂いたものを参考にさせていただきながら 自身でも作ってみたいと思います。 ありがとうございました!!
guest

0

今度は逆です。ループを使います。
const int kaheis[] = { 10000, 5000, 2000, 1000, 500, 100, 50, 10, 5, -1 };

int index = 0;
while (kaheis[index] != -1) {
int ans = inputData / kaheis[index];
inputData = inputData % kaheis[index];
index++;
printf(.....);
}
printf( inputData は 10で割った余りが入ってるのでそのまま表示 );
こんなイメージでしょうか。

玉と札ですが、 500 より大きいか、以下かで判定か。

5円忘れた、、、

誤字訂正、5円追加、

投稿2016/02/25 02:25

編集2016/02/25 02:27
ipadcaron

総合スコア1693

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

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

kutsulog

2016/02/25 02:45

-1の前に1を入れないと ループの中で1円を処理してくれないですよ?
ipadcaron

2016/02/25 04:52 編集

最後の printfが1なんですよ。 ってーよく見ると、0でも print するね、、、べつに正解を載せてるんじゃなくて、考え方なんで全部コピペしたけど動きません、じゃないスレッドだと思っています。過去の経緯からして。
kutsulog

2016/02/25 04:55

あぁ、そういうことですね それでも-1の前に1を書いた方が ループの外のprintfがいらなくなるのですっきりすると思います
ipadcaron

2016/02/25 05:11

stringbuilder とかでループ外で、再構築するようなロジックをよく組むのでそういうが出ちゃったのかもしれません。指摘されて見直すとありゃ?言う通りだ、と思います。 このやり取りが、質問者とできると彼は確実にグレードアップしてる証跡になりますよね。 ↓の模範解答を載せるのもそれはそれで正解です。この質問は学校の課題であり、質問者は、完全コピペ回答しか求めてない場合もありますから。無視すれば良いですが無視とかそういうことではなくて、質問には答える姿勢です。この質問者は、過去ログで、勉強したい、っていう決意表明してます。
退会済みユーザー

退会済みユーザー

2016/02/25 07:33

ご指摘ありがとうございます。 また皆様のやりとりとても勉強になります。 正直理解が追いついていないので、 取り急ぎいただいた内容を整理整頓してみたいと思います。 すいませんが、わからないところが出たらご相談させてください!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問