Bagaimana cara mendeklarasikan array 2d di C ++ menggunakan yang baru?

527

Bagaimana cara mendeklarasikan array 2d menggunakan yang baru?

Seperti, untuk array "normal" saya akan:

int* ary = new int[Size]

tapi

int** ary = new int[sizeY][sizeX]

a) tidak berfungsi / dikompilasi dan b) tidak mencapai apa:

int ary[sizeY][sizeX] 

tidak.

pengguna20844
sumber
60
Ini hanya berfungsi jika sizeX konstan: int (* ary) [sizeX] = new int [sizeY] [sizeX]; Yang merupakan cara yang tepat untuk membuat int [sizeY] [sizeX] dan di mana semua memori berdekatan. (Saya tidak berpikir ini layak jawaban, karena mungkin sizeX Anda tidak konstan
Johannes Schaub - litb
23
Saya tidak dapat percaya bahwa selusin jawaban di bawah ini semuanya salah dan tidak menjawab pertanyaan, namun semuanya dijungkirbalikkan. Komentar di atas oleh Johanes Shaub adalah satu-satunya jawaban yang benar untuk pertanyaan itu . Array 2D dan array pointer ke array adalah dua hal yang benar-benar terpisah, yang tampaknya digabungkan oleh semua orang.
Bregalad
6
@ JohannesSchaub-litb: Itu tidak 100% benar. Tentu saja itu berfungsi dalam kasus itu, tetapi ada metode untuk membuatnya bekerja di mana semua dimensi berbeda, lihat stackoverflow.com/a/29375830/103167
Ben Voigt

Jawaban:

749

Array 2D dinamis pada dasarnya adalah array pointer ke array . Anda dapat menginisialisasi menggunakan loop, seperti ini:

int** a = new int*[rowCount];
for(int i = 0; i < rowCount; ++i)
    a[i] = new int[colCount];

Di atas, untuk colCount= 5dan rowCount = 4, akan menghasilkan yang berikut:

masukkan deskripsi gambar di sini

Mehrdad Afshari
sumber
143
Ingatlah bahwa apa pun yang dialokasikan dengan newdibuat pada heap dan harus de-dialokasikan dengan delete, ingatlah ini dan pastikan untuk menghapus memori ini dari tumpukan ketika Anda sudah selesai dengan itu untuk mencegah kebocoran.
Kekoa
83
Perhatikan juga bahwa ini adalah array pointer. bukan dari array. Pointer pada gilirannya menunjuk ke array. Penting untuk benar-benar memperbaiki persyaratan, karena banyak tutorial yang salah juga. Array array akan bersebelahan, yang ini bukan
Johannes Schaub - litb
4
Ya, T [] [N] akan disebut "larik array [N] dari T" dan menjadi tipe yang tidak lengkap, sedangkan T [] [] akan menjadi tipe yang tidak valid (semua kecuali dimensi terakhir harus memiliki ukuran yang diketahui. ). T [N] [M] adalah "array [N] dari array [M] dari T", sedangkan milik Anda, T [sizeX] adalah "array [sizeX] dari T" di mana T adalah penunjuk ke int. Membuat array 2d yang dinamis bekerja seperti ini: new int [X] [Y]. Ini akan membuat larik tipe [X] [Y] yang dialokasikan. Ini adalah "lubang" dalam sistem tipe C ++, karena sistem tipe biasa C ++ tidak memiliki dimensi array dengan ukuran yang tidak diketahui pada waktu kompilasi, dengan demikian ini disebut "tipe yang dialokasikan"
Johannes Schaub - litb
34
Ya Tuhan, ini benar-benar sampah, ini benar-benar salah. Ini bukan array 2D. "Array 2D dinamis pada dasarnya adalah array pointer ke array." - Tidaaaak, SL! T (*ptr)[M] = new T[N][M];adalah solusi yang tepat ... Tidak ada jumlah array-of-pointer yang akan sama dengan array-of-array ...
The Paramagnetic Croissant
7
@TheParamagneticCroissant Anda bisa berpendapat ini bukan array 2D. Itu benar. Itu bisa diindeks seperti array 2D, tetapi itu bukan array 2D. Tata letak memori sebenarnya digambarkan dalam gambar. Masalah dengan pernyataan itu adalah gagal berfungsi jika M tidak konstan.
Mehrdad Afshari
300
int** ary = new int[sizeY][sizeX]

seharusnya:

int **ary = new int*[sizeY];
for(int i = 0; i < sizeY; ++i) {
    ary[i] = new int[sizeX];
}

dan kemudian membersihkannya adalah:

for(int i = 0; i < sizeY; ++i) {
    delete [] ary[i];
}
delete [] ary;

EDIT: seperti yang ditunjukkan Dietrich Epp dalam komentar ini bukan solusi yang ringan. Pendekatan alternatif adalah dengan menggunakan satu blok memori besar:

int *ary = new int[sizeX*sizeY];

// ary[i][j] is then rewritten as
ary[i*sizeY+j]
Kevin Loney
sumber
56
Beratnya sedikit lebih berat daripada yang seharusnya, dan itu mengalokasikan lebih banyak blok daripada yang Anda butuhkan. Array multidimensi hanya membutuhkan satu blok memori, tidak perlu satu blok per baris. Mengalokasikan hanya satu blok membuat pembersihan juga lebih mudah.
Dietrich Epp
11
@Kevin: Mengalokasikan hanya satu blok yang berdekatan adalah cara yang harus dilakukan (dampak yang lebih kecil pada pengalokasi, lokalitas yang lebih baik, dll). Tetapi Anda tidak harus mengorbankan subskrip bersih. Lihat stackoverflow.com/a/29375830/103167
Ben Voigt
9
Bukankah seharusnya begitu i*sizeX+j? Jika saya ingat dengan benar, dengan pemesanan baris utama harus baris * numColumns + col.
arao6
2
hm, pemikiran yang bagus, memang itu hanya masalah representasi - sisanya adalah perspektif. pintar
Miro Rodozov
1
@ Borna: Secara umum menggunakan array 2D tunggal akan lebih cepat dari array array. Mengikuti dua petunjuk dapat menyebabkan warung pipa. Seperti biasa, itu tergantung pada pola akses.
Dietrich Epp
211

Meskipun jawaban populer ini akan memberikan Anda sintaks pengindeksan yang Anda inginkan, ini sangat tidak efisien: besar dan lambat dalam ruang dan waktu. Ada cara yang lebih baik.

Mengapa Jawaban Itu Besar dan Lambat

Solusi yang diusulkan adalah membuat array dinamis dari pointer, kemudian menginisialisasi setiap pointer ke array dinamisnya sendiri. The Keuntungan dari pendekatan ini adalah bahwa hal itu memberi Anda sintaks pengindeksan Anda terbiasa, jadi jika Anda ingin mencari nilai matriks pada posisi x, y, Anda mengatakan:

int val = matrix[ x ][ y ];

Ini berfungsi karena matriks [x] mengembalikan pointer ke array, yang kemudian diindeks dengan [y]. Hancurkan:

int* row = matrix[ x ];
int  val = row[ y ];

Nyaman ya Kami menyukai sintaks [x] [y] kami.

Tetapi solusinya memiliki kelemahan besar , yaitu bahwa ia gemuk dan lambat.

Mengapa?

Alasan mengapa keduanya gemuk dan lambat sebenarnya sama. Setiap "baris" dalam matriks adalah array dinamis yang dialokasikan secara terpisah. Membuat alokasi tumpukan mahal dalam waktu dan ruang. Pengalokasi membutuhkan waktu untuk membuat alokasi, terkadang menjalankan algoritma O (n) untuk melakukannya. Dan pengalokasi "bantalan" masing-masing array baris Anda dengan byte tambahan untuk pembukuan dan perataan. Biaya ruang ekstra itu ... well ... ruang ekstra. Deallocator juga akan membutuhkan waktu ekstra saat Anda melakukan deallocate matriks, dengan susah payah membebaskan setiap alokasi baris individu. Membuatku berkeringat hanya memikirkannya.

Ada alasan lain mengapa ini lambat. Alokasi yang terpisah ini cenderung hidup dalam bagian memori yang terputus-putus. Satu baris mungkin di alamat 1.000, yang lain di alamat 100.000 — Anda mendapatkan ide. Ini berarti bahwa ketika Anda melintasi matriks, Anda melompati memori seperti orang liar. Hal ini cenderung menyebabkan kesalahan cache yang sangat memperlambat waktu pemrosesan Anda.

Jadi, jika Anda mutlak harus memiliki sintaks pengindeksan [x] [y] imut Anda, gunakan solusi itu. Jika Anda ingin cepat dan kecil (dan jika Anda tidak peduli tentang itu, mengapa Anda bekerja di C ++?), Anda memerlukan solusi yang berbeda.

Solusi yang Berbeda

Solusi yang lebih baik adalah dengan mengalokasikan seluruh matriks Anda sebagai array dinamis tunggal, kemudian gunakan (sedikit) matematika pengindeksan Anda sendiri untuk mengakses sel. Matematika pengindeksan hanya sedikit sangat pintar; nah, sama sekali tidak pintar: sudah jelas.

class Matrix
{
    ...
    size_t index( int x, int y ) const { return x + m_width * y; }
};

Dengan index()fungsi ini (yang saya bayangkan adalah anggota kelas karena perlu mengetahui m_widthmatriks Anda), Anda dapat mengakses sel dalam array matriks Anda. Array matriks dialokasikan seperti ini:

array = new int[ width * height ];

Jadi, ini setara dengan solusi lambat dan gemuk:

array[ x ][ y ]

... apakah ini dalam solusi cepat, kecil:

array[ index( x, y )]

Sedih, saya tahu. Tetapi Anda akan terbiasa dengan hal itu. Dan CPU Anda akan berterima kasih.

OldPeculier
sumber
5
@ Nooe, saya semacam membuat sketsa solusi tanpa meresepkan yang tertentu. Lebih detail mungkin terlihat seperti: class Matrix { int* array; int m_width; public: Matrix( int w, int h ) : m_width( w ), array( new int[ w * h ] ) {} ~Matrix() { delete[] array; } int at( int x, int y ) const { return array[ index( x, y ) ]; } protected: int index( int x, int y ) const { return x + m_width * y; } };Jika Anda meluruskan kode itu mungkin masuk akal, dan mungkin menjelaskan jawaban di atas.
OldPeculier
4
Saya suka solusi ini, apakah itu berlaku untuk array 3 dimensi juga? Saya sedang memikirkan sesuatu seperti ini: (x + m_width * y) + (m_width * m_height * z)
Ulrar
3
Masalah utama dengan solusi ini adalah bahwa ada perhitungan tambahan untuk setiap indeks. Ini menjadi lebih buruk jika Anda menempatkan perhitungan indeks dalam suatu fungsi yang menambahkan overhead tambahan. Setidaknya, pertimbangkan untuk menggunakan fungsi makro atau inline untuk mengurangi overhead. Contoh makro untuk C ++: #define ROW_COL_TO_INDEX(row, col, num_cols) (row*num_cols + col)Kemudian Anda dapat menggunakannya sebagai int COLS = 4; A[ ROW_COL_TO_INDEX(r, c, COLS) ] = 75; overhead benar-benar mempengaruhi ketika kita melakukan perkalian matriks yang kompleksitas O (n ^ 3) atau O (n ^ 2.81) untuk algoritma Strassen .
Ash Ketchum
5
@AshKetchum Inlining (atau mungkin substitusi makro) masuk akal untuk dioptimalkan, tetapi bagaimana perhitungan yang dikompilasi lebih kompleks daripada apa yang perlu dilakukan untuk menyelesaikan alamat [x] [y]?
Dronz
1
@Dronz Dengan a[x][y], apa yang sebenarnya Anda lakukan adalah *(*(a + x) + y): dua tambahan dan dua pengambilan memori. Dengan a[index(x, y)], apa yang sebenarnya Anda lakukan adalah *(a + x + w*y): dua tambahan, satu perkalian, dan satu pengambilan memori. Yang terakhir sering lebih disukai, karena alasan-alasan yang terungkap dalam jawaban ini (yaitu, perdagangan memori tambahan yang diambil dengan perkalian adalah sepadan, terutama karena data tidak terfragmentasi dan oleh karena itu Anda tidak ketinggalan cache).
Boris Dalstein
118

Dalam C ++ 11 dimungkinkan:

auto array = new double[M][N]; 

Dengan cara ini, memori tidak diinisialisasi. Untuk menginisialisasi, lakukan ini sebagai gantinya:

auto array = new double[M][N]();

Program sampel (kompilasi dengan "g ++ -std = c ++ 11"):

#include <iostream>
#include <utility>
#include <type_traits>
#include <typeinfo>
#include <cxxabi.h>
using namespace std;

int main()
{
    const auto M = 2;
    const auto N = 2;

    // allocate (no initializatoin)
    auto array = new double[M][N];

    // pollute the memory
    array[0][0] = 2;
    array[1][0] = 3;
    array[0][1] = 4;
    array[1][1] = 5;

    // re-allocate, probably will fetch the same memory block (not portable)
    delete[] array;
    array = new double[M][N];

    // show that memory is not initialized
    for(int r = 0; r < M; r++)
    {
        for(int c = 0; c < N; c++)
            cout << array[r][c] << " ";
        cout << endl;
    }
    cout << endl;

    delete[] array;

    // the proper way to zero-initialize the array
    array = new double[M][N]();

    // show the memory is initialized
    for(int r = 0; r < M; r++)
    {
        for(int c = 0; c < N; c++)
            cout << array[r][c] << " ";
        cout << endl;
    }

    int info;
    cout << abi::__cxa_demangle(typeid(array).name(),0,0,&info) << endl;

    return 0;
}

Keluaran:

2 4 
3 5 

0 0 
0 0 
double (*) [2]
Mohammad Alaggan
sumber
3
Saya perlu melakukan ini di kelas, maka saya tidak dapat menggunakan otomatis. Apa yang akan menjadi tipe yang tepat untuk array?
Peter Smit
3
Bisakah Anda menggunakan ini:using arr2d = double(*)[2]; arr2d array = new double[M][N];
Mohammad Alaggan
3
+1: inilah yang diminta OP. Jenis yang tepat untuk ini adalah salah satu double (*)[M][N]atau double(*)[][N]dengan M, N menjadi ekspresi konstan.
Fozi
58
Masalah dengan solusi ini adalah bahwa dimensi tidak bisa menjadi nilai run-time, tetapi harus diketahui pada waktu kompilasi.
legends2k
4
@vsoftco Ya, memang , namun pertanyaannya adalah secara khusus tentang memiliki kedua dimensi yang tidak diketahui pada saat kompilasi.
legends2k
58

Saya kira dari contoh array statis Anda bahwa Anda ingin array persegi panjang, dan bukan yang bergerigi. Anda dapat menggunakan yang berikut ini:

int *ary = new int[sizeX * sizeY];

Kemudian Anda dapat mengakses elemen sebagai:

ary[y*sizeX + x]

Jangan lupa untuk menggunakan delete [] pada ary .

Isvara
sumber
1
Ini cara yang baik untuk melakukannya. Anda juga dapat melakukan vektor <int> dengan ukuran sizeX * sizeY untuk keamanan ekstra yang bagus.
Dietrich Epp
4
Yang terbaik adalah membungkus kode ini dalam sebuah kelas - Anda dapat melakukan pembersihan dalam destruktor dan Anda dapat mengimplementasikan metode get (x, y) dan set (x, y, val) daripada memaksa pengguna untuk melakukan perkalian dengan dirinya sendiri . Operator pelaksana [] lebih rumit, tapi saya percaya itu mungkin.
Tadeusz Kopec
47

Ada dua teknik umum yang saya sarankan untuk ini di C ++ 11 dan di atas, satu untuk kompilasi dimensi waktu dan satu untuk run time. Kedua jawaban mengasumsikan Anda menginginkan array dua dimensi yang seragam (bukan yang bergerigi).

Kompilasi dimensi waktu

Gunakan std::arraydari std::arraydan kemudian menggunakan newuntuk meletakkannya di heap:

// the alias helps cut down on the noise:
using grid = std::array<std::array<int, sizeX>, sizeY>;
grid * ary = new grid;

Sekali lagi, ini hanya berfungsi jika ukuran dimensi diketahui pada waktu kompilasi.

Jalankan dimensi waktu

Cara terbaik untuk mencapai array 2 dimensi dengan ukuran yang hanya diketahui saat runtime adalah membungkusnya menjadi sebuah kelas. Kelas akan mengalokasikan array 1d dan kemudian membebani operator []untuk menyediakan pengindeksan untuk dimensi pertama. Ini berfungsi karena di C ++ array 2D adalah baris-utama:

 Matriks ditampilkan dalam bentuk logis dan bentuk satu dimensi

(Diambil dari http://eli.thegreenplace.net/2015/memory-layout-of-multi-dimensional-arrays/ )

Urutan memori yang berdekatan baik untuk alasan kinerja dan juga mudah dibersihkan. Berikut ini adalah contoh kelas yang menghilangkan banyak metode berguna tetapi menunjukkan ide dasarnya:

#include <memory>

class Grid {
  size_t _rows;
  size_t _columns;
  std::unique_ptr<int[]> data;

public:
  Grid(size_t rows, size_t columns)
      : _rows{rows},
        _columns{columns},
        data{std::make_unique<int[]>(rows * columns)} {}

  size_t rows() const { return _rows; }

  size_t columns() const { return _columns; }

  int *operator[](size_t row) { return row * _columns + data.get(); }

  int &operator()(size_t row, size_t column) {
    return data[row * _columns + column];
  }
}

Jadi kami membuat array dengan std::make_unique<int[]>(rows * columns)entri. Kami membebani operator []yang akan mengindeks baris untuk kami. Ini mengembalikan int *yang menunjuk ke awal baris, yang kemudian dapat dereferensi sebagai normal untuk kolom. Catat itumake_unique pengiriman pertama dalam C ++ 14 tetapi Anda dapat polyfill dalam C ++ 11 jika perlu.

Ini juga umum untuk tipe struktur ini untuk kelebihan beban operator()juga:

  int &operator()(size_t row, size_t column) {
    return data[row * _columns + column];
  }

Secara teknis saya belum pernah menggunakan di newsini, tapi sepele untuk pindah dari std::unique_ptr<int[]>ke int *dan menggunakan new/ delete.

Levi Morrison
sumber
apakah mungkin untuk membuat parameter templat baris dan kolom?
Janus Troelsen
1
Jika Anda mengetahui dimensi pada waktu kompilasi (yang Anda lakukan jika Anda menggunakan parameter template) maka saya sarankan menggunakan std::arraydari std::arrays: std::array<std::array<int, columns> rows>.
Levi Morrison
1
Bolehkah saya mengatakan ini adalah jawaban canggih / modern dengan filosofi di bawahnya sangat mirip dengan (lebih sederhana, dalam hal LOC dan konsep) jawaban yang diberikan oleh @kamshi?
KcFnMi
Mereka cukup sebanding sehubungan dengan teknik yang mendasarinya: ada array tunggal yang menampung semua nilai di semua dimensi. Lalu, entah bagaimana kembalikan pointer ke awal setiap baris. Dalam praktiknya, kelas biasanya akan memiliki metode yang lebih bermanfaat, mungkin memiliki copy constructor dan operator penugasan copy, memiliki assertsuntuk debug membangun untuk memverifikasi akses memori, dll. Penambahan ini umumnya membuatnya lebih mudah dan lebih baik untuk bekerja dengan.
Levi Morrison
1
Juga, @KcFnMi, jika Anda memutuskan untuk menggunakan jawaban kamshi maka pastikan untuk membaca komentar Ben tentang menggunakan make_uniquealih-alih new/delete.
Levi Morrison
31

Pertanyaan ini mengganggu saya - itu adalah masalah yang cukup umum bahwa solusi yang baik seharusnya sudah ada, sesuatu yang lebih baik daripada vektor vektor atau menggulung pengindeksan array Anda sendiri.

Ketika sesuatu seharusnya ada di C ++ tetapi tidak, tempat pertama untuk melihatnya adalah boost.org . Di sana saya menemukan Boost Multidimensional Array Librarymulti_array ,. Bahkan termasuk multi_array_refkelas yang dapat digunakan untuk membungkus buffer array satu dimensi Anda sendiri.

Mark tebusan
sumber
5
Saya mengerti argumen Anda, saya pribadi tidak mengerti mengapa itu harus sangat sulit, jujur ​​ini adalah alasan mengapa kami kehilangan begitu banyak programmer ke Jawa, itu hanya bekerja di luar kotak! Ini adalah fitur dasar yang membuat c ++ guys kehilangan waktu!
Oliver
Saya mungkin hanya menambahkan, saya menemukan ini solusi terbaik tetapi saya kira untuk beberapa orang perlu banyak otak untuk memahami semua langkah, terutama untuk pemula ...;)! Saya melihat 80% dari programmer C ++ gagal ketika mereka melihat hal-hal yang diketikkan.
Oliver
1
@OliverStutz itulah bahaya menjadi yang pertama. Standar C ++ terbaru telah berusaha mati-matian untuk membuat hal-hal yang kurang memberatkan, favorit saya adalah autokata kunci. Saya terkejut mereka belum mencoba menangani array 2D, terutama karena Boost sudah menunjukkan caranya.
Mark Ransom
itu lucu bagaimana seluruh otomatisasi pengembangan tertidur. Sekarang satu-satunya keuntungan mudah adalah java. Saya benar-benar ingin c ++ untuk melakukan lompatan, sudah menjadi bahasa yang kuat dan kuat sejak saat itu ... mengapa memiliki lightsaber jika Anda tidak menggunakannya!
Oliver
2
Apa yang lebih menggangguku adalah seberapa jauh C ++ berada di belakang C dalam hal ini: C99 memungkinkan untuk array multidimensi nyata yang dialokasikan pada heap dengan dimensi yang ditentukan pada saat run time, dan C ++ 17 masih belum mendekati apa yang memungkinkan C99 ...
cmaster - mengembalikan monica
27

Mengapa tidak menggunakan STL: vektor? Sangat mudah, dan Anda tidak perlu menghapus vektor.

int rows = 100;
int cols = 200;
vector< vector<int> > f(rows, vector<int>(cols));
f[rows - 1][cols - 1] = 0; // use it like arrays

Anda juga dapat menginisialisasi 'array', cukup berikan nilai default

const int DEFAULT = 1234;
vector< vector<int> > f(rows, vector<int>(cols, DEFAULT));

Sumber: Cara Membuat 2, 3 (atau Multi) Dimensi Array dalam C / C ++?

doctorlai
sumber
1
solusi terbaik IMHO
vipin8169
1
Ini bukan solusi yang baik jika saya tidak ingin memuat STL karena kendala memori.
katta
2
@katta kebanyakan program C ++ nontrivial memang menggunakan STL, jadi ini adalah solusi yang baik, hanya saja tidak untuk beberapa kasus kecil termasuk kasus Anda.
Zar Shardan
Yang tidak saya mengerti adalah mengapa begitu banyak orang menganggap indeks pertama sebagai baris, dan yang kedua sebagai kolom. Pemberontakan terhadap diagram koordinat XY di kelas matematika?
Dronz
2
@Dronz Itu karena itulah model memori C ++ - kolom-kolomnya berdekatan dalam memori, bukan baris. Di Fortran sebaliknya.
Levi Morrison
16

Array 2D pada dasarnya adalah array pointer 1D, di mana setiap pointer menunjuk ke array 1D, yang akan menampung data aktual.

Di sini N adalah baris dan M adalah kolom.

alokasi dinamis

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

mengisi

for(int i = 0; i < N; i++)
    for(int j = 0; j < M; j++)
      ary[i][j] = i;

mencetak

for(int i = 0; i < N; i++)
    for(int j = 0; j < M; j++)
      std::cout << ary[i][j] << "\n";

Gratis

for(int i = 0; i < N; i++)
    delete [] ary[i];
delete [] ary;
akshay_rahar
sumber
14

Bagaimana cara mengalokasikan array multidimensi yang berdekatan di GNU C ++? Ada ekstensi GNU yang memungkinkan sintaks "standar" berfungsi.

Sepertinya masalahnya berasal dari operator baru []. Pastikan Anda menggunakan operator baru sebagai gantinya:

double (* in)[n][n] = new (double[m][n][n]);  // GNU extension

Dan itu saja: Anda mendapatkan array multidimensi C-kompatibel ...

etham
sumber
Kompiler apa yang Anda gunakan? Sintaks array mengkompilasi dan berjalan dengan baik dengan g ++ 4.6.4 dan 4.7.3. Saya hanya mendapatkan peringatan pada yang terakhir] sebelum = bahwa "nilai yang dihitung tidak digunakan" atau "pernyataan tidak berpengaruh". Namun, jika saya menggunakan g ++ 4.8.1 (seharusnya sepenuhnya memenuhi persyaratan ++ 11), ia melempar kesalahan pada n dan o tidak menjadi konstan "ukuran array di operator baru harus konstan", dan menunjuk ke yang terakhir] di baris.
jbo5112
@ cmaster double (*in)[m][n] = (double (*)[m][n])new double[k*m*n];tidak berfungsi juga. Saya mendapatkan kesalahan C2057, C2540 nkarena tidak diketahui pada waktu kompilasi. Saya tidak mengerti mengapa saya tidak bisa melakukannya, karena memori dialokasikan dengan benar dan itu hanya petunjuk untuk menangani memori ini dengan mudah. (VS 2010)
user1234567
2
@ user3241228 gccmembodohi saya ketika saya menulis ini: memasok -std=c++11tidak cukup untuk mengaktifkan kesesuaian standar yang ketat, -pedantic-errorsdiperlukan juga. Tanpa bendera yang lebih baru, gccdengan senang hati menerima para pemeran, meskipun itu memang tidak sesuai dengan standar C ++. Dengan apa yang saya ketahui sekarang, saya hanya bisa menyarankan untuk kembali ke C ketika melakukan hal-hal yang sangat bergantung pada array multidimensi. C99 jauh lebih kuat dalam hal ini daripada C ++ 17.
cmaster - mengembalikan monica
@ cmaster yang dialokasikan secara dinamis VLA adalah gula sintaksis ... mereka baik dalam C karena tidak ada yang lain, tetapi C ++ memiliki gula sintaksis yang lebih baik :)
MM
1
@ MM Kasihan bahwa C ++ tidak memiliki gula sintaksis untuk array multidimensi berturut-turut yang dialokasikan pada heap dengan ukuran yang hanya diketahui saat runtime. Selama Anda tidak membutuhkan ini, gula sintaksis C ++ baik-baik saja. Tetapi ketika Anda membutuhkan semua hal di atas, bahkan FORTRAN mengalahkan C ++ ...
cmaster - mengembalikan monica
13

