アプリ版:「スタンプのみでお礼する」機能のリリースについて

C言語の入門書には、必ずと言っていいほどscanf()が例題に使われており、また本質を理解するに到底足らない上っ面の説明だけが載っています。

ここで質問ですが、なぜ入門書では扱いが難しく将来的に使う可能性が非常に低いであろうscanf()を例題に使っているのでしょうか?どうせおまじないとして書くならば、fgets()とstrtol(), strtod()あたりを組み合わせたおまじないを例題に書いておいてもよさそうな気がしますが、紙面の都合なのでしょうか?

A 回答 (5件)

int a ;


scanf("%d",&a);

とほぼ同じことをするのに

int a ;
char buf[256] ;
fgets(buf, 256, stdin) ;
a = (int) strtol(buf,NULL, 10);

となり、

・文字列用の変数(charの配列)
 bufは変数名だからbufでなくてもよい
 256は適当
・FILE* stdin を使った入力
・long→intのキャスト(暗黙のキャストでもできるけど)

が「おまじない」になります。
これだと、さすがに「おまじない」が長過ぎるでしょう。

int a,b ;
scanf("%d",&a);
scanf("%d",&b);


int a,b ;
char buf[256] ;
fgets(buf, 256, stdin) ;
a = (int) strtol(buf,NULL, 10);
char buf[256] ;
fgets(buf, 256, stdin) ;
b = (int) strtol(buf,NULL, 10);

って書いちゃう人が続出しそうです。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

>これだと、さすがに「おまじない」が長過ぎるでしょう。

ここが、感覚の相違ですね。
1個のchar配列の宣言の追加と2行での処理を「長すぎる」と考えるか、今後応用の利く記法として例示しておいても構わないと考えるか、だと思います。質問文からご推察いただけるように、私の立場は後者です。

>って書いちゃう人が続出しそうです。

これは、確かにその通りかもしれません。scanf()を使った例題を書く段階って、宣言の意味がまだ定着していないでしょうね。まあ、そこで叱られて痛い目を見て覚えろ、というのは不親切ですかね。

お礼日時:2017/12/05 10:39

No1の方の言う通りなのですが、更に言えば、実際の業務では、strtol等も使いません。


例えば、CSV形式でデータ(数値)が入力される場合(スペース区切りでも良いですが)、
scanfで入力データを取得する場合を例にとると、
入門書では、データが正しく入力されることを前提にプログラミングを行っています。
もし、数値でないデータ、CSV形式にならないデータ等が入力された場合、どうなるか結果は保証されません。

一方、実際の業務では、そもそも、入力データが正しくない場合があることを前提に、プログラミングを行います。
もし、数値でないデータ、CSV形式にならないデータ等が入力された場合は、どの行でそのエラーが発生したのか、
どのデータが正しくないのか等の正確なエラー情報をオペレータに出力する必要があります。
(そうしないと、データを正しく修正して、やり直しして修正することができません)
その為に、CSVの構文解析ルーチンのようなものを自前で作るか、あるいは、ライブラリのようなものを利用することになります。
そして、全てのデータが正しいことが、保証された時、初めてそのデータを使って処理をおこないます。

入門書では、上記の実際の業務ようなことをさせるわけにはいかない為、簡単にscanfで扱っているのが現状かと思います。
又、入門書は、scanfの使用方法の取得が本来の目的ではなく、scanfで取得したデータを使って、
そのデータをどのように処理するかが本来の入門書での説明の目的になります。
その為、データの取得については、scanfで簡単にすましているかと思います。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

>更に言えば、実際の業務では、strtol等も使いません。

えー、使わないのですか?不整値のチェック等非常にやりやすいので、私は文字列→数値変換では常用しています。
もしよろしければ、文字列→数値変換でstrtol()以外のベストな方法を教えてください。
#業務では文字列→数値変換する機会がない、ということでしたらスミマセン

>一方、実際の業務では、そもそも、入力データが正しくない場合があることを前提に、プログラミングを行います。

これはその通りです。
業務どころか、実際に使えるプログラムを書くという場面では、入力を正しくチェックすることは必須でしょう。そういったときに、非常に使いづらいscanf()を「最初の」知識として与えるのが本当に適当なのだろうか、ということが疑問なのです。

