質問
コマンドライン引数を文字配列に渡す2つの方法を見つけました:
int main (int argc, char **argv)
{
const char *s1 = argv[0];
char s2[256];
strcpy(s2, argv[0]);
printf("s1: %s\ns2: %s\n\n", s1, s2);
}
AIXシステム上のIBM xlcコンパイラーでコンパイル
[MyPrompt] <!> gt; ./a.out
s1:./a.out
s2:./a.out
どの実装(s1またはs2)が正しいですか? argv [0]は任意の長さにできるため、s1は便利です。 s2では、argv [0] <!> lt;の長さが必要です。 256文字。
s1の動作方法/理由を理解できません。コンパイル時にはs1の右側を考える必要がありますが、実行時に生成される考える。
解決
s1が機能する理由は、argv [0]のタイプが ポインターであるためです。単にアドレスを割り当てているだけで(実際の値ではなく)、安全です。いかなる種類の割り当てやキャストも実行していません。
通常、最初のオプションを好むのは、引数変数からのみ読み取る必要があるためです。
他のヒント
文字列を変更したくない場合は、s1が機能します。
文字列を変更する場合は、そのコピーを作成できます。システムでサポートされている場合でも、より安全なstrnlen()およびstrncpy()を使用する必要があります。
s1の右側を考える コンパイル時に必要になるはずです。 しかし、私はそれがで生成されると思います 実行時。
いいえ、ステートメントが検出されるたびに必要です。例:
void f() {
int x = 1;
...
}
整数xは、コンパイル時ではなく、関数が呼び出されるたびに1に初期化されます。
s2には、バッファーオーバーランの影響を受けやすいという優れた特性があります。
人々がargv [0]の値を変更するのを見てきました。場合によっては、(一部のOSでは)argv [0]を変更すると、変更したものとしてプログラムがpsに表示されます。
引数を変更せずに参照する場合は、 s1 が正しいです。
引数を何らかの方法で変更する必要がある場合は、 s2 の例のように引数のコピーを作成する必要がありますが、 s2 の例では、長さがコピー先のバッファより長いかどうかを確認します。たとえば、入力としてfilename.jpgのような引数を取り、出力としてfilename.gifを保存する場合、拡張子を.jpgから.gifに変更するため、その引数のコピーを作成する必要があります
特にargv [n]の場合、n <!> gt;でs1を使用します。 0. s2のようなものは、古典的なバッファオーバーフロー攻撃の可能性を開きます。基本的に、ユーザーは長さが256文字を超える引数をフォーマットし、スタック上の情報を上書きして、必要なコードを実行できます。