3

ここに私のC ++のコードがあります

int** a;
try{
  a = new int*[m];
  for(int i = 0; i<m;i++)
    a[i] = new int[n];
}

... 現在、次のように for ループを使用して上記を初期化しています。

for(int i = 0; i<m; i++)
  for(int j = 0; i<n; j++)
      a[i][j] = 0;

私はパフォーマンスを改善しようとしているので、 memset を使用することをお勧めします。したがって、次のように for ループの代わりに memset を使用するようにコードを変更しました。

memset(a, 0, sizeof(a[0][0]) * m * n);

しかし、これを実行するとセグメンテーション違反が発生します。私が間違っていることを理解するのを手伝ってくれる人はいますか?

4

5 に答える 5

4
int** a;

これにより、単一のオブジェクトが得られます。int**オブジェクト。まったくどこにも当てはまりません。int割り当てるがありません。s が存在するかのように s に割り当て始めると、int未定義の動作が発生します。

さらに、s の「2 次元配列」を指す のメモリ レイアウトは、s のint**配列の最初の要素をポイントし、s は s の配列の最初の要素をポイントします。このメモリは連続していません。これは、メモリをジャンプするために間接的な処理が必要なためです。つまり、単一のメモリ ブロックではありません。を使用して書き込むことはできません。intint**int*int*intmemset

コンパイル時の固定サイズのints の 2D 配列が必要な場合は、次のようにします。

int a[N][M];

NM定数式です。これ連続して保存されますが、それでも使用はお勧めしませんmemset

または、次のような標準コンテナを使用します。

std::array<std::array<int, M>, N> a;

動的サイズが必要な場合は、次を試してください。

std::vector<std::vector<int>> a(M, std::vector<int>(N));

別の方法として、独自のs とsint**を動的に割り当てるようにすることもできます。int*int

int** a = new int*[M];
for (i = 0; i < N; i++) {
  a[i] = new int[N];
}

しかし、これは醜いです!

于 2013-03-22T18:59:57.177 に答える
3
int** a;

へのポインタへのポインタの単なる宣言ですint

「今、for ループを使用して上記を初期化しています」

ループで初期化していません。存在しない要素forに割り当てようとしているだけで、未定義の動作が発生します。これらの要素にメモリを動的に割り当てるか、さらに良い方法で、代わりに次を使用する必要があります。0std::vector

std::vector< std::vector<int> > a(m, std::vector<int>(n, 0));

「パフォーマンスを上げたい」

必要でない限り、これを行わないでください。時期尚早に最適化しないでください。


EDIT:すでにパフォーマンスの問題に直面していると述べた後、次のことができます:この2次元のCスタイル配列の代わりに:

int** a = new int*[m];      // m = number of rows
for(int i = 0; i < m; i++)
    a[i] = new int[n];      // n = number of columns

一次元を使用できますstd::vector

std::vector<int> vec(rows * cols, 0);
...
vec[i * cols + j] = 7;   // equivalent of vec[i][j]
これにはより多くの利点があります。
  • 2D 配列は、メモリの連続ブロック内に格納されます
  • このメモリ ブロックは一度に割り当てられます。多くの小さな断片ではありません。
  • 要素への頻繁なアクセスは、空間的局所性のおかげで高速になります
    (「近い」要素はキャッシュ メモリで使用できるため、
    プログラムはそれらをメイン メモリからロードする必要がありません)。
  • また、メモリ管理については責任を負いません(オブジェクトが破棄されると、
    メモリは自動的にクリーンアップされます)。vector
于 2013-03-22T19:01:10.337 に答える
1

を使用するint **と、通常、単一の連続したメモリ ブロックはありません。正しく使用すると仮定すると、ポインターの配列が得られます。これらの各ポインターには、個別に割り当てられた配列があります。

その場合、ループを単一に変換することはできませんmemset(それでも定義された動作を取得できます)。

于 2013-03-22T19:00:11.027 に答える
0

問題は、実際のストレージに割り当てられていないメモリにあると思います。変数aはポインタのみです (さらに初期化されていません)。どこを指す?

于 2013-03-22T19:00:15.833 に答える
0

あなたはそれを次のように割り当てたと言いました:

a = new int*[m]; 
for(int i =0; i<m ;i++) a[i] = new int[n];

Jerry Conffin が言ったように、これは単一の連続したメモリブロックを提供しません。新しい配列 ( new int[n]) はそれぞれ、まったく異なる場所に割り当てられる可能性があり、memset は連続したブロックでのみ機能するため、それぞれを「手動で」リセットする必要があります。ループ上で memset を使用することによる改善 (memset 自体は、ループを使用して実装されていると思います)。

于 2013-03-22T19:08:14.547 に答える