• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:C言語 sscanf関数で変換に失敗した場合)

C言語のsscanf関数で変換に失敗した場合について

このQ&Aのポイント
  • C言語のsscanf関数を使用して変換に失敗した場合について質問です。
  • 入力された整数の2乗を返すプログラムで、sscanf関数が変換エラーの場合の扱いについて疑問があります。
  • 変換エラーがどのようなものか理解できず、エラーが発生すると再入力を促されることもあります。

質問者が選んだベストアンサー

  • ベストアンサー
  • wormhole
  • ベストアンサー率28% (1626/5665)
回答No.2

>変換エラーというのは、入力された値とsscanf関数で指定した書式が異なる場合は含まないのでしょうか。 含みません。 Linuxでの例になりますが http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/scanf.3.html のエラーの欄に書いてあるようなものです。

jet888
質問者

補足

回答ありがとうございます。 上記のサイトの返り値のところで、 「最初に一致の失敗があった場合には 0 になることもある。 最初の変換が成功する前に入力の最後に達して、一致の失敗が起こった場合には、 EOF が返される。」 とあります。 今回の場合は、最初に一致の失敗となるため返り値が「0」になるということだと思いますが、 「最初の変換が成功する前に入力の最後に達して」という部分との違いがよくわかりません。 入力した値はすでにlinebuf変数に格納されているため、 入力の最後に達しているということにはならないのでしょうか。

その他の回答 (11)

  • wormhole
  • ベストアンサー率28% (1626/5665)
回答No.12

>> ある処理系においてはstrcmp("abcd", "abc")の戻り値は'd'になる仕様です >#4の回答には、「仕様」とは書かれていません。 #4には確かにstrcmpの仕様とは書かれていませんけど >%d以外の!=EOFの間は&inputに0が代入されると思ってました >コンパイラの仕様で戻りもかわりますね の文からすると、strcmpの戻り値として'd'を返すのも(コンパイラの)仕様と思われてるように思いますが。 また#6には >コンパイラの仕様の違いを表現する為 >関係の無いstrcmp関数を持ち出しました というような事書いてあるんですが。 >C言語では、'd'は文字ではなく、文字dの文字コード(整数値)です。したがって、int値を返す関数の中で >return 'd'; >と書いてもかまいません。もちろん整数値が返ります。 私自身が'd'を文字と思ってるわけじゃないですけど・・・

回答No.11

元の質問から離れてしまっているので心苦しいのですが、 #10の方へ > ある処理系においてはstrcmp("abcd", "abc")の戻り値は'd'になる仕様です #4の回答には、「仕様」とは書かれていません。 strcmp("abcd", "abc")は正の整数値を返せばよいので、値'd'を返してもよいということです。 > 「strcmpは何らかの演算結果で文字'd'の文字コードと同じ値を戻してるのであって、文字'd'を戻してるわけじゃない」 C言語では、'd'は文字ではなく、文字dの文字コード(整数値)です。したがって、int値を返す関数の中で return 'd'; と書いてもかまいません。もちろん整数値が返ります。

  • wormhole
  • ベストアンサー率28% (1626/5665)
回答No.10

#9の方へ >'d'はint値です。 >strcmp("abcd","abc")としたとき、 > 値'd'が正であるなら、'd'を戻り値にしても規格違反ではありません。 > ('d'の値が負であるような処理系があったとして、それが-'d'を戻り値にしても規格に適っています) 私が#5で書いてるのは規格違反という話ではありません。 「ある処理系においてはstrcmp("abcd", "abc")の戻り値は'd'になる仕様です」というように「仕様」扱いにするのはおかしいという事を話をしてるんです。 もしstrcmp("abcd", "abc")の戻り値が'd'になる事、または'd'になることが予想できる事を仕様として明言している処理系がありましたら教えてください。 >> strcmpの仕様を勘違いされてます。 >> この場合、strcmpは'd'を戻してるわけじゃありません。 >この処理系は、'd'-'\0'='d'-0='d'で、'd'を戻しているのでしょう。 これは私の説明不足だったんでしょうが「strcmpは何らかの演算結果で文字'd'の文字コードと同じ値を戻してるのであって、文字'd'を戻してるわけじゃない」という事を書こうとしてました。

