この場合、おそらく次のいずれかを書く必要があります。
char str1[10] = "%any";
char str1[] = "%any"; // str1 has size 5
const char *str1 = "%any"; // str1 points to a string literal
%a
フォーマット文字列では、16進浮動小数点フォーマットです。引数を指定しなかったdouble
(未定義の動作を引き起こす)という事実を除けば、これにより10バイトを超える書き込みが発生し、バッファをオーバーランする可能性がありますstr1
(未定義の動作を引き起こします)。
そのため、が表示されます。これ0x0.07fff00000001p-1022ny
は、16進浮動小数点値の0x0.07fff00000001p-1022
後に。が続きny
ます。おそらく、スタックに格納されているリターンアドレスを壊したために発生する不正な命令エラーが原因であるため、関数がリターンすると、無効なアドレスにジャンプします。
経験則として、printf
関数の1つを使用し、フォーマット文字列の後に少なくとも1つのvarargを指定しない場合、何か間違ったことをしている可能性があります。f
inの意味はprintf
、関数がフォーマットを行うということですが、フォーマットするものがないときに使用しています。つまり、これは単なる文字列のコピーであり、間違いを犯す可能性があります。
関数ファミリーの1つを使用しprintf
て文字列を記述したい場合は、次のように意図していない形式を誤って指定することを回避できます。
sprintf(str1, "%s", SOME_STRING);
または長さチェックを利用するには:
#define STR1_SIZE 10
char str1[STR1_SIZE];
if (snprintf(str1, STR1_SIZE, "%s", SOME_STRING) >= STR1_SIZE) {
// error-handling here
}
どういうわけかそれがSOME_STRING
バッファに収まることがわかっている場合は、エラー処理を省略したり、strcpy
代わりに使用したりできます。しかし、それを行うと長さが間違ってしまうと、かなりばかげているように見えます。
(ほとんどの文字列処理コードのように)ポインタではなく、(ここにあるように)配列である提供sizeof(str1)
の代わりに使用することもできます。STR1_SIZE
str1
エスケープしてみました。つまり、sprintfで「%any」の代わりに「\%any」を使用しました。しかし、これは役に立ちません。
良い試み、葉巻なし;-)
バックスラッシュは、文字列リテラル内の特殊文字をエスケープするためのものです。%
文字列リテラルでは特別な意味はないので、エスケープしても効果はありません。結果の文字列は5文字、、、、、%
です。a
n
y
\0
後でその文字列をに渡しますsprintf
。これで、は特別な意味を持ち、それをエスケープする別の方法があります。%
%%