1

ユーザーからいくつかの値を読み取り、特定のサイズの配列を作成する必要がある場合、次のようにします。

#include <iostream>
using namespace std;    
unsigned* numbers;
int main()
{
int a;
cin >> a;
numbers = new unsigned[a];
}

2次元配列(ユーザーから読み取ったサイズのa * b)でどうすればよいですか?

4

8 に答える 8

7

a と b がそれぞれ行数と列数の場合、次のように配列を割り当てることができます。

new unsigned[a * b];

i行と列の要素にアクセスするには、次のjようにします。

numbers[i * b + j]

ただし、実際にstd::vectorは、やろうとしていることは何でも使用する方がほぼ確実に優れていることに注意してください。ただし、まだそれについて学んでいない可能性があります:)

于 2013-01-11T10:09:49.033 に答える
6

コード内で 2D 配列のように見えるものはすべて、メモリ内の物理的な 2D 配列ではなく、割り当て方法に応じて、メモリの 1 つのプレーン ブロックまたは散らばった配列になります。

  • nrusselの答えが示唆するように、Nポインタの別の動的配列でN配列の動的割り当てを行うことで、自分を苦しめることができます。
  • billz と Arun CB が示唆するように、代わりにベクトルのベクトルを作成できます。これにより、割り当てられたメモリを自分で管理する必要がなくなりますが、パフォーマンスがあまり良くない N+1 の分散した割り当てが残ります。
  • Brennan Vincent の答えは、a*b 要素を含む 1 つの動的配列の割り当てを提案しています。これにより、メモリ内に 1 つの連続したブロックが得られます。それを彼が言及した組み込みの動的メモリ管理と組み合わせて、std::vector満足してください。

    std::vector<unsigned> matrix(a*b);

マトリックスにアクセスしやすくしたい場合は、すべてをクラスにラップして、2D 座標で要素にアクセスできるようにします。ただし、自分でメモリを管理することから離れてください。それは、あなたとそのコードを維持しなければならない (そしてメモリ リークを探す必要がある) 人を傷つけるだけです。

于 2013-01-11T10:20:49.113 に答える
3

更新された推奨事項:

ブーストがすでにそれを行ったことは注目に値します。したがって、クラスにカプセル化することを意図していない場合は、それに固執します。

元の答え:

一般に、生の配列と割り当てを使用することは、を使用することよりも劣りstd::vectorます。もちろん、を使用することもできますが、vector<vector<T>>入力に時間がかかるだけでなく、不要なコピーが必要になる場合もあります。

ptr_vectorまたはを使用vector<unique_ptr<vector<int>>すると2番目の問題は解決しますが、問題はさらに複雑になります。それで、それをどのように解決するのですか?

簡単です。2D配列はまったく使用しないでください

メモリ内の2D配列を想像してみてください。

[X|X|X|X]
[Y|Y|Y|Y]
[Z|Z|Z|Z]

それを一列に並べることができることは十分に明らかです:

[X|X|X|X|Y|Y|Y|Y|Z|Z|Z|Z]

vectorこれで、古くて馴染みのある1D配列に戻ります(またはCスタイルの配列であるかどうかは関係ありません)。要素に到達するには、最初の配列の幅を知って、n番目の行に対応する配列要素に移動し、列の数を単純に追加する必要があります。

int& access (unsigned x, unsigned y) { 
    return data[x * sizeY + y]; // Or (y * sizeX + x)
}

スタブ方式なので、実際の使用に問題があるかもしれません。グローバル実装の例を次に示します。

int& accessVectorAs2d (std::vector<int> & data, unsigned x, unsigned y, unsigned int sizeY); // inside stays the same
unsigned SizeX = 20, SizeY = 20;
std::vector<int> V (SizeX * SizeY, 0);

accessVectorAs2d(V, 1, 3, SizeX) = 5;

通常の2D配列と非常によく似た方法で1D構造を使用できるようにするために、参照が返されます。

// So you can do either reads
int X = access(1, 3);

// Or writes!
access(1,3) = 5;

追記:独自のクラスを作成する場合、オーバーロードoperator()するとさらに良い結果が得られます。

Data(1, 3) = 5;
int X = Data(1, 3);

ここで、そのアクセスをどのように実装するか(ベクトルをサブクラス化またはカプセル化するか、単純なグローバル関数を使用するか)は実際には重要ではありません。

ここで使用することを強くお勧めしますstd::vector。これにより、メモリがリークする(削除を忘れる)ことがなくなり、サイズを(.push_back()または.reserve()で)変更するのが簡単になり、一般的に推奨される方法です。結局のところ、CではなくC++で書いているのです。

