2017-04-10 10 views
2

前に尋ねられた場合は、事前に謝罪します。見つけられませんでした。C行列の次元が宣言と異なる

これは実用性がほとんどない奇妙なバグです。ここでは、コードは次のとおり

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

void print_matrix(int a[4][3], int i, int j) 
{ 
    printf("a[%d][%d] = %d\n", i, j, a[i][j]); 
    return; 
} 

int main(void) 
{ 
    int i, j; 
    int array[3][5]; 
    for (i = 0; i < 3; i++) 
    { 
     for(j = 0; j < 5; j++) 
     { 
      scanf("%d",&(array[i][j])); 
     } 
    } 
    printf("array[2][1] = %d\n", array[2][1]); 
    print_matrix(array, 2, 1); 
    printf("array[0][4] = %d\n", array[0][4]); 
    print_matrix(array, 0, 4); 
    return 0; 
} 

I [3]、それは奇妙な結果を返す[5] [3]のサイズの行列を宣言し、私は別の関数でこの行列を使用して、サイズとそれを呼び出すとき[4] 。誰かがこのシナリオでメモリにアクセスする方法を説明できますか?

+0

コンパイラから警告があります。すべての警告を有効にしてコンパイルします。 –

+0

関数を 'void print_matrix(int x、int y、int a [x] [y])'に変更するだけです。 Cはサイズがゼロの配列を許可しないことに注意してください。 – Lundin

答えて

2

コードには未定義の動作があるため、何かが起こる可能性があります。関数の最初の引数は、3つの整数の配列へのポインタであるint (*a)[3]であると予想されます。関数のパラメータとしての配列は常にポインタに減衰します。この場合、配列へのポインタです。しかし、arrayを渡すと、5つの整数の配列へのポインタint(*)[5]に減衰します。 C11規格の次のサブセクションによれば

:2つのポインタ型が互換性を持つように

[§6.7.6.1 ¶2]

については、両方が同じ修飾されなければならないとの両方に互換性のタイプへのポインタでなければなりません。 2つの配列のタイプは互換性があるようにするため

[§6.7.6.2 ¶6]

、両方とも互換性のある要素タイプを有するもの、および両方のサイズ指定子が存在し、定数式が整数であれば、両方のサイズ指定子は同じでなければなりません一定値。 2つの配列型が互換性が必要なコンテキストで使用されている場合、は2つのサイズ指定子が等しくない値であると評価された場合、未定義の動作です

ポインタ型は互換性がないため、コンパイラは制限なしで任意のコードを出力できます。コードは意味をなす必要はありません。つまり、未定義の動作の意味です。

しかし、GCC(と確かに他のコンパイラ)は、コードの次の警告を発することができる。

warning: passing argument 1 of 'print_matrix' from incompatible pointer type [-Wincompatible-pointer-types] 

だから常に有効に警告してコンパイルすると、それらに耳を傾けます!


おそらく起きていることは、多次元配列に対して配列アクセスがどのように起こるかを考慮する必要があります。あなたがa[i][j]を書くとき、それは次のように解釈されるように、サイズ3は、配列の定義の一部です:

*(a + i * 3 + j) 

しかし、これはarrayの正しい算術ではない、正しいアクセスが

*(array + i * 5 + j) 
に相当しています

したがって、arrayからaまでは間違ったセルにアクセスします。

関連する問題