回答No.9

sscanfの戻り値は、『変換が一つも行われないまま入力誤りが起きたときはEOF、それ以外の場合は代入された入力項目の個数を返す、この個数はゼロになることもある。』です。 例えば、次のプログラムでは、 #include <stdio.h> int main(void) { int a, b, c, d; b = sscanf("", "%d", &a); d = sscanf("abc", "%d", &c); printf("%d %d\n", b, a); printf("%d %d\n", d, c); } bの値はEOF、dの値は0になります。aとcの値は不定です。 質問の中のプログラムでは、うまく変換できたときのsscanfの戻り値は1になるので、 if(sscanf(linebuf, "%d", &input) == 1) { とすればうまくいくでしょう。 #5の方へ 'd'はint値です。 strcmp("abcd","abc")としたとき、 値'd'が正であるなら、'd'を戻り値にしても規格違反ではありません。 ('d'の値が負であるような処理系があったとして、それが-'d'を戻り値にしても規格に適っています) > strcmpの仕様を勘違いされてます。 > この場合、strcmpは'd'を戻してるわけじゃありません。 この処理系は、'd'-'\0'='d'-0='d'で、'd'を戻しているのでしょう。

jet888
質問者

お礼

回答ありがとうございます。 遅くなって申し訳ありません。 >質問の中のプログラムでは、うまく変換できたときのsscanfの戻り値は1になるので、 >if(sscanf(linebuf, "%d", &input) == 1) { >とすればうまくいくでしょう。 確かにこの場合は、格納するアドレス変数が一つしかないため、 「==1」としたほうがいいですよね。 ご指摘ありがとうございます。

  • wormhole
  • ベストアンサー率28% (1626/5665)
回答No.8

>仕様と実装の違いもよくわからないのですが、 >http://web.sfc.keio.ac.jp/~tsaito/JavaLectures/Lecture1/Lec1-1.html >によると、 そこに書かれているのは作業工程としての「実装」のような。 >例えばsscanf関数なら文字列から書式付きデータを読み込むことを目的とし、パラメータや戻り値を設定することで合ってますでしょうか。 それはsscanfの仕様の内の処理概要ですね。 VisualC++のsscanfの仕様 https://msdn.microsoft.com/ja-jp/library/ms396980(v=vs.71).aspx Linuxのsscanfの仕様 http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/scanf.3.html を見てもらえれば、それだけではなく引数や戻り値の説明も書かれているのがわかると思います。 それら全部が揃ってsscanfの仕様です。 実装は、仕様を実現するためのコード(プログラム)の事です。 実装は、仕様を実現できればよいので何種類もあることはあります。 例えば2つの整数の掛け算をするint multi(int, int)という関数があったとして実装が int multi(int a, int b) { return a * b; } であろうが int multi(int a, int b) { int r = 0; if (b > 0) { for (int i = 0; i < b; i++) { r += a; } } else if (b < 0) { for (int i = 0; i < -b; i++) { r -= a; } } return r; } であろうが、どちらもint multi(int, int)の実装には違いありません。 >私が質問のところで記述したプログラムでは<stdio.h>をincludeしていますが、 >この<stdio.h>の内容が、例えばWindowsの場合とMacの場合では異なるということでしょうか。 同じかもしれませんし異なるかもしれません(実際には異なってるんでしょうけど)。 ただヘッダファイルにはほとんどの場合、書かれてるのはプロトタイプ宣言で実装は書かれていません。

jet888
質問者

お礼

再度、回答ありがとうございます。 実装と仕様の違いと、ヘッダファイルの件についても説明していただき、 ありがとうございます。 知らないことばかりで大変勉強になりました。 何度も質問に答えていただき、ありがとうございました。

  • wormhole
  • ベストアンサー率28% (1626/5665)
回答No.7

>コンパイラによって関数内部の仕様はまったく異なるのですね。 >大変勉強になりました。 違うのは仕様ではなく実装です。 関数の仕様を知りたければ実装から推測せずにマニュアルを参照しましょう。 VisualStudioのstrcmpやsscanfの仕様だと https://msdn.microsoft.com/ja-jp/library/ms396980(v=vs.71).aspx https://msdn.microsoft.com/ja-jp/library/vstudio/e0z9k731(v=vs.100).aspx になります。 その仕様を実現するために、どのような実装がされているのかを勉強するのはよいと思いますが、それを仕様と思い込まない方がよいです。 また(C)コンパイラによって異なるわけではなくライブラリによって異なります。 コンパイラはヘッダファイルなどに書かれているプロトタイプ宣言などで、関数と戻り値や引数の型を知る(事前に知ってるわけではなくコンパイル時に知ります)だけで、その関数がどのような実装になってるのかコンパイラ自身で知ってるわけじゃありません。

jet888
質問者

お礼

再度、回答ありがとうございます。 >違うのは仕様ではなく実装です。 仕様と実装の違いもよくわからないのですが、 http://web.sfc.keio.ac.jp/~tsaito/JavaLectures/Lecture1/Lec1-1.html によると、 実装とは「設計に従ってプログラミング言語で命令を記述してゆく段階です。この段階のこと」とあるので、プログラムを記述することであり、 仕様とは、「プログラムを実際に作成する際の指針と内容のあらまし」のことで、例えばsscanf関数なら文字列から書式付きデータを読み込むことを目的とし、パラメータや戻り値を設定することで合ってますでしょうか。 >その仕様を実現するために、どのような実装がされているのかを勉強するのはよいと思いますが、それを仕様と思い込まない方がよいです。 ということは、プログラムを作成する際の指針(文字列から書式付きデータを読み込むこと)は同じであるが、実装(出力の仕方など)は異なることがあるという意味でよろしいでしょうか。 >また(C)コンパイラによって異なるわけではなくライブラリによって異なります。 私が質問のところで記述したプログラムでは<stdio.h>をincludeしていますが、 この<stdio.h>の内容が、例えばWindowsの場合とMacの場合では異なるということでしょうか。

  • Wap58
  • ベストアンサー率33% (29/87)
回答No.6

1です、sscanf関数は第2引数で 要求を受けて、それを元に比較して 第1引数から第3引数に代入します 何を代入するかはコンパイラ次第 該当しないので何も代入しない もしくは0を代入するなどは コンパイラまかせです コンパイラの仕様の違いを表現する為 関係の無いstrcmp関数を持ち出しました ご指摘のようにstrcmpは文字列比較の目的で intを返します、本来の使用目的が違います 又。コンパイラによって仕様も変わります 以下のソースで内部の動きを確認して下さい #include <stdio.h> #include <string.h> int main(void){ char name[10]; int i; while(1){ printf("Type to :"); fgets(name,sizeof(name),stdin); if(strlen(name) <= 1) break; i = strcmp(name,"\0"); printf("Your Type : => %c %d\n",i,i); }//END while i = strcmp("abcd","abc"); printf("strcmp =>%c %d 100 =>%c\n",i,i,100); return 0; } 最後の部分でコンパイラの結果 Win strcmp =>『 1 100 =>d Cygwin strcmp => 1 100 =>d Mac strcmp =>d 100 100 =>d sscanf内部の仕様もコンパイラで変わります ところで日本語は自然解釈じゃダメですか?

jet888
質問者

お礼

再度、回答ありがとうございます。 >何を代入するかはコンパイラ次第 >該当しないので何も代入しない >もしくは0を代入するなどは >コンパイラまかせです この部分の意味を書いていただいたソースの実行結果を見て、 ようやく理解できました。 コンパイラによって関数内部の仕様はまったく異なるのですね。 大変勉強になりました。 ※Cygwinはまだインストールしていないため、後で実行してみます。 (Macは持ってないため実行できないのです) >ところで日本語は自然解釈じゃダメですか? これはどういう意味でしょうか?

  • wormhole
  • ベストアンサー率28% (1626/5665)
回答No.5

#4の方へ >printf("strcmp=>%c\n",strcmp("abcd","abc")); (略) >うちのやつは%cにdを持って戻ってきます strcmpの仕様を勘違いされてます。 この場合、strcmpは'd'を戻してるわけじゃありません。

jet888
質問者

お礼

再度、回答ありがとうございます。 >この場合、strcmpは'd'を戻してるわけじゃありません。 この点について、#4さんの御礼コメントにも書いたのですが、 strcmp関数のデータ型はint型であるため、戻り値もint型(整数)となると思うのですが、 教えていただけますでしょうか。

  • Wap58
  • ベストアンサー率33% (29/87)
回答No.4

1です、標準関数の仕組みの勉強になりました %d以外の!=EOFの間は&inputに0が代入されると思ってました コンパイラの仕様で戻りもかわりますね できればいろんなコンパイラで試して下さい 多分以下はトピ主さんのは%cで戻らないと思います #include <stdio.h> #include <string.h> int main(void){ printf("strcmp=>%c\n",strcmp("abcd","abc")); return 0; } うちのやつは%cにdを持って戻ってきます 自作関数の発想も変わります

jet888
質問者

お礼

再度、回答ありがとうございます。 コンパイラはMinGWしか使ったことがなかったのですが、 他のコンパイラでも試したほうがいいのですね。 あと、書いていただいたコードを実行してみたところ、 strcmp=>『(かぎかっこの前の部分のみ) と出力されました。 「%c」を「%d」にしたところ、 strcmp=>1 と出力されました。 ちなみに、visual C++ 2008でためしたところ同じ結果となりました。 strcmp関数の戻り値はint型(整数)となると思うのですが、 これを%cで出力すると文字が出力されることになりますよね? >うちのやつは%cにdを持って戻ってきます これは、%cでも整数の値が出力されるということでしょうか?

  • wormhole
  • ベストアンサー率28% (1626/5665)
回答No.3

>今回の場合は、最初に一致の失敗となるため返り値が「0」になるということだと思いますが、 >「最初の変換が成功する前に入力の最後に達して」という部分との違いがよくわかりません。 変換する前に文字列終端に達してる場合です。 例えばlinebufが""だったら、どうなのか考えてみてください。 >コンパイラによって挙動が異なるのですね。 >MinGWの場合、EOFではなく0でなければうまくいかないようです。 未定義の部分ですからコンパイラにより挙動が異なるのは確かですけど "a"が入力されたとき、この場合のsscanfの戻り値は0ですからEOFではもちろんありません。 またsscanfの戻り値が0ということは何も変換してないわけですからinputは int input; の何が入ってるかわからない状態です。 それがたまたま0の場合は「0の2乗は0です。」と出力されます。 #1の方の書かれてるのは『「!=EOF」で実行したところ無関係な数値0が出力されました。』という事ですよ(値が0だから関係ありそうな気がするだけで実際には何の関係もありません)。

jet888
質問者

お礼

再度、回答ありがとうございます。 >例えばlinebufが""だったら、どうなのか考えてみてください。 これは入力された文字列がなかった場合ということですね。 (enterのみが入力された場合) そう考えると、「最初の変換が成功する前に入力の最後に達して」の意味がわかりました。 また、コンパイラに関わらず、この場合のsscanf関数の戻り値は0であり、 #1さんの場合は、input変数にたまたま0が入っていたため、 「0の2乗は0です。」と出力されたということなんですね。 大変わかりやすい説明をしていただき、理解することができました。 ありがとうございました。

関連するQ&A