-3

Cで数週間遊んだ後、今では嫌いです。

私は今、execl を使用して別のプログラムに引数を渡そうとしていますが、引数のフォーマットは奇妙なことをします:

int select[2], result[2];
char str_w,str_r;

snprintf(&str_w, 2, "%d", select[1]);
snprintf(&str_r, 2, "%d", result[0]);
printf("%d %d %s %s\n", select[1], result[0], &str_w, &str_r);

execl("./recive.x","./recive.x",&str_w,&str_r,(char *)NULL);

ここで重要なのは snprintf です。ベクトル内の数値を文字列に変換しようとしています。数値は 10 未満になります。これを実行すると、表示される printf の結果は次のようになります。

5 6  6

つまり、select[1] には数値 (5) があり、result[0] には数値 (6) があり、result[0] は適切に文字列に変換されますが、select[1] はありません。

何だその行為は!!

前もって感謝します!

4

3 に答える 3

2

sprintfの呼び出しは、出力全体に適合するのに十分な、印刷データ用のバッファーを提供する必要があります。単一の文字へのポインタを渡しているため、出力は明らかに適合しません。

char str_w[2];
snprintf(str_w, 2, "%d", select[0]);

1桁の数値を文字列に変換するためのより良い方法は次のとおりです。

char res[2];
res[0]=num+'0';
res[1]=0;

最初のゼロを囲む一重引用符に注意してください。アイデアは、ゼロ文字のコードを1桁の数字に追加することです。

于 2013-02-17T14:24:22.440 に答える
2

Cで数週間遊んだ後、今では嫌いです。

これは珍しい反応ではありません。私の CS 入門クラスの 3 分の 1 は、 C の難しさを理由に専攻を変更しました (C は恐ろしい教育言語です)。頭を十分に理解するのに数年かかりましたが、一度理解すると感謝するようになりました。

char str_w,str_r;

snprintf(&str_w, 2, "%d", select[1]);
snprintf(&str_r, 2, "%d", result[0]);

これが主な問題です。str_w文字列ではなくstr_r、単一のchar値を保持するのに十分な大きさです (少なくとも2 文字が必要です)。代わりに、予想される最大の文字列表現、符号用のスペース (値が負の場合)、および 0 ターミネータを保持するのに十分な大きさのstr_wとの配列str_rとして宣言する必要があります。たとえば、またはの値を制限していなかった場合:charintselectresult

#define MAX_DIGITS 20 // max decimal digits for 64-bit integer
#define SIZE MAX_DIGITS+2 // 2 extra for sign and 0 terminator

char str_w[SIZE], str_r[SIZE]; 

sprintf(str_w, "%d", select[1]);
sprintf(str_r, "%d", result[0]);

可能な入力に対して十分な大きさのターゲット配列を作成することで、オーバーフローを心配する必要がなくなります。はい、内部の断片化が少し発生します。アプリケーションによっては、問題になる場合とそうでない場合があります。しかし、私は物事をシンプルに保つのが好きです。

および配列が 0..10 の範囲外の値を保持しないことがわかっている場合は、SIZE を 3 (最大 2 桁と 0 ターミネータ) に設定 できますselectresult

つまり、select[1] には数値 (5) があり、result[0] には数値 (6) があり、result[0] は適切に文字列に変換されますが、select[1] はありません。

何だその行為は!!

結果を保持するのに十分な大きさではないバッファにアドレスを渡したので、動作はundefinedです。つまり、コンパイラは、危険なことをしていることを警告する義務はありません。

これが最も起こりそうなことです (動作は定義されていないため、イベントの順序は任意ですが、これは結果の合理的な解釈だと思います)。まず、変数が次のようにメモリに配置されているとします。

Item        Address        Value
----        -------        -----
str_r       0xffec1230     ??
str_w       0xffec1231     ??
            0xffec1232     ??

str_wstr_r連続するバイトに割り当てられ、初期値は不定です。最初のsnprintf~の後str_w、メモリは次のようになります。

Item        Address        Value
----        -------        -----
str_r       0xffec1230     ??
str_w       0xffec1231     '5'
            0xffec1232     0

snprintf末尾の 0 ターミネータをバッファに書き込みます。この場合、ターミネータを次のバイトに書き込みますstr_w。2 回目のsprintf呼び出しの後、メモリは次のようになります。

Item        Address        Value
----        -------        -----
str_r       0xffec1230     '6'
str_w       0xffec1231     0
            0xffec1232     0

2 番目の呼び出しでは、たまたま;の後にsnprintf続くバイトに 0 ターミネータが書き込まれました。以前に書き込まれた値を壊してしまいました。そのため、文字列は表示されますが、文字列は表示されません。 str_rstr_wstr_rstr_w

于 2013-02-17T15:16:18.553 に答える
0

ではchar、1 バイトの変数のみを定義します。s の配列である必要がありますchar

于 2013-02-17T14:21:00.077 に答える