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

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

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

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

Q&A

解決済

4回答

2173閲覧

教えてください

退会済みユーザー

退会済みユーザー

総合スコア0

C

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

0グッド

0クリップ

投稿2015/11/06 10:44

編集2015/11/07 23:41
#include <stdio.h> int main(void){ double a, b, ans; char o; //演算子 int x; //繰り返すかどうか char line[1000]; do{ printf("電卓です。\n数字を入力してください。\n"); fgets(line,sizeof line,stdin); sscanf_s(line,%lf,&a); printf("演算子を入力してください。\n"); fgets(line,sizeof line,stdin); sscanf_s(line,%c,&o,1); printf("数字を入力してください\n"); fgets(line,sizeof line,stdin); sscanf_s(line,lf,&b); switch (o) { case '+': printf("%lf+%lfの値は%lfです", a, b, a + b); break; case '-': printf("%lf-%lfの値は%lfです", a, b, a - b); break; case '*': printf("%lf×%lfの値は%lfです", a, b, a*b); break; case '/': if (a == 0 || b == 0){ printf("0で除算はできません。\n"); break; } else{ printf("%lf÷%lfの値は%lfです", a, b, a / b); break; } default: printf("演算子は+か-か*か/のみ対応しています。"); break; } printf("\n続けますか?Yesなら偶数、Noなら奇数を入力してください。\n"); scanf_s("%d", &x); } while (x % 2 == 0); return 0; }

これで実行すると、まず演算子を入力できません。scanf_sが飛ばされ二つ目のprintfが出力されます。scanf_sを使って文字を入力してもらうには、この書き方じゃないのですか?
そのため、0で除算云々の所にバグがあるかどうかも調べれません。
また、3つ目のscanf_sのところで何を入力しようとwhile defaultが実行されます。
最後に、「続けますか?」のところで、数字を入力すれば正しく動作するのですが、文字を入力すると、入力した文字数分ループします。

この場合、どのように記述するとよいですか?

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

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

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

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

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

guest

回答4

0

ふと思ったのですが、scanf_s系を使うのであれば、数値と演算子を別々に入力する必要はないですよね。まとめて入力させてしまいましょう。

otnさんのご指摘のように、1行分をまとめて読み取ってから読み取った文字列に対してsscanf系を使うと変な挙動にならずにすみます。

char buffer[1000]; fgets(buffer, 1000, stdin); int count = sscanf_s(buffer, "%lf %c %lf", &a, &o, 1, &b); // countが3でなければ入力ミスと判定

という具合にすれば、「12.3+45.6」と入力すれば、aには12.3、oには'+'、bには45.6がそれぞれ入ります。

投稿2015/11/06 13:06

catsforepaw

総合スコア5938

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

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

catsforepaw

2015/11/06 13:19

もう一つアイディアを伝授。 > fgets(buffer, 1000, stdin); この次に if(strcmp(buffer, "end\n") == 0) break; のような感じにすると、計算式を入力するところで"end"を入力すると終了するといったことができるようになります。 ※strcmp関数を使う際は「#include <string.h>」が必要です。
退会済みユーザー

退会済みユーザー

2015/11/07 23:50

#include<string.h>は #include<stdio.h> #include<string.h> という風につなげて書いてもいいのですか?
catsforepaw

2015/11/08 00:54

> #include<stdio.h> > #include<string.h> > という風につなげて書いてもいいのですか? はい。そのように必要なインクルードをどんどん並べていきます。
guest

0

ベストアンサー

まず、double型変数へのscanf書式は、"%lf" です。関数の機能はちゃんと調べてから使いましょう。

scanf_sを使って文字を入力してもらうには、この書き方じゃないのですか?

やはり、scanf_sは初心者には難しいですよね。先の質問の回答にも書きましたが、scanf_sを使うのをやめましょう。

scanf_s(~,~) を、すべて、
fgets(line,sizeof line,stdin); sscanf_s(line,~,~); に書き換えてください。
lineは、あらかじめ char line[1000]; などと宣言。

そのうえで、sscanf_sの戻り値が1であるのか(入力変数の個数が1個なので)確認して、0ならエラー処理が必要です。

if (a || b == 0)

これは、「aが0でないか、または、bが0である」という意味になりますが、たぶん意図と違いますよね?

投稿2015/11/06 11:03

otn

総合スコア84538

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

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

退会済みユーザー

退会済みユーザー

2015/11/07 23:42

2つ目の質問にも答えていただきありがとうございます。 scanfを変更したのですが、あってるでしょうか? if文も編集しました。こっちは恐らくあってると思います。
guest

0

scanf系やprintf系の書式指定は初心者にはなかなか難しいかもしれませんね。
(特にscanf系は苦労して覚えてもセキュリティの関係で実務で使うことなどまずありませんし……)
どうしてもC言語でなければ困るというのでなければ、C#をお勧めしたいところではあります。

scanf_s("%c", &o);

引数が足りませんね。リファレンスを確認してみましたが、

scanf_s("%c", &o, 1);

1文字入力ということを明示しないといけないようです。

printf("%d+%dの値は%dです", a, b, a + b);

"%d"はint型用なので、double型を表示する際は、

printf("%1.15g+%1.15gの値は%1.15gです", a, b, a + b);

という具合にします。

投稿2015/11/06 12:33

catsforepaw

総合スコア5938

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

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

退会済みユーザー

退会済みユーザー

2015/11/07 23:48

scanfの方では%lfを使ったのですが、%1.15gと何か違うのでしょうか?
catsforepaw

2015/11/08 01:33

scanfの方は入力用でprintfの方は出力用です。つまり目的が違います。 浮動小数点の扱いはC言語ではちょっと混沌としていて、doubleはscanfでは"%lf"ですが、printfでは"%f"です。 ちょっと難しい話になってしまいますが、浮動小数点にはfloat,double,long doubleの3種類があって、入力(scanf)ではどの変数なのかを明確にしなければなりません。それぞれ%f,%lf,%Lfとなります。 出力(printf)では少し違っていて、引数にfloatを渡しても内部的にはdoubleに変換して処理されるので、floatとdoubleの区別がありません。なので、どちらも%fです。そしてlong doubleを出力するときは%lfです。このようにscanfとprintfの書式は似て非なるものなので注意しましょう。 ちなみに、VC++ではdoubleとlong doubleは両方とも64bitなのでprintfでdoubleを%lfで出力しても問題なくできたりしますが、間違いなので気をつけましょう。 さて、%1.15gですが、浮動小数点を出力するときの%fに代わるもう一つのやり方です。 %fでは小数点以下の桁数が固定で、12.3を出力すると12.300000のように出力されますが、余計な0はいらないというときには%gを使います。%1.15gは、1桁以上で表示し、有効桁数は15桁という意味になります。
guest

0

aとbへの入力は、otnさんご指摘の通り、scanf_s("%lf", &a);のようにしないと適切に読み取れません。(変な値が入ります。)

演算子が入力できない問題ですが、%cは文字入力ですので、1文字読み出されます。
どの文字が読み出されるかと言うと、最初のscanf_s("%d", &a);で読み取った数字の直後の文字です。
恐らく数値を入れた後Enterキーを押していると思いますので、そのEnter文字('\n')が読み出されてしまいます。
取り敢えず、scanf_s()の%dを%lfへ修正後、例えば、5+6 Enterのように入力すれば読み出せる筈です。

なお、このままでは、printfのプロンプトが間抜けな位置に出てしまいます。
この辺をきちんとするなら、otnさんのご指摘通りfgets()とsscanf_s()を使うとうまくいくと思いますよ。

投稿2015/11/06 12:08

Chironian

総合スコア23272

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

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

退会済みユーザー

退会済みユーザー

2015/11/07 23:46

otnさんの通り変更したのですが、これでよろしかったでしょうか? Enterが文字として認識されてたことを正直今まで知りませんでした。ありがとうございます。
Chironian

2015/11/08 01:08

修正されたソースを見ましたが、問題がまだ残っているようです。 ①まず、これを初めて見た方が混乱しますので、投稿全体としておかしくならないようにしましょう。 現在のソースでは、「これで実行すると、まず演算子を入力できません。」とは異なる筈です。 最初の投稿を残して、追記する方がよい場合が多いですよ。 ②コンパイルできたものを投稿しましょう。 sscanf_s()のformatパラメータの与え方が間違ってますね。 ③otnさんのアドバイスにありますが、sscanf_s()の戻り値を確認するようにしましょう。 sscanf_s()はint型を戻しますので、例えば int ret; ret=sscanf_s(略); で戻り値を受け取れます。この戻されたretの値が適切か確認しましょう。 どのような値がもどされるか、リファレンスに記載されています。 お使いのVisusal Studioのバージョンが分かりませんが、2015なら下記に記載されてます。 https://msdn.microsoft.com/ja-jp/library/t6z7bya3.aspx ここには他のバージョンへのリンクもあるので、適切なバージョンのものを確認下さい。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問