以下のコードでつぎのエラーがでます。理由がわからないので教えてください。vs2005 vc win32です。


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.

回答の条件
  • 1人2回まで
  • 登録:
  • 終了:2009/10/24 02:05:03
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

回答3件)

id:ardarim No.1

回答回数897ベストアンサー獲得回数145

ポイント26pt

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桁に収まらない場合は、自動的に桁数が拡張されます。

参考:printf 関数の文字幅指定 (CRT)


sprintfは、格納先の領域のサイズをチェックしませんので結果としてspsの前後に配置された変数(この場合double sdやchar *shm1,*shm2)の領域を侵して上書きしてしまいます。その結果、警告が出た後はこれらの変数の値は予期しない値に書き換わってしまいます。


警告をなくすには、変換後の文字列が絶対に格納できる程度に領域サイズを十分に取る(spsのサイズを大きくする)か、StringCbPrintfのような領域サイズをチェックするsprintfの代替関数を利用して、領域に収まるかどうかのエラーチェックを行う方法があります。

id:yo-kun No.2

回答回数220ベストアンサー獲得回数30

ポイント27pt

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を指定する意味はありません。

id:hseisyu No.3

回答回数11ベストアンサー獲得回数2

ポイント27pt

確認は行っていないですが、

3.2f ということは "123.45" といった値ですよね?

この6文字に加え、char の場合終端文字 '\0' が最後に必要ですので、7文字分必要です。

char sps[7];

で解決できないでしょうか?

さらにいうと、もし sd が 1000 を超えた場合、

sps には8文字入る可能性もあると思います。

なので、sps[256] 程度とって置くと安全かと思いますよ。

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません