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

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

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

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Q&A

解決済

3回答

8105閲覧

C言語 -if文がうまく動かない

kamiokabegami

総合スコア13

C

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

0グッド

0クリップ

投稿2018/03/29 04:18

編集2018/03/29 04:42

前提・実現したいこと

プログラミング&テラテイル初心者です。C言語で簡単な物理の方程式を解くプログラムを作ろうとしています。開発にはVisual Studio 2017を使っています。

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

エラーは出ませんでした。
Borland BCC32やOnlineGDBでは問題なく作動、Visual studioでも一応コンパイルはできます。ただしVisual Studioでコンパイルさせた時だけうまく動きません。
具体的には「プログラムの続行を問う」ところで、if文がうまく動かないようです…

該当のソースコード

C言語

1void VelocityCalc() { 2 do { 3 4 //以下、演算パートです 5 printf("\n\nWhat is initial velocity[u]?: "); 6 scanf("%lf", &u); 7 8 printf("\n\nWhat is acceleration[a]?: "); 9 scanf_s("%lf", &a); 10 11 printf("\n\nWhat is time[t]?: "); 12 scanf_s("%lf", &t); 13 14 v = u + a * t; 15 16 //演算結果と続行の是非を問います。このあたりからうまく動きません。 17 printf("\n\nResult: v = %f\n\nDo you want to calculate another velocity?[Y/N]", v); 18 scanf_s("%s", &con); //続行の是非をYかNで入力します。conはchar型のグローバル変数です。 19 20 //yが入力されたとき、constatに1を代入してdo-whileを継続します。 21 if (con=='y') { 22 printf("\n\nSTH"); //if文が動作しているか確認のためにprintfを置きました 23 constat = 1; 24 } 25 26 //nが入力されたとき、constatに0を代入してdo-whileを抜け出します。 27 if (con=='n') { 28 constat = 0; 29 } 30 } while (constat); //constatの真偽値でdo-whileの動作を決定します。 31 32 NewtonLauncher(); //メニュー画面を表示する関数に飛びます。この関数自体はちゃんと動きます... 33}

試したこと

Visual Studioにあまり慣れていないので、ほかのコンパイラも試しましてみました。
そちらの方ではscanf_sが使えないような感じなので、すべてscanfに戻してからコンパイルしました。

補足情報(FW/ツールのバージョンなど)

Visual Studio Community 2017
全体のコードはこちらです...
https://www.onlinegdb.com/online_c_compiler

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

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

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

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

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

guest

回答3

0

scanf_s("%s", &con);

ここで受け取りに使用しているconの型が不明です。

char con; の場合
%cで受け取ってください。
scanf_s("%c", &con);

char con[数字]; の場合
値の比較を次のようにしてください。
if (con=='y') {

if (con[0]=='y') {

投稿2018/03/29 04:31

ttyp03

総合スコア16996

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

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

kamiokabegami

2018/03/29 04:40

回答ありがとうございます。 質問が不明瞭で申し訳ありません... conはグローバル変数で宣言しました。単なるchar型です。
ttyp03

2018/03/29 04:42

であるなら、scanfの書式を%cにするだけでよさそうですね。
kamiokabegami

2018/03/29 04:45

%cに書き換えたのですが、今度はY/Nクエスチョンをすっ飛ばしてしまいます... <実行結果> Result: v = 2.000000 Do you want to calculate another velocity?[Y/N]: <-入力待ちしてくれません What do you need? [1]Velocity, v [2]Length(Height), s [3]Acceleration, a [4]Time, t [0]Back to the main page
ttyp03

2018/03/29 04:59

理由はLouiS0616さんが解説してくださっています。 要は直前のscanfで入力した際の改行コードが残っているのが原因です。 対策としては下記のいずれかでしょうか。 ①scanf直前にバッファをクリアする(LouiS0616さんの方法) ②文字で受け取らず、文字列で受け取る ③scanfを使わない(fgetsなどを使う)
kamiokabegami

2018/03/29 07:17

ありがとうございます! バッファクリアの位置を変えたら作動するようになりました... ちなみにfgetsなどを使う際はやはりscanf_sなどとの混用はできないのでしょうか?
ttyp03

2018/03/29 07:19

いえ、混用は可能です。
guest

0

1.con変数の定義がない(グローバル変数?)
2.scanfの%sで取得できるのは文字列です。入力間違えたら、最悪暴走します

競技プログラミングとかのとにかく動けばいい、という場合はscanfのところで%c を指定しとけばいいですが、実用的なプログラムを組むというなら、fgets などで文字列を受け取るようにして、文字列の先頭文字を判定する、あるいは文字列自体を判定するようにするほうがよろしいかと思われます
scanfは使用禁止、とおもっておきましょう

投稿2018/03/29 04:30

y_waiwai

総合スコア87719

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

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

kamiokabegami

2018/03/29 04:39

回答ありがとうございます。 すみません、con変数はグローバル変数でchar型で宣言しています。 指定子を%cに書き換えたところプログラムは停止することなく動いたのですが、Y/Nクエスチョンがすっ飛ばされて選択ができなくなってしまいました。 fgetsやgetcharなどの使用も考えたのですが、double型での使い方などがイマイチわかっておらず結局scanf型で書いています...(Visual Studioではエラーが出るのでscanf_sに書き換えていますが)
y_waiwai

2018/03/29 04:50

VisualStudioを使ってるなら、scanfの後ろにブレークポイントを設定して、デバッグモードで実行すればそこで止まって各変数の値を参照できます。 そこからワンステップづつ実行して動作を見ることが出来ますんでやってみてください
kamiokabegami

2018/03/29 06:47

ありがとうございます。 scanfの前後にブレークポイントを設置したところ、やはりバッファに\nが残っていました… これがプログラム停止の要因のようですね... ところでfgetsやgetcharなども試したのですが、なぜか入力待機になりません...
y_waiwai

2018/03/29 06:50

>ところでfgetsやgetcharなども試したのですが、なぜか入力待機になりません... それは使い方が間違ってます それぞれ関数の引数など変わってきますんで、ぐぐるなどしてどう使えばいいのか調べてみましょう
kamiokabegami

2018/03/29 07:02

con = getchar(); これで正しいでしょうか? conをchar型で宣言した場合やはりすっ飛ばされてしまい、int型で宣言してみてもダメでした。
kamiokabegami

2018/03/29 07:19

ありがとうございます。 原因はバッファだったようです。 ちなみに上記のようにfgetsとgetcharを使ってもダメだったのですが、scanf系との混用は基本的にできないということでしょうか?
y_waiwai

2018/03/29 07:22

まあ、いろいろやってみればいいかとw
guest

0

ベストアンサー

文字列ではなく文字を読み取りたい場合は、%sではなく%cで受け取ってください。
逆に文字列として扱いたい場合は、"y"とstrcmpで比較してください。

投稿2018/03/29 04:21

LouiS0616

総合スコア35658

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

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

kamiokabegami

2018/03/29 04:34

回答ありがとうございます。 ご指摘の通り"%s"を"%c"に変えたのですが、続行の是非のところでY/Nクエスチョンがすっ飛ばされてしまいます... 同様の処理をほかの場所でも使用しているので変更があまりないに越したことはないのですが、scanf_s以外の関数を使うことを検討した方がいいでしょうか...? 【補足】 conはグローバル変数のchar型で宣言しています。これが何か関係しているのでしょうか...?
LouiS0616

2018/03/29 04:42 編集

おそらく直前の入力の改行文字が悪さをしています。 while(getchar() != '\n'); と文字を読みとる前に回収しておくのが良く見る回避法です。
kamiokabegami

2018/03/29 04:46

printf("\n\nResult: v = %f\n\nDo you want to calculate another velocity?[Y/N]: ", v); この部分の\nでしょうか?
LouiS0616

2018/03/29 04:51

いえ、標準入力のバッファの改行文字です。 値を入力してエンターを打鍵すると、例えば『3.14\n』がバッファに格納され、浮動小数が読み込まれた結果『\n』がバッファに残ります。 この状態で新たに『文字(char)』を読み取ってしまうと\nが引っ張りこまれてしまうのです。 while(getchar() != '\n'); は、入力を空読みしてバッファを掃除させるために使えます。
kamiokabegami

2018/03/29 06:49

ありがとうございます。 デバッグで見てみたらおっしゃる通りバッファに\nがたまっていたようです。 ところでバッファクリア(getcharのから読みだけでなくfflushも)やfgets/getcharなども試したのですが、なぜかY/Nの入力待ちになりません…
LouiS0616

2018/03/29 06:53 編集

入力部分だけに限って順序を書くならば、これで上手くいきませんか? a読み込み; t読み込み; u読み込み; バッファクリア; 文字読み込み;
LouiS0616

2018/03/29 06:56 編集

ところで、fflushで標準入力のバッファをクリアするのはやめといた方が良いです。 http://www.kijineko.co.jp/tech/superstitions/fflush-with-input-stream.html リンク先はちょっと厳密で難しいですが、要するに『出来るかもしれないけど、もし出来たとしても処理系依存だからやめとけ』って書いてあります。
kamiokabegami

2018/03/29 07:11

バッファクリアの位置をおっしゃるとおりの位置に移動させたところ、うまくいきました! ちなみにbcc32やほかのコンパイラで動いたのはまぐれだったのでしょうか...?
LouiS0616

2018/03/29 07:20 編集

当初のコードだと%sで文字を受け取ろうとしているのがそもそもまずいので、上手く動作するコンパイラがあっても『たまたま』だと捉えて良いと思います。 (規格上どのような扱いになるかは、私はちょっとわかりません。ごめんなさい。もしとても気になるのであれば、もっとミニマムに状況を再現するコードを書いたあとで、新たに質問を立てると良いかもしれません。) あるいは%cに置き換えてからも、VSコンパイラと他のコンパイラで挙動が異なったのでしょうか?
kamiokabegami

2018/03/29 07:24

%cに置き換えると同様に件のY/Nがスキップされていました。 ちなみにバッファクリアが必要なタイミングというのはどのような時なのでしょうか?
LouiS0616

2018/03/29 07:31

典型的にはやはり文字の入力を受け付ける場合ですね。 改行文字も文字の一種なので、それを無視するかどうかはコーダが指定する必要がありますから。
asm

2018/03/29 07:45

> ちなみにbcc32やほかのコンパイラで動いたのはまぐれだったのでしょうか...? まぐれではないが実は書き込んではいけないとこに書き込んでいるバグが発生しています。
LouiS0616

2018/03/29 08:23

あ、&con + 1 にヌル文字を書き込みに行って未定義動作を踏む感じでしょうか。
asm

2018/03/29 08:42

ええ、%sですから終端書き込みに行っちゃいますね
kamiokabegami

2018/03/29 09:15

質問ばかりで申し訳ありません。 double型の格納には現在すべてscanf_sを使っているのですが、fgetsやgetcharで代用できますか...? 他にもっとdoubleと相性がよく、使い勝手のいい関数があれば教えていただけますでしょうか。
LouiS0616

2018/03/29 09:26

やるなら fgets + strtod ですね。 ただC言語の標準入力は真面目に考えだすとドツボにハマるので、常用する分にはscanfで良いんじゃないかと個人的には思います。
kamiokabegami

2018/03/29 09:46

ご丁寧にありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問