>入門書では、データが正しく入力されることを前提にプログラミングを行っています。
...
>入門書では、上記の実際の業務ようなことをさせるわけにはいかない為、簡単にscanfで扱っているのが現状かと思います。

No.1の方がご親切に例示していただいたstrtol()の第2引数をNULLにしているのも、データが正しく入力されることを前提としているという意味では同様ですよね(つまりatoi()と等価な用法)。
入門書の段階では、それはそれでいいと思います。
さすがに、比較的コード量が短くて済むstrtol()のエラー処理でも、
char *e;
a = strtol(buf, &e, 10);
if (errno == ERANGE) {
...
}
if (*e != '\n') {
...
}
ぐらいの量になるので本来の目的がぼやけてしまい、本末転倒だと思います。

でも、数行増える程度だったら、scanf()よりも今後多用するであろう記法を刷り込んでおいてもいいんじゃないかな、と思うのですが・・・

お礼日時:2017/12/05 11:32

>えー、使わないのですか?不整値のチェック等非常にやりやすいので、私は文字列→数値変換では常用しています。


>もしよろしければ、文字列→数値変換でstrtol()以外のベストな方法を教えてください。

いやいや、strtolを使うのがだめだと言ってるわけではありません。
例えば、"+1234"の文字列をstrtolで処理すると正常になりますが、
+、-の符号はエラーにして、0~9の数字の場合だけを正常にしたいケースの場合は、strtolは使っていません。
そして、そのようなケースは非常に多いのです。

以下は、私が業務で使っている方法です。(これがベストとは言ってません。念のため)
条件としては、
1)int型で扱える範囲の数
2)0以上の整数
上記の2つを扱う場合に使います。
尚、int型で扱える範囲の上限は、2147483647ですが、
これを厳密におこなうなら、算出した結果が、この上限を超えないことのチェックまで行います。
但し、これまでの数値を必要としない場合(9桁以内の数字で間に合う場合)は、文字列長が9桁以内であればOKにしています。
以下は、私がよく使用している数字チェック関数です。
OKなら0以上の値を返し、エラーなら-1を返します。
int check_numeric( char *str)
{
int i;
int num = 0;
int len = strlen(str);
char *p = str;
if (len < 1 || len > 9) return -1;
for (i = 0; i < len;i++,p++){
if (*p < '0' || *p >'9') return -1;
num = (10 * num) + (*p - '0');
}
return num;
}

この関数の場合、"001"等をOKにしていますが、最初から"0"で始まる数字はエラーにしたい
場合は、更にチェックを追加する必要があります。その場合は、そのように作りこみます。

結局、私が言いたいのは、strtolで充分なら、それで良いし、それで不十分なら、strtolに近いものを
(極力簡単になるように条件を絞り)自前で実装すればよいということです。
    • good
    • 0
この回答へのお礼

再びご回答ありがとうございます。

>+、-の符号はエラーにして、0~9の数字の場合だけを正常にしたいケースの場合は、strtolは使っていません。

なるほど、+-を正負号ではない記号として使われることが多いのですね、納得です。
私はめんどくさがりなので、先頭文字の判定だけが必要なら次の文字からstrtol()使っちゃうし、数字判定ならif (isdigit((int)*p))しちゃいますが、このあたりはわかってて自分のスタイルで書くことには全く異論はありません。
「実際の業務では」を「プロの書くコードでは」と勘違いしてしまいました。

お礼日時:2017/12/05 12:48

紙面の都合上では無いでしょうか。



文字の入力は飽くまで記述したい内容への過程ですので、
簡潔に一行で済むscanfを採用しているのだと思います。

以上ご参考まで
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

「簡潔に一行で済む」ってところがポイントだということですね。

お礼日時:2017/12/07 10:51

正直なところ, どうせ「入門書」ではエラー処理などほとんどしていないのだから scanf で十分じゃないかなって思う.



まじめに処理しようとすると fgets でもめんどくさいしね.
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

>まじめに処理しようとすると fgets でもめんどくさいしね.

確かにどんなエラー処理でもめんどくさいですが、fgets()のエラー処理のめんどくささはscanf()の比ではないと思います。

お礼日時:2017/12/07 11:19

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!