目次
1.はじめに
2.キーボードからの入力
3.scanf()の使用例
4.バッファオーバーフローについて
5.安易な解決方法
6.フィールド幅を指定する
7.おわりに
1.はじめに
筆者自身半年前にC言語の学習を始めたばかりであることを最初にお断り申し上げます。自身も初心者ながら、様々な、初級的なプログラムを書いてきた身として、悩まされたが面白いなと思ったのがscanfでした。普段何も考えず使っていた方には一読していただけると幸いです。
2.キーボードからの入力
c言語にはscanf()という入力を受け付ける関数が存在します。
初心者やテストプログラムでしか使われませんが、初心者が使う関数にしてはかなり難のある関数です。
メモリやポインタ、配列などを理解せずに、この関数を使用すると安易にエラーや、バッファオーバーフローを引き起こしてしまいます。
ここでは、その仕組みについては触れませんが、とりあえず皆さんが作ったプログラムが正しく動作するように、どのようなことをすればよいか、簡単に説明します。
3.scanf()の使用例
よく入門書に書かれている感じで scanf を使いキーボードから文字を入力してみる。
※コピペして実行してみてください
#include<stdio.h>
int main(void)
{
char a[10] = {0};
char b[10] = "shimada";
scanf("%s",a);
printf("%s\n",a);
printf("%s",b);
}
この場合9文字までの入力であれば正常に表示できるが10文字を超えてしまうとバッファオーバーフローとなり
b[10]の文字列を正しく表示できなくなってしまいます。
4.バッファオーバーフローについて
C言語においてchar型の配列は、文字列を格納できる変数であるが、定義する際に、配列の大きさを指定する必要がある。
ここで問題になるのが、この最初に決めた配列の大きさより大きなサイズの文字列はその最初に決めたサイズ分は格納できるが、あふれ出た分がほかの変数に影響を及ぼすことがあるということである。これがバッファオーバーフローと呼ばれる現象である。この現象は主にC言語で起こる特有の現象である。
5.安易な解決方法
入力をする配列を大きくすることにより、人間が入力するであろう、常識的な範囲内ではバッファオーバーフローが起きないようにする
※コピペして実行してみてください
#include<stdio.h>
#define S_MAX 1024
int main(void)
{
char a[S_MAX] = {0};
char b[S_MAX] = "shimada";
scanf("%s",a);
printf("%s\n",a);
printf("%s",b);
}
このやり方で、C言語始めたての人が書いたプログラムならだいたい正常に動くと思いますが、根本的には全く解決していません。結局数千字の入力をされるとバッファオーバーフローが再び起きてしまいます。
6.フィールド幅を指定する
scanf("%s",b)となっていたものを
scanf("%9s",b)と書き換えることで読み取りを行う文字数に制限をかける。
※コピペして実行してみてください
#include<stdio.h>
#define S_MAX 10
int main(void)
{
char a[S_MAX] = {0};
char b[S_MAX] = "shimada";
scanf("%9s", a);
printf("%s\n",a);
printf("%s",b);
}
この方法をとれば、バッファオーバーフローは起きません。しかし、問題がなくなったわけではありませんが、入門ということであればここまでできれば、ほとんどのプログラムで問題はないでしょう。
このほかにも解決法は様々ありますがが、scanfはもう嫌だ、ほかの入力方法が知りたいという方は、fgetsなどほかの入力方法について調べることを強く推奨します。
7.おわりに
実際にこの知識が生かされることがどこまであるか、わかりませんが初心者のうちから、C言語というのはメモリと深い関わりがあり、下手をすると、プログラムが壊れてしまうこともあるということは、今後C言語を学ぶ上で必要なのではないでしょうか。また、今回解決法として提示したやり方にも様々な問題があります。その壁にぶつかったときまた、ほかのサイトなどを調べて学習していただくことをお勧めします。