typedef adalah teman Anda

Setelah kembali dan melihat banyak jawaban lain saya menemukan bahwa penjelasan yang lebih dalam adalah dalam urutan, karena banyak jawaban lain menderita masalah kinerja atau memaksa Anda untuk menggunakan sintaks yang tidak biasa atau memberatkan untuk mendeklarasikan array, atau mengakses array. elemen (atau semua yang di atas).

Pertama, jawaban ini mengasumsikan Anda mengetahui dimensi array pada waktu kompilasi. Jika Anda melakukannya, maka ini adalah solusi terbaik karena keduanya akan memberikan kinerja terbaik dan memungkinkan Anda untuk menggunakan sintaks array standar untuk mengakses elemen array. .

Alasan ini memberikan kinerja terbaik adalah karena mengalokasikan semua array sebagai blok memori yang berdekatan yang berarti bahwa Anda cenderung memiliki lebih sedikit halaman yang hilang dan lokalitas spasial yang lebih baik. Mengalokasikan dalam satu loop dapat menyebabkan array individu berakhir tersebar di beberapa halaman yang tidak bersebelahan melalui ruang memori virtual karena loop alokasi dapat terganggu (mungkin beberapa kali) oleh utas atau proses lain, atau hanya karena kebijaksanaan dari pengalokasi mengisi kecil, blok memori kosong itu kebetulan telah tersedia.

Manfaat lainnya adalah sintaks deklarasi sederhana dan sintaks akses array standar.

Di C ++ menggunakan yang baru:

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

int main(int argc, char **argv) {

typedef double (array5k_t)[5000];

array5k_t *array5k = new array5k_t[5000];

array5k[4999][4999] = 10;
printf("array5k[4999][4999] == %f\n", array5k[4999][4999]);

return 0;
}

Atau gaya C menggunakan calloc:

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

int main(int argc, char **argv) {

typedef double (*array5k_t)[5000];

array5k_t array5k = calloc(5000, sizeof(double)*5000);

array5k[4999][4999] = 10;
printf("array5k[4999][4999] == %f\n", array5k[4999][4999]);

return 0;
}
Robert S. Barnes
sumber
1
Mengakses di luar akhir array tidak dijamin menyebabkan kesalahan. Jika Anda beruntung, programnya akan macet. Anda pasti berada di ranah perilaku yang tidak terdefinisi.
Michael Kristofik
Benar, meskipun tujuan dari contoh ini adalah benar-benar hanya untuk menunjukkan bagaimana menggunakan typedef dan baru bersama untuk mendeklarasikan array 2D.
Robert S. Barnes
1
Saya sangat menyukai jawaban Anda. Saya sendiri pernah menjadi penganjur typedef.
Fooo
12

Masalah ini mengganggu saya selama 15 tahun, dan semua solusi yang diberikan tidak memuaskan bagi saya. Bagaimana Anda membuat array multidimensi dinamis secara bersamaan dalam memori? Hari ini saya akhirnya menemukan jawabannya. Dengan menggunakan kode berikut, Anda dapat melakukan hal itu:

#include <iostream>

int main(int argc, char** argv)
{
    if (argc != 3)
    {
        std::cerr << "You have to specify the two array dimensions" << std::endl;
        return -1;
    }

    int sizeX, sizeY;

    sizeX = std::stoi(argv[1]);
    sizeY = std::stoi(argv[2]);

    if (sizeX <= 0)
    {
        std::cerr << "Invalid dimension x" << std::endl;
        return -1;
    }
    if (sizeY <= 0)
    {
        std::cerr << "Invalid dimension y" << std::endl;
        return -1;
    }

    /******** Create a two dimensional dynamic array in continuous memory ******
     *
     * - Define the pointer holding the array
     * - Allocate memory for the array (linear)
     * - Allocate memory for the pointers inside the array
     * - Assign the pointers inside the array the corresponding addresses
     *   in the linear array
     **************************************************************************/

    // The resulting array
    unsigned int** array2d;

    // Linear memory allocation
    unsigned int* temp = new unsigned int[sizeX * sizeY];

    // These are the important steps:
    // Allocate the pointers inside the array,
    // which will be used to index the linear memory
    array2d = new unsigned int*[sizeY];

    // Let the pointers inside the array point to the correct memory addresses
    for (int i = 0; i < sizeY; ++i)
    {
        array2d[i] = (temp + i * sizeX);
    }



    // Fill the array with ascending numbers
    for (int y = 0; y < sizeY; ++y)
    {
        for (int x = 0; x < sizeX; ++x)
        {
            array2d[y][x] = x + y * sizeX;
        }
    }



    // Code for testing
    // Print the addresses
    for (int y = 0; y < sizeY; ++y)
    {
        for (int x = 0; x < sizeX; ++x)
        {
            std::cout << std::hex << &(array2d[y][x]) << ' ';
        }
    }
    std::cout << "\n\n";

    // Print the array
    for (int y = 0; y < sizeY; ++y)
    {
        std::cout << std::hex << &(array2d[y][0]) << std::dec;
        std::cout << ": ";
        for (int x = 0; x < sizeX; ++x)
        {
            std::cout << array2d[y][x] << ' ';
        }
        std::cout << std::endl;
    }



    // Free memory
    delete[] array2d[0];
    delete[] array2d;
    array2d = nullptr;

    return 0;
}

Saat Anda menjalankan program dengan nilai sizeX = 20 dan sizeY = 15, hasilnya adalah sebagai berikut:

0x603010 0x603014 0x603018 0x60301c 0x603020 0x603024 0x603028 0x60302c 0x603030 0x603034 0x603038 0x60303c 0x603040 0x603044 0x603048 0x60304c 0x603050 0x603054 0x603058 0x60305c 0x603060 0x603064 0x603068 0x60306c 0x603070 0x603074 0x603078 0x60307c 0x603080 0x603084 0x603088 0x60308c 0x603090 0x603094 0x603098 0x60309c 0x6030a0 0x6030a4 0x6030a8 0x6030ac 0x6030b0 0x6030b4 0x6030b8 0x6030bc 0x6030c0 0x6030c4 0x6030c8 0x6030cc 0x6030d0 0x6030d4 0x6030d8 0x6030dc 0x6030e0 0x6030e4 0x6030e8 0x6030ec 0x6030f0 0x6030f4 0x6030f8 0x6030fc 0x603100 0x603104 0x603108 0x60310c 0x603110 0x603114 0x603118 0x60311c 0x603120 0x603124 0x603128 0x60312c 0x603130 0x603134 0x603138 0x60313c 0x603140 0x603144 0x603148 0x60314c 0x603150 0x603154 0x603158 0x60315c 0x603160 0x603164 0x603168 0x60316c 0x603170 0x603174 0x603178 0x60317c 0x603180 0x603184 0x603188 0x60318c 0x603190 0x603194 0x603198 0x60319c 0x6031a0 0x6031a4 0x6031a8 0x6031ac 0x6031b0 0x6031b4 0x6031b8 0x6031bc 0x6031c0 0x6031c4 0x6031c8 0x6031cc 0x6031d0 0x6031d4 0x6031d8 0x6031dc 0x6031e0 0x6031e4 0x6031e8 0x6031ec 0x6031f0 0x6031f4 0x6031f8 0x6031fc 0x603200 0x603204 0x603208 0x60320c 0x603210 0x603214 0x603218 0x60321c 0x603220 0x603224 0x603228 0x60322c 0x603230 0x603234 0x603238 0x60323c 0x603240 0x603244 0x603248 0x60324c 0x603250 0x603254 0x603258 0x60325c 0x603260 0x603264 0x603268 0x60326c 0x603270 0x603274 0x603278 0x60327c 0x603280 0x603284 0x603288 0x60328c 0x603290 0x603294 0x603298 0x60329c 0x6032a0 0x6032a4 0x6032a8 0x6032ac 0x6032b0 0x6032b4 0x6032b8 0x6032bc 0x6032c0 0x6032c4 0x6032c8 0x6032cc 0x6032d0 0x6032d4 0x6032d8 0x6032dc 0x6032e0 0x6032e4 0x6032e8 0x6032ec 0x6032f0 0x6032f4 0x6032f8 0x6032fc 0x603300 0x603304 0x603308 0x60330c 0x603310 0x603314 0x603318 0x60331c 0x603320 0x603324 0x603328 0x60332c 0x603330 0x603334 0x603338 0x60333c 0x603340 0x603344 0x603348 0x60334c 0x603350 0x603354 0x603358 0x60335c 0x603360 0x603364 0x603368 0x60336c 0x603370 0x603374 0x603378 0x60337c 0x603380 0x603384 0x603388 0x60338c 0x603390 0x603394 0x603398 0x60339c 0x6033a0 0x6033a4 0x6033a8 0x6033ac 0x6033b0 0x6033b4 0x6033b8 0x6033bc 0x6033c0 0x6033c4 0x6033c8 0x6033cc 0x6033d0 0x6033d4 0x6033d8 0x6033dc 0x6033e0 0x6033e4 0x6033e8 0x6033ec 0x6033f0 0x6033f4 0x6033f8 0x6033fc 0x603400 0x603404 0x603408 0x60340c 0x603410 0x603414 0x603418 0x60341c 0x603420 0x603424 0x603428 0x60342c 0x603430 0x603434 0x603438 0x60343c 0x603440 0x603444 0x603448 0x60344c 0x603450 0x603454 0x603458 0x60345c 0x603460 0x603464 0x603468 0x60346c 0x603470 0x603474 0x603478 0x60347c 0x603480 0x603484 0x603488 0x60348c 0x603490 0x603494 0x603498 0x60349c 0x6034a0 0x6034a4 0x6034a8 0x6034ac 0x6034b0 0x6034b4 0x6034b8 0x6034bc 

0x603010: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 
0x603060: 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 
0x6030b0: 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 
0x603100: 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 
0x603150: 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 
0x6031a0: 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 
0x6031f0: 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 
0x603240: 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 
0x603290: 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 
0x6032e0: 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 
0x603330: 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 
0x603380: 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 
0x6033d0: 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 
0x603420: 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 
0x603470: 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299

Seperti yang Anda lihat, array multidimensi terletak berdekatan dalam memori, dan tidak ada dua alamat memori yang tumpang tindih. Bahkan rutin untuk membebaskan array lebih sederhana daripada cara standar mengalokasikan memori secara dinamis untuk setiap kolom (atau baris, tergantung pada bagaimana Anda melihat array). Karena array pada dasarnya terdiri dari dua array linier, hanya keduanya yang harus (dan dapat) dibebaskan.

Metode ini dapat diperluas untuk lebih dari dua dimensi dengan konsep yang sama. Saya tidak akan melakukannya di sini, tetapi ketika Anda mendapatkan ide di baliknya, itu adalah tugas yang sederhana.

Saya harap kode ini akan membantu Anda sebanyak itu membantu saya.

kamshi
sumber
1
Masih ada array ekstra pointer. Kode yang menggunakan array harus melakukan lapisan tipuan tambahan, karena tidak bisa berasumsi array2d[i] = buffer + i * sizeX. Jadi ini membantu sedikit, tetapi dalam kode menggunakan array, kompiler tidak bisa hanya menambah pointer untuk memindai array.
Peter Cordes
4
Ya, inilah cara yang tepat untuk melakukannya. Tetapi ini adalah cara C untuk melakukannya, dalam C ++ kami akan gunakan make_unique<int[]>(sizeX*sizeY)untuk mengatur penyimpanan yang berdekatan, dan make_unique<int*[]>(sizeX)untuk mengatur penyimpanan untuk pointer (yang harus ditetapkan dengan cara yang sama seperti yang Anda tunjukkan). Ini membebaskan Anda dari persyaratan untuk menelepon delete[]dua kali di akhir.
Ben Voigt
Jawaban ini agak masuk akal bagi saya, bahkan lebih mempertimbangkan komentar @BenVoigt. Array ekstra dari pointer @PeterCordes merujuk, bukan temp? Mempertimbangkan manfaat (array 2d berkelanjutan dengan dimensi yang tidak diketahui pada waktu kompilasi), saya tidak yakin saya peduli memilikinya menggantung. Saya tidak mengerti apa yang dimaksud dengan @PeterCordes extra layer of indirection, apa itu? Mengapa kurung, array2d[i] = (temp + i * sizeX);
KcFnMi
delete [] array2d [0] sama dengan delete [] temp?
KcFnMi
6

Tujuan dari jawaban ini bukan untuk menambahkan sesuatu yang baru yang belum dibahas oleh orang lain, tetapi untuk memperluas jawaban @Kevin Loney.

Anda dapat menggunakan deklarasi ringan:

int *ary = new int[SizeX*SizeY]

dan sintaks aksesnya adalah:

ary[i*SizeY+j]     // ary[i][j]

tetapi ini rumit untuk sebagian besar, dan dapat menyebabkan kebingungan. Jadi, Anda bisa mendefinisikan makro sebagai berikut:

#define ary(i, j)   ary[(i)*SizeY + (j)]

Sekarang Anda dapat mengakses array menggunakan sintaks yang sangat mirip ary(i, j) // means ary[i][j] . Ini memiliki keuntungan karena sederhana dan indah, dan pada saat yang sama, menggunakan ekspresi sebagai pengganti indeks juga lebih sederhana dan kurang membingungkan.

Untuk mengakses, katakanlah, [2 + 5] [3 + 8], Anda dapat menulis ary(2+5, 3+8)sebagai ganti dari yang tampak kompleks ary[(2+5)*SizeY + (3+8)]yaitu menghemat tanda kurung dan membantu keterbacaan.

Peringatan:

  • Meskipun sintaksinya sangat mirip, ini TIDAK sama.
  • Jika Anda meneruskan array ke fungsi lain, SizeYharus dilewatkan dengan nama yang sama (atau sebaliknya dinyatakan sebagai variabel global).

Atau, jika Anda perlu menggunakan array dalam berbagai fungsi, maka Anda bisa menambahkan SizeY juga sebagai parameter lain dalam definisi makro seperti:

#define ary(i, j, SizeY)  ary[(i)*(SizeY)+(j)]

Anda mendapatkan idenya. Tentu saja, ini menjadi terlalu lama untuk berguna, tetapi masih dapat mencegah kebingungan dari + dan *.

Ini tidak direkomendasikan secara pasti, dan itu akan dikutuk sebagai praktik buruk oleh sebagian besar pengguna yang berpengalaman, tetapi saya tidak bisa menahan untuk membagikannya karena keanggunannya.

Sunting:
Jika Anda menginginkan solusi portabel yang berfungsi untuk sejumlah array, Anda dapat menggunakan sintaks ini:

#define access(ar, i, j, SizeY) ar[(i)*(SizeY)+(j)]

dan kemudian Anda bisa meneruskan array apa pun ke panggilan, dengan ukuran apa pun menggunakan sintaks akses:

access(ary, i, j, SizeY)      // ary[i][j]

PS: Saya sudah menguji ini, dan sintaks yang sama berfungsi (baik sebagai lvalue dan rvalue) pada kompiler g ++ 14 dan g ++ 11.

Zargles
sumber
4

Coba lakukan ini:

int **ary = new int* [sizeY];
for (int i = 0; i < sizeY; i++)
    ary[i] = new int[sizeX];
stanigator
sumber
2

Di sini, saya punya dua opsi. Yang pertama menunjukkan konsep array array atau pointer dari pointer. Saya lebih suka yang kedua karena alamatnya berdekatan, seperti yang Anda lihat pada gambar.

masukkan deskripsi gambar di sini

#include <iostream>

using namespace std;


int main(){

    int **arr_01,**arr_02,i,j,rows=4,cols=5;

    //Implementation 1
    arr_01=new int*[rows];

    for(int i=0;i<rows;i++)
        arr_01[i]=new int[cols];

    for(i=0;i<rows;i++){
        for(j=0;j<cols;j++)
            cout << arr_01[i]+j << " " ;
        cout << endl;
    }


    for(int i=0;i<rows;i++)
        delete[] arr_01[i];
    delete[] arr_01;


    cout << endl;
    //Implementation 2
    arr_02=new int*[rows];
    arr_02[0]=new int[rows*cols];
    for(int i=1;i<rows;i++)
        arr_02[i]=arr_02[0]+cols*i;

    for(int i=0;i<rows;i++){
        for(int j=0;j<cols;j++)
            cout << arr_02[i]+j << " " ;
        cout << endl;
    }

    delete[] arr_02[0];
    delete[] arr_02;


    return 0;
}
emarazz
sumber
1

Jika proyek Anda CLI (Dukungan Runtime Bahasa Biasa) , maka:

Anda bisa menggunakan kelas array, bukan yang Anda dapatkan saat menulis:

#include <array>
using namespace std;

Dengan kata lain, bukan kelas array yang tidak dikelola yang Anda dapatkan saat menggunakan std namespace dan ketika menyertakan header array, bukan kelas array yang tidak dikelola yang didefinisikan dalam namespace std dan di header array, tetapi kelas array yang dikelola dari CLI.

dengan kelas ini, Anda dapat membuat array dari peringkat apa pun yang Anda inginkan.

Kode berikut di bawah ini membuat array dua dimensi baru 2 baris dan 3 kolom dan tipe int, dan saya beri nama "arr":

array<int, 2>^ arr = gcnew array<int, 2>(2, 3);

Sekarang Anda dapat mengakses elemen dalam array, dengan nama itu dan menulis hanya satu tanda kurung [], dan di dalamnya, tambahkan baris dan kolom, dan pisahkan dengan koma ,.

Kode berikut di bawah ini mengakses elemen di baris ke-2 dan kolom ke-1 dari array yang sudah saya buat di kode sebelumnya di atas:

arr[0, 1]

hanya menulis baris ini untuk membaca nilai dalam sel itu, yaitu mendapatkan nilai dalam sel ini, tetapi jika Anda menambahkan sama = tanda , Anda akan menulis nilai dalam sel itu, yaitu mengatur nilai dalam sel ini. Anda juga dapat menggunakan operator + =, - =, * = dan / = untuk angka saja (int, float, double, __int16, __int32, __int64 dan lain-lain), tetapi yakin Anda sudah mengetahuinya.

Jika proyek Anda bukan CLI, maka Anda dapat menggunakan kelas array yang tidak dikelola dari namespace std, jika Anda #include <array>, tentu saja, tetapi masalahnya adalah bahwa kelas array ini berbeda dari array CLI. Buat array jenis ini sama seperti CLI, kecuali Anda harus menghapus ^tanda dan gcnewkata kunci. Namun sayangnya parameter int kedua dalam <>tanda kurung menentukan panjang (ukurannya) dari array, bukan peringkatnya!

Tidak ada cara untuk menentukan peringkat dalam array semacam ini, peringkat adalah fitur array CLI saja. .

array std berperilaku seperti array normal di c ++, yang Anda tetapkan dengan pointer, misalnya int*dan kemudian new int[size]:, atau tanpa pointer:, int arr[size]tetapi tidak seperti array normal dari c ++, array std menyediakan fungsi yang dapat Anda gunakan dengan elemen-elemen array, seperti mengisi, memulai, mengakhiri, ukuran, dan lain-lain, tetapi array normal tidak memberikan apa-apa .

Tetapi array masih std adalah array satu dimensi, seperti array c ++ normal. Tetapi berkat solusi yang orang lain sarankan tentang bagaimana Anda dapat membuat normal c ++ array satu dimensi ke array dua dimensi, kita dapat mengadaptasi ide yang sama ke std array, misalnya menurut ide Mehrdad Afshari, kita dapat menulis kode berikut:

array<array<int, 3>, 2> array2d = array<array<int, 3>, 2>();

Baris kode ini menciptakan "jug array" , yang merupakan array satu dimensi yang masing-masing selnya atau menunjuk ke array satu dimensi lainnya.

Jika semua array satu dimensi dalam array satu dimensi sama panjang / ukurannya, maka Anda dapat memperlakukan variabel array2d sebagai array dua dimensi nyata, plus Anda dapat menggunakan metode khusus untuk memperlakukan baris atau kolom, tergantung pada bagaimana Anda melihatnya dalam pikiran, dalam array 2D, array std mendukung.

Anda juga dapat menggunakan solusi Kevin Loney:

int *ary = new int[sizeX*sizeY];

// ary[i][j] is then rewritten as
ary[i*sizeY+j]

tetapi jika Anda menggunakan std array, kode tersebut harus terlihat berbeda:

array<int, sizeX*sizeY> ary = array<int, sizeX*sizeY>();
ary.at(i*sizeY+j);

Dan masih memiliki fungsi unik dari std array.

Perhatikan bahwa Anda masih dapat mengakses elemen-elemen dari array std menggunakan []tanda kurung, dan Anda tidak harus memanggil atfungsi. Anda juga dapat mendefinisikan dan menetapkan variabel int baru yang akan menghitung dan mempertahankan jumlah total elemen dalam array std, dan menggunakan nilainya, alih-alih mengulangisizeX*sizeY

Anda dapat menentukan kelas generik array dua dimensi Anda sendiri, dan menentukan konstruktor dari kelas array dua dimensi untuk menerima dua bilangan bulat untuk menentukan jumlah baris dan kolom dalam array dua dimensi baru, dan menentukan fungsi get yang menerima dua parameter bilangan bulat yang mengakses elemen dalam array dua dimensi dan mengembalikan nilainya, dan mengatur fungsi yang menerima tiga parameter, bahwa keduanya pertama adalah bilangan bulat yang menentukan baris dan kolom dalam array dua dimensi, dan parameter ketiga adalah nilai baru dari elemen. Jenisnya tergantung pada jenis yang Anda pilih di kelas generik.

Anda akan dapat menerapkan semua ini dengan menggunakan salah satu c yang normal ++ array (pointer atau tanpa) atau std array dan penggunaan salah satu ide bahwa orang-orang lain yang disarankan, dan membuatnya mudah untuk digunakan seperti array cli, atau seperti dua array dimensi yang dapat Anda tetapkan, tetapkan, dan gunakan dalam C #.


sumber
1

Mulailah dengan mendefinisikan array menggunakan pointer (Baris 1):

int** a = new int* [x];     //x is the number of rows
for(int i = 0; i < x; i++)
    a[i] = new int[y];     //y is the number of columns
Omar Mohamed Abdel-Sattar
sumber
1

Contoh di bawah ini dapat membantu,

int main(void)
{
    double **a2d = new double*[5]; 
    /* initializing Number of rows, in this case 5 rows) */
    for (int i = 0; i < 5; i++)
    {
        a2d[i] = new double[3]; /* initializing Number of columns, in this case 3 columns */
    }

    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            a2d[i][j] = 1; /* Assigning value 1 to all elements */
        }
    }

    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            cout << a2d[i][j] << endl;  /* Printing all elements to verify all elements have been correctly assigned or not */
        }
    }

    for (int i = 0; i < 5; i++)
        delete[] a2d[i];

    delete[] a2d;


    return 0;
}
The_Learner
sumber
1

Jika Anda menginginkan array bilangan bulat 2d, elemen mana yang dialokasikan secara berurutan dalam memori, Anda harus mendeklarasikannya seperti

int (*intPtr)[n] = new int[x][n]

di mana alih-alih x Anda dapat menulis dimensi apa pun, tetapi n harus sama di dua tempat. Contoh

int (*intPtr)[8] = new int[75][8];
intPtr[5][5] = 6;
cout<<intPtr[0][45]<<endl;

harus mencetak 6.

Vahag Chakhoyan
sumber
0

Saya telah meninggalkan Anda dengan solusi yang paling cocok untuk saya, dalam beberapa kasus. Terutama jika seseorang tahu [ukuran?] Satu dimensi array. Sangat berguna untuk array karakter, misalnya jika kita membutuhkan berbagai array ukuran char [20].

int  size = 1492;
char (*array)[20];

array = new char[size][20];
...
strcpy(array[5], "hola!");
...
delete [] array;

Kuncinya adalah tanda kurung dalam deklarasi array.

FedeBsAs
sumber
StackOverflow hanya menggunakan bahasa Inggris, silakan terjemahkan pertanyaan Anda.
M. Mimpen
0

Saya menggunakan sistem yang tidak elegan tapi CEPAT, MUDAH dan BEKERJA ini. Saya tidak mengerti mengapa tidak bisa bekerja karena satu-satunya cara bagi sistem untuk memungkinkan membuat array ukuran besar dan mengakses bagian adalah tanpa memotongnya menjadi beberapa bagian:

#define DIM 3
#define WORMS 50000 //gusanos

void halla_centros_V000(double CENW[][DIM])
{
    CENW[i][j]=...
    ...
}


int main()
{
    double *CENW_MEM=new double[WORMS*DIM];
    double (*CENW)[DIM];
    CENW=(double (*)[3]) &CENW_MEM[0];
    halla_centros_V000(CENW);
    delete[] CENW_MEM;
}
ahli matematika
sumber
0

Saya tidak tahu pasti apakah jawaban berikut tidak diberikan tetapi saya memutuskan untuk menambahkan beberapa optimasi lokal ke alokasi array 2d (misalnya, matriks persegi dilakukan hanya melalui satu alokasi): int** mat = new int*[n]; mat[0] = new int [n * n];

Namun, penghapusan berjalan seperti ini karena linearitas alokasi di atas: delete [] mat[0]; delete [] mat;

sharkzeeh
sumber
Sudah disebutkan dalam jawaban untuk pertanyaan ini: stackoverflow.com/a/27672888/103167 dan versi smart pointer di sini: stackoverflow.com/a/29375830/103167
Ben Voigt
-1

mendeklarasikan array 2D secara dinamis:

    #include<iostream>
    using namespace std;
    int main()
    {
        int x = 3, y = 3;

        int **ptr = new int *[x];

        for(int i = 0; i<y; i++)
        {
            ptr[i] = new int[y];
        }
        srand(time(0));

        for(int j = 0; j<x; j++)
        {
            for(int k = 0; k<y; k++)
            {
                int a = rand()%10;
                ptr[j][k] = a;
                cout<<ptr[j][k]<<" ";
            }
            cout<<endl;
        }
    }

Sekarang dalam kode di atas kami mengambil pointer ganda dan menetapkannya memori dinamis dan memberikan nilai kolom. Di sini memori yang dialokasikan hanya untuk kolom, sekarang untuk baris kita hanya perlu untuk loop dan menetapkan nilai untuk setiap baris memori dinamis. Sekarang kita bisa menggunakan pointer persis seperti kita menggunakan array 2D. Dalam contoh di atas kita kemudian menetapkan angka acak ke array 2D (penunjuk). Semua tentang DMA array 2D.

pengguna2808359
sumber
-3

Saya menggunakan ini saat membuat array dinamis. Jika Anda memiliki kelas atau struct. Dan ini berhasil. Contoh:

struct Sprite {
    int x;
};

int main () {
   int num = 50;
   Sprite **spritearray;//a pointer to a pointer to an object from the Sprite class
   spritearray = new Sprite *[num];
   for (int n = 0; n < num; n++) {
       spritearray[n] = new Sprite;
       spritearray->x = n * 3;
  }

   //delete from random position
    for (int n = 0; n < num; n++) {
        if (spritearray[n]->x < 0) {
      delete spritearray[n];
      spritearray[n] = NULL;
        }
    }

   //delete the array
    for (int n = 0; n < num; n++) {
      if (spritearray[n] != NULL){
         delete spritearray[n];
         spritearray[n] = NULL;
      }
    }
    delete []spritearray;
    spritearray = NULL;

   return 0;
  } 
siapa saja
sumber