-1

私は動作する単純な入力機能を持っています:

int main(void)
{
    char *first;
    char *last;

    scanf("%s", first);

    printf("%s", last);

    return 1;
}

しかし、作業を拡張して単純なカウンターを配置すると、プログラムがクラッシュします。

int main(void)
{
    int i = 0;
    char *first;
    char *last;

    scanf("%s", first);

    printf("%s", last);

    return 1;
}

何か案が ?

4

4 に答える 4

2
char *first;

scanf("%s", first);

firstは呼び出す前に初期化されていませんscanf: 呼び出し前の値は無効なアドレスです。

于 2013-06-24T17:36:04.717 に答える
1

問題は、firstポインタ変数が初期化されていないことです。つまり、ポインタが任意の値を持ち、メモリ内の任意の場所を指している可能性があります。

運が良ければ、未使用の割り当てられたメモリを指すことになるため、文字列の読み取りはたまたま機能します。

運が良ければ、マップされていないアドレスを指すことになるため、文字列を読み取るとセグメンテーション違反が発生します。

運が悪ければ、何か他のものを保持する有効なメモリを指してしまうため、機能しているように見えますが、他のデータ (またはコード) を上書きし、デバッグが困難な不可解なクラッシュ、誤った結果、またはセキュリティ ホールを引き起こします。


追加int i = 0;しても、「サイコロを再ロールする」ことを除いて、実際には何も変わりません。また、たとえばコンパイラ フラグを変更することによって、異なる結果を得ることができます (特に、デバッグ機能または最適化機能をオンまたはオフにした場合)。


mainたとえば、関数に入ると、スタックが割り当てられる領域は次のようになります。

pointer to return address in the middle of libc
pointer to data segment
0

コードの最初のバージョンでは、何も初期化せずfirst、データ セグメントへのポインターの値を継承することになるため、データ セグメントへのスキャンが機能します。2 番目のバージョンでiは、データ セグメントへのポインターを継承する (そして で上書きする0)ことになり、値をfirst継承する0ことになるため、セグメンテーション違反が発生します。


実際に何が起こっているのかを確認したい場合は、-Sフラグ (またはコンパイラの同等のもの)によって生成されたアセンブリをprintf("%p\n", first)確認するか、取得したアドレスを確認して、そこにマップされているものを把握することができます。

しかし、実際には、なぜ機能しないかは問題ではありません。動作するはずがありません。唯一の解決策は、ポインターを有効なものに適切に初期化することです(ouahの回答と他の人が説明しているように)。

于 2013-06-24T17:49:39.720 に答える