見よ!この後のドラゴン!

実際には、クラスはもちろん、タイプだけでなく、次元の数(わかりました、簡略化できます)と次元のサイズ(-1つごと)(片側で無制限に拡張できるように-1)を使用してテンプレート化する必要があります。これはおそらく、コンパイル時に適切なアクセス関数を作成し、計算することによって最もよく行われます。

Sum i = 0 i <n(サイズii * D i

ここで、nは次元の数、Sは次元サイズの配列、Dは座標の配列です。

于 2013-01-11T10:22:41.673 に答える
3

1 つのベクトルを使用して、2 次元配列を表すことができます。

   typedef std::vector<int>     d1_type;       // 1D
   typedef std::vector<d1_type> d2_type;       // 2D
   typedef std::vector<d2_type> d3_type;       // 3D


   int num = 5;
   d2_type value2d(num, d1_type(num));
   d3_type value3d(num, d2_type(num, d1_type(num)));

また、配列のような 2D/3D ベクトルにアクセスできます。次に例を示します。

 value2d[0][0] = 100;
 value3d[0][0][0] = 100;
于 2013-01-11T10:11:01.773 に答える
2

ベクトルを使用してみてください。

#include <iostream>
#include <vector>
using namespace std;

int main()
{
// An empty vector of vectors. The space 
// between the 2 '>' signs is necessary
vector<vector<int> > v2d;

// If you intend creating many vectors 
// of vectors, the following's tidier
  typedef vector<vector<int> > IntMatrix;
  IntMatrix m;

// Now we'll try to create a 3 by 5 "matrix".
// First, create a vector with 5 elements
   vector<int> v2(5, 99); 

// Now create a vector of 3 elements. 
 // Each element is a copy of v2
 vector<vector<int> > v2d2(3,v2);

// Print out the elements
 for(int i=0;i<v2d2.size(); i++) {
  for (int j=0;j<v2d2[i].size(); j++)
    cout << v2d2[i][j] << " "; 
    cout << endl;
   }
}
于 2013-01-11T10:16:55.067 に答える
1

次の方法でc++new[]を使用してメモリを割り当てることができます。

int** array = new int*[x];
for(int i = 0; i < x; i++)
    aryay[i] = new int[y];

これの単純な概念は、配列を指しているポインタの配列です。メモリリークを回避するためにも削除する必要があります。

于 2013-01-11T10:32:52.657 に答える
1

「ベクトルのベクトル」ソリューションは満足のいくものですが、それらは 2D 構造ではありません。各「行」は互いに独立して割り当てられ、長さは生ごとに異なる可能性があります (したがって、2D 制約は手動で維持する必要があります: 挿入上下にある要素が相対的な位置を維持できるように、アイテムはすべての行を拡大する必要があります。

適切な動的 2D 構造が必要な場合は、ベクトル (単純な 1 次元) をクラス (" table" と呼びましょう) でラップし、そのクラスに、外部表現された 2D として適切に維持するために必要な操作を提供できます。特に:

  • テーブルの実際のサイズを返す関数を定義Colums() constします。Rows() const
  • int& operator()(unsigned row, unsigned col) { return vect[row*Colums()+col]; }aとその対応する constを定義する
  • struct coord { unsigned r, unsigned c }aと便利な a を定義するtable::operator[](const coord&)
  • 行を挿入するメソッド ( に連続する要素を挿入するだけ) と列を挿入するメソッド (から始まる要素を 1 つ挿入する)を定義insertします。removeColums()r*Columns()Columns()+1c
  • 列 (++ は 1 要素ずつ進む) と行 (++ は列 (Colums() 要素) ずつ進む) に沿って移動する適切な反復子クラスを定義します (end()それらの値を一貫して定義するように注意してください) 。

これらすべての重要なポイントはn = r*C+c、2 番目のポイントで式を理解することです。他のすべては、ほとんど即時の結果にすぎません。

于 2013-01-11T10:42:04.260 に答える
0
unsigned **numbers;
numbers = new unsigned*[a];
for (int i=0; i<a; i++){
    numbers[i] = new unsigned[b];
}

メモリ内で連続していないという点で、2次元配列とまったく同じようには動作しませんが、動作します。表記numbers[i][j]を使用して要素にアクセスすることもできます。

-ing自体の前に、最後にdelete[]の各要素を覚えておいてくださいnumbersdelete[]numbers

std::vector他の投稿で詳しく説明されているように、使用はおそらく好ましい解決策です

于 2013-01-11T10:08:36.787 に答える