double sd;
char sps[6];
char *shm1,*shm2;
sd=atof(shm2)-atof(shm1);
sprintf(sps,"%3.2f",sd); <=ここでエラー
エラー
Run-Time Check Failure#2 Stack around the variable 'sps' was corrupted.
sprintfでフォーマットされた文字列を格納する領域(sps)が不足しているため、メモリ破壊(スタック破壊)が起きているという警告です。
このプログラムでは、spsはchar型の6個の配列であり、つまり6文字まで格納することができますが、文字列を格納する場合、一番最後に文字列の終端を意味する '¥0' (いわゆるNULL文字)が必要になるため、実際にspsに格納できる文字列は5文字までとなります(6文字目は '¥0' が入る)。
さてsprintfの書式指定は "%3.2f" なので、小数点以下2桁までで3桁表示すると言う指定です。sdの値をこの書式に当てはめた結果が、5文字を超えるような場合に、spsの領域に納めることができず該当の警告が表示されます。
例えば、sdの値が、100.00(6桁)とか、-10.00(6桁)のような数字になった場合このような結果となります。
sprintfの書式指定において桁数指定(このプログラムの場合、3)は最小の桁数であって最大の桁数ではないことに注意する必要があります。3桁と指定していても、実際の結果が3桁に収まらない場合は、自動的に桁数が拡張されます。
sprintfは、格納先の領域のサイズをチェックしませんので結果としてspsの前後に配置された変数(この場合double sdやchar *shm1,*shm2)の領域を侵して上書きしてしまいます。その結果、警告が出た後はこれらの変数の値は予期しない値に書き換わってしまいます。
警告をなくすには、変換後の文字列が絶対に格納できる程度に領域サイズを十分に取る(spsのサイズを大きくする)か、StringCbPrintfのような領域サイズをチェックするsprintfの代替関数を利用して、領域に収まるかどうかのエラーチェックを行う方法があります。
sdに入る値によってはアウトですね。
spsのサイズが足らない場合があります。
例えばsdに3.1415926535が入っていると
spsには"3.14\0"が入ります。(\0は終端文字)
これはchar5つ分なのでセーフです。
しかし仮にsdに1234.56789が入っていると
spsには"1234.56\0"の8文字が入ることになります。
すると6文字分しかない配列をはみ出してスタック領域を破壊することになります。
これによりエラーとなるのです。
spsには十分大きなサイズを用意しましょう。
そもそも変換指定の%3.2fの「3」は最小フィールド幅を指定しているだけです。
言い換えれば、「文字列に変換した後3文字に満たない場合は空白で埋める」という意味です。
例えば
printf( "%3d", 1 );
とすると
__1と表示されるわけです。(_は空白を表していると考えてください)
この場合、精度(%3.2fの2の部分)が2で小数点以下第2位まで表示されるわけですから
最小フィールド幅に3を指定する意味はありません。
確認は行っていないですが、
3.2f ということは "123.45" といった値ですよね?
この6文字に加え、char の場合終端文字 '\0' が最後に必要ですので、7文字分必要です。
char sps[7];
で解決できないでしょうか?
さらにいうと、もし sd が 1000 を超えた場合、
sps には8文字入る可能性もあると思います。
なので、sps[256] 程度とって置くと安全かと思いますよ。
コメント(0件)