- 締切済み
getsをscanfで書き直すにはどうしたらよいですか?
現在。行数を数えるプログラムを例をみながらエディダに入力してコンパイルしてみたのですが、gets関数ではエラーが出てそれ以上すすまないです。 他の掲示板なんかをみると、getは危険だからscanfを使うといいですよと書いてあったのですが、書き換えかたがよく分からないのです。 *以下が問題にしているソースです。 /* ************************************* */ /* */ /* 行を数えるプログラム */ /* */ /* ************************************* */ #include <stdio.h> #include <stdlib.h> void main(void) { FILE *fp; char fname[256]; int c; int count; printf("ファイル名:"); if (gets(fnama) == NULL) { /* この部分 */ printf("入力エラーが発生しました。\n"); exit (-1); } if ((fp = fopen(fname,"r")) == NULL) { printf("ファイル '%s'をオープンできませんでした。\n",fname); exit (-1); } while ((c fgetc(fp)) != EOF) { if (c == '\n') { count++; } } printf(">>> ファイル %s は %d 行です。\n",fname,count); fclose(fp); }
- みんなの回答 (8)
- 専門家の回答
みんなの回答
- jacta
- ベストアンサー率26% (845/3158)
処理系が不明な状況で、「決め付け」の回答をいくらしても不毛なだけですが... 何となく、glibcがgetsをリンクしたときに出す警告の話のような気がします。 その警告を消すためにscanfを使うというのなら、一応効果があります。 なお、scanfで入力文字数を制限するのであれば、 char *mygets(char *s) { if (scanf("%256[^\n]%*[^\n]", s) < 1) { return NULL; } return scanf("%*c") == EOF ? NULL : s; } とでもしておけば、入力文字数を256文字に制限できます。
- Tacosan
- ベストアンサー率23% (3656/15482)
う~ん, 「getsは危険だからscanfを使うといいですよ」って意味が分からんなぁ. まあ確かに gets よりは scanf の方が安全にできるけど, 普通の流れは「gets は危険だから fgets」だと思う. ああ, fgets は仕様上「最後に改行が残ることがある」のでその処理は必要. 以下 #5 に対する補足というか突っ込みというかなんというか: まず, 「ファイルが 0x1a で終わっている」とは限らない. 0x1a はいわれる通り CP/M の名残だが, これは CP/M がブロック単位でしか長さを記録できなかったためであり, MS-DOS では既にこの仕様は廃止されている. また, 「プログラムが正常に終了した場合」に「返すべき」値は C の規格で決まっているし, (#define された) 記号定数として与えられている. プログラム上で「OS のご機嫌取り」をする必要はない.
- chie65536(@chie65535)
- ベストアンサー率44% (8742/19841)
「getsが危険な理由」は「改行が来るまで延々と読み込もうとする」からです。 入力をリダイレクトし、ファイルを標準入力に結び付けた場合、そのファイルが2メガバイトあって、改行コードが一切入って無いとしたら、getsは、指定したバッファに2メガバイト読み込もうとします。 それが「危険な理由」です。 どなたかの回答で scanf("%[^\n]%*c", s) < 1 ? NULL : s; と書いているのがありますが、これも「scanfを使ってgetsを忠実に再現した」ので「getsとまったく同じ危険性を孕んでいる」のです。 これでは「危険性を回避する」と言う目的を達していません。 「危険性を回避する」には「上限(バッファサイズ)を与え、改行が来ない場合にも上限を超えないように打ち切る」と言う処理が必要です。 そういう意味では「scanfもgetsと同様に危険」なので「getsをscanfに置き換えても危険なのは危険」です。 安全性を求めるなら「getcharだけ使って1行入力を自作する」しかありません。
- yama5140
- ベストアンサー率54% (136/250)
>gets関数ではエラーが出てそれ以上すすまないです。 いや、それ以上進みますが・・(もち、スペルミス修正後 fnama → fname )。 (BorlandC++5.5.1) 「エラー」の出た場所は、while ((c fgetc(fp)) != EOF) { では・・?。 まっ、ここを直し、コンパイルできたとしても、 テキストファイルは、ファイル終端が 「改行」0x1A ではなく、直 0x1A のこともあります( 0x1A は CP/M の名残?)。 if( c == '\n' ){ は「改行」を数えているので、この場合、最終行をカウントしません。 正確に行数を数えるのなら fgets がよろしいのでは・・。 http://www.bohyoh.com/CandCPP/C/Library/index.html 「・・改行文字を読み取ったとき、またはファイルの終わりを検出したときに、文字の読取りは終了・・」 ここの「または・・」が「改行なしの最終行」を指すのだと思います。 >他の掲示板なんかをみると、getは危険だからscanfを使うといいですよと書いてあったのですが、書き換えかたがよく分からないのです。 gets の、「入力する文字数を制限できない」という点は、今回は関係ないかと・・。 +++++++++++++++++++++++++++++++++++++ >void main(void) 質問者様お使いの処理系が、この定義を「エラー」としないのは、「処理系定義の方法」だからで、いたって正常な使い方だと思います。 ☆「自分」で「自分」のプログラムからの「戻り値」を使おうとしない限り、void main() のままのスタイルで良いと思います。 なお、「戻り値」は、OS、少なくとも MS-Windows にとっては、全く無用で屁の突っ張りにもなりません。 万が一、「戻り値」がOSにとって重要であるならば、(プログラム的には正常終了 = return )状態によって、どんな整数を「戻す」べきか、調べてプログラムしないといけません。 言い換えると、OSのご機嫌取りをしなくてはなりません。 ☆「言語」側(「自分」のプログラム)で、「OS」のご機嫌取りをする必要は全くない、と考えます。
- asuncion
- ベストアンサー率33% (2127/6289)
>getは危険だから 今回のような練習問題のレベルであれば、getsを使っても特に問題ないです。 他のだれにも迷惑がかかりませんので。 >void main(void) main関数の型は言語規格でintであると決まっています。 >count++; インクリメントするからには、ゼロで初期化しておかねばなりません。
- koko_u_
- ベストアンサー率18% (459/2509)
>このままgets関数を使っていてもいいですか? まずは何故危険であるかを理解しましょう。 scanf() を使用しても「自動的に」安全性が手に入るわけではありません。
- jacta
- ベストアンサー率26% (845/3158)
スペルミスのような気もしますが... > getsをscanfで書き直すにはどうしたらよいですか? これに答えるのであれば、 char *mygets(char *s) { return scanf("%[^\n]%*c", s) < 1 ? NULL : s; } でよいかと思います。
- koko_u_
- ベストアンサー率18% (459/2509)
>gets関数ではエラーが出てそれ以上すすまないです。 スペルを間違えている。とかそんなオチではないですよね?
補足
すいません、そんなオチでした・・・ でも、最後まで、gets関数は危険ですというメッセージは 消えませんでした。 このままgets関数を使っていてもいいですか?