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

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

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

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

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

Q&A

解決済

3回答

1370閲覧

scanfの入力が書式と異なっていても動作を続行させたい[C言語]

退会済みユーザー

退会済みユーザー

総合スコア0

C

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

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

0グッド

0クリップ

投稿2021/10/29 14:33

c言語におけるscanfでの入力についての質問です。

異なった図形(三角、四角、長方形)の面積を比較するコードを書いているのですが、三角形以外のものだとscanfでクラッシュしてしまいます。(例えば、"T 3 3 3" と入力すれば大丈夫だが、"S 4.5"や"R 6 8" と入力すると動作が止まる)これを解決するためにはどうすればよいでしょうか?scanfの書式途中まで(&aや&bまで)しか入力していなくても動作を続行させる方法はあるのでしょうか?

C言語

1#include <stdio.h> 2 3int main (void) 4{ 5 double a, b, c, tris, area; //a, b, cは各辺の長さ 6 char shape; //shapeは図形のこと。T = 三角形、S = 四角形、R = 長方形 としている 7 8 printf("Shape #1\n"); 9 m1 = scanf("%c %lf %lf %lf", &shape, &a, &b, &c); 10 11 fflush(stdin); 12 13 printf("Shape #2\n"); 14 m2 = scanf("%c %lf %lf %lf", &shape, &a, &b, &c); 15 16  if (shape == 'S'){ 17 area = a * a; 18 return 0; 19 } 20 21 else if (shape == 'T'){ 22 tris = a + b + c / 2; 23 area = sqrt(tris * (tris - a) * (tris - b) * (tris - c)); 24 return 0; 25 } 26.......コード以下省略....................................

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

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

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

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

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

guest

回答3

0

ベストアンサー

まず、fgets ( あるいは getline ) で行を丸ごと取得する話は、別の方が提示されてますので割愛します。
ここでは scanf の基本的な使い方だけでの対処について説明します。

で、質問には入ってないですが、先に以下の箇所について。

fflush(stdin);

これおそらく、行になにか余分なデータが残っていても捨てて次の行を読みに行こう、という意図で入れられてるものと思いますが、fflush にそういう機能はありません。間違った使い方です。
※fflush は書き込みデータをファイル等に吐き出させるための関数なので

(改行含め)行の余分なデータを捨てたいということなら、以下による「読み捨て」を行います。

ungetc(' ',stdin); scanf("%*[^\n]%*c");

ちょっと ungetc の併用がカッコ悪い感じもしますが、そこはご容赦ください。

scanfの書式で、% の次にある * は「変数に保存しないで読み捨てる」ことを意味します。
そして、%[文字種] の書式は「指定の文字種1文字以上」を表します。^を先頭につけると「該当しないもの」と指定が反転しますので、%*[^\n] だと * も併せると「改行以外全てが続く限り読み捨てる」で、次の %*c では(必ず来ることになる)改行が読み捨てられます。

で、本題に戻りまして、「改行があった時点で数値の数が足りなくてもscanfを打ち切りたい」ということになるかと思いますので、「空白・改行等を読み捨てる」意味を持つ「空白文字」の代わりに、上で出てきた %[文字種] をここでも活用して、数値と数値の間を %*[ ] にする、つまり「改行は数値の区切りじゃないよ、区切りは空白だよ」と明示する方法が使えます。

具体的には、以下のような指定になります。

m1 = scanf("%c %lf%*[ ]%lf%*[ ]%lf", &shape, &a, &b, &c);

もし数値が3つ出てくる前に改行が来れば、指定の書式に合わなくなるので、途中で打ち切り、ということになります。
読み切りが途中で打ち切られたかどうかについては、scanf の返り値 m1 の値 ( 変数に保存された要素数 ) で判断してください。

ということで、fflush部分の置き換え、scanfの置き換えの2か所での対応、となります。

投稿2021/10/29 18:23

angel_p_57

総合スコア1672

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

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

退会済みユーザー

退会済みユーザー

2021/10/30 20:28

詳細な説明ありがとうございます。 本当に助かります、、
thkana

2021/10/31 06:26

ちょっといじっていて気がついたのですが、 m1 = scanf("%c %lf%*[ ]%lf%*[ ]%lf", &shape, &a, &b, &c); だと、例えば T[空白]1[空白][Enter] という入力を与えると%*[ ]がマッチして%lfで入力待ちに入ってしまいますね。 それを良しとするかどうかはプログラムに対する要求次第ですが。 (こういうのって、真面目に突き詰めるととても大変なことになりがち)
angel_p_57

2021/10/31 07:39

なるほど。確かにそのパターンはちょっと困りますね。 明確に「行単位」で処理するなら、やはり fgets や getline からの sscanf, atof 等の方が簡明ではあると思います。
guest

0

tris = a + b + c / 2;tris = (a + b + c) / 2; の間違いですよね。

次のコードが理解できますか?

C

1#include <stdio.h> // printf, fgets, sscanf, puts 2#include <math.h> // sqrt 3 4int main(void) 5{ 6 double a, b, c, d, tris, area; 7 char s[256]; 8 9 for (int i = 1; ; i++) { 10 printf("Shape #%d> ", i); 11 if (!fgets(s, sizeof s, stdin)) break; 12 if (sscanf(s, " S%lf%lf", &a, &b) == 1) { 13 area = a * a; 14 printf("area = %g\n", area); 15 } 16 else if (sscanf(s, " T%lf%lf%lf%lf", &a, &b, &c, &d) == 3) { 17 tris = (a + b + c) / 2; 18 area = sqrt(tris * (tris - a) * (tris - b) * (tris - c)); 19 printf("area = %g\n", area); 20 } 21 else if (sscanf(s, " R%lf%lf%lf", &a, &b, &c) == 2) { 22 area = a * b; 23 printf("area = %g\n", area); 24 } 25 else puts("error"); 26 } 27}

投稿2021/10/30 01:37

kazuma-s

総合スコア8224

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

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

退会済みユーザー

退会済みユーザー

2021/10/30 20:27

回答ありがとうございます。 コード自体は何となくは読めるのですが、まだまだ勉強不足なので、細かいところは分かってないです。
guest

0

「scanfでクラッシュ」、していないんです、実は。改行を入力した後、続けて数値を入力してみてください。実は、入力待ちをしているだけなんです。
回避方法はいくつかありますが、1つは、1行全体を文字列として読み込んでから、sscanf関数で解析する、というものがあります。

投稿2021/10/29 14:40

majiponi

総合スコア1720

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

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

退会済みユーザー

退会済みユーザー

2021/10/29 16:42

回答ありがとうございます。 fgets()とatof()を使うことで入力の際の問題は解決することができました。 ただそのあとの条件分岐(もしshape == 'T'だったら、その計算をする)のプログラムが動作しません。 fgets()とatof()後に条件分岐へと持っていくにはどうすればよいのでしょうか、、、
jbpb0

2021/10/30 01:36 編集

質問者さん > そのあとの条件分岐… は、この質問とは別内容だし、既に別の質問としてしてるのだから、この質問は解決済にしましょう
退会済みユーザー

退会済みユーザー

2021/10/30 20:27

ご指摘ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問