質問: 0; i < num; i++) free(ptr[i]); free(ptr); } return 0; } ``` こちらはscanf()でオーバーフローを防いでいます。 正常に動作しオーバーフローは起きません。 [迷信] scanf ではバッファオーバーランを防げない データの読み込み(scanf関数) 今回の場合、scanf()が複数回実行されるので、stdinバッファ内に文字列を残さないようにしています。 ここからが本題です。 scanf()の他にfgets関数を使う方法があります。 標準入力から安全に文字列を受け取る方法いろいろ コメントの方にも書かれているのですが、 ``` fgets(temp, 128, stdin); ``` こちらを使うと表示が崩れます。 文字列は何個 : 2 ptr[0] :ptr[1] :fhdklafuadsf ptr[0] : ptr[1] : fhdklafuadsf このように、標準出力が崩れてしまいます。 なぜでしょうか? どうすれば解決できますか? いろいろ試してみたのですが、どうもうまくいきません。 fgets()は入力の処理をしているのになぜ出力の方に影響が出ているんですか?? おまけに1回しか入力を受け付けていないという困った現象まで起きています。 あ、ちなみに、オーバーフローの方は防げているようです。 それと、scanf(), fgets() 以外にユーザー入力からのオーバーフローを防げる関数ってあるんですか? (scanf_s()以外) Linux 64bit gccです。
回答: そもそも表示が崩れた原因は > > scanfとfgetsを混ぜて使うと入力ストリームの状態が意図せぬ状態になってうまくいかない > > > 元のコードでいえば、むしろ原因は先頭の scanf() にあると思います。 ``` printf("文字列は何個 : "); scanf("%d", &num); ``` ここで、例えば `12` と入力したとしましょう。実際は改行キーも叩くので、入力ストリームには `'1' '2' '\n'` という3文字が入力されます。`scanf("%d", &num);` は、そのうちの `'1' '2'` を読み出して num に 12 を代入します。 この時点で、まだ`'\n'` がストリームに残っていることに注意。この \n があるため、 一回目の fgets() の呼出しは、キーをタイプしなくても、自動的に空の一行が入力されてしまう、という現象だと思います。 だから scanf("%d", &num); の周辺に小細工を弄する手もあるでしょうが、私なら潔く scanf() を諦め、最初の数字入力も fgets() でやる手を選びます。こんな関数を紹介しましょう。 ``` char *myGets(char *buf, int size) { char *ptr; ptr = fgets(buf, size, stdin); if (ptr == NULL) // any error from fgets() return NULL; // then, return error ptr = strchr(buf, '\n'); // search '\n' in input if (ptr != NULL) // found '\n' ! *ptr = '\0'; // erase '\n' return buf; } ``` strchr(buf, '\n') は、buf 文字列中に '\n' があるかどうかを検査します。即ち '\n' が無い場合もあります(その条件は fgets() の仕様を調べること)。目的は '\n' '\0' を '\0' '\0' にする、即ち改行文字を消してしまう事です。こうしておけば、 ``` printf("文字列は何個 : "); myGets(temp, BUFLEN); sscanf(temp, "%d", &num); // 途中省略 for (i = 0; i < num; i++) { printf("ptr[%d] :", i); if (myGets(temp, BUFLEN) == NULL) goto FREE; ``` のような感じで動作を確かめられるはず。 P.S. オーバーフローというより、バッファオーバーランと呼んだ方が良いのではないかな。オーバーフローとは、例えば `unsigned char` 型の変数で `200 + 100` を計算したら桁溢れを起こして 300 にならない、ような場合がふさわしい気がする。