2016-04-11 20 views
1

私はこのコードが間違っている理由を見つける作業があります。それがあることを私に語ったvalgrindのを使用することによりCの次のコードで何が問題なのかを理解しようとしています

#include <stdlib.h> 
#include <stdio.h> 

#define fail(a)   ((test == 0 || test == a) ? fail##a() : 0) 
#define N    (10) 

int a[N] = { 1 }; 
int* b = &a[0]; 


void fail1() 

{ 
    printf("a[0] = %d\n", a[0]); 
    printf("b[0] = %d\n", b[0]); 
    printf("*b = %d\n", *b); 
    *b = 2; 
    a[N] = 3; 
    printf("*b = %d\n", *b); 

} 

... 

int main(int argc, char **argv) 
{ 
    int  test = 0; 

    if (argc > 1) { 
      sscanf(argv[1], "%d", &test); 
      printf("doing test %d\n", test); 
    } else 
      puts("doing all tests"); 

    fail(1); 
    fail(2); 
    fail(3); 
    fail(4); 
    fail(5); 
    fail(6); 

    puts("lab6 reached the end"); 

    exit(0); 
} 

printf("*b = %d\n", *b);に失敗します。私はコメントによってそれに気づいたa[N] = 3; valvgrindはエラーを出さない。しかし、なぜ私は理解していない。私はこれがメモリと関係があり、a[N]は配列外の要素を要求することを知っています。

+1

'main()'がないためですか? –

+0

まあ、それを含めるべきでしょう、編集を見てください。 – Olba12

答えて

5

C配列には0から始まるインデックスがあります。 a[N]のように定義された配列の場合、有効な最大要素はa[N-1]になります。

a[N]は、範囲外のメモリを指します。バインドされていないメモリにアクセスしようとすると、undefined behaviorが呼び出されます。

あなたは上記の事実を知っているかもしれませんが、あなたがUBの影響で無視したことがあるかもしれません。 UBにヒットしたら、何も保証されません。簡単な解決策は、UBを呼び出すことができるコードを記述しないでください。

+0

はい、私はそれを理解していますが、なぜprintf( "* b =%d \ n"、* b); * b = 2を印刷するには?代わりに* b = 1を出力します。 – Olba12

+0

@ Olba12答えとリンクされたWikiポストを読み直すことをお勧めします。 –

+1

申し訳ありませんが、私は実際にリンクを逃しました。 (フォーラムで初めて)。これは役に立ちました。 – Olba12

4

アレイインデックスは0から始まるため、aの最後のインデックスはN-1ではなく、Nです。 a[N]に書き込むと、配列の一部ではないメモリにアクセスしているため、undefined behaviorが発生します。

2

は、C [N]にチェック何アレイ境界がない[0] .. [N-1]

あなたが読み取り場合、または外部書き込みである配列の終わりを過ぎています配列の境界、あなたはランダムな結果を得る(人々はUB "最近定義されていない動作"と呼んでいる)。これは、あなたがあなたがa[outside] = x;

  • 書く

を期待する値を取得

  • ランダムな値を取得する

    x = a[outside];

    • を読み取るコードが
    • をクラッシュする可能性がありコードがクラッシュする
    • 書き込みが行われますが、読み込み中に値が変更されました。
    • 書き込みが行われ、それを読み取ることはOKです(つまり、何も起こりません)。
    • 書き込みは実行されますが、コードの他の部分でクラッシュします。

    例では、[]がcharの配列であるとします。

    a[0] | a[1] | ... | a[N-1] | s[0] | s[1] | s[2] | s[3] | s[4] | s[5] 
        1 | 0 |  | 7  | 'H' | 'e' | 'l' | 'l' | '0' | 0 
    

    [N]に書き込むと、配列は変更されず、代わりに別の変数(この場合は文字列の一部)が上書きされます。あなたは混乱の原因となるプログラムのメモリを破壊します。この例では

    a[N] = 255;     /*bug*/ 
    
        a[0] | a[1] | ... | a[N-1] | s[0] | s[1] | s[2] | s[3] | s[4] | s[5] 
        1 | 0 |  | 7  | 255 | 'e' | 'l' | 'l' | '0' | 0 
    

    、読み、[N]を書き込むと、動作しているように見えますが、それは(「こんにちは」と言うために使用されるが、今doesntの)別の文字列変数を破損しました。これにより、後でバグが発生する可能性があります。

    Cでプログラミングする場合は、非常に注意し、訓練する必要があります。

  • 関連する問題