Wie deklariere ich ein 2D-Array mit new?
Für ein "normales" Array würde ich:
int* ary = new int[Size]
aber
int** ary = new int[sizeY][sizeX]
a) funktioniert nicht / kompiliert und b) erreicht nicht was:
int ary[sizeY][sizeX]
tut.
Wie deklariere ich ein 2D-Array mit new?
Für ein "normales" Array würde ich:
int* ary = new int[Size]
aber
int** ary = new int[sizeY][sizeX]
a) funktioniert nicht / kompiliert und b) erreicht nicht was:
int ary[sizeY][sizeX]
tut.
Antworten:
Ein dynamisches 2D-Array ist im Grunde ein Array von Zeigern auf Arrays . Sie können es mit einer Schleife wie folgt initialisieren:
int** a = new int*[rowCount];
for(int i = 0; i < rowCount; ++i)
a[i] = new int[colCount];
Das Obige für colCount= 5
und rowCount = 4
würde Folgendes ergeben:
new
ist, auf dem Heap erstellt wird und mit der Zuordnung aufgehoben werden muss. delete
Denken Sie daran und löschen Sie diesen Speicher aus dem Heap, wenn Sie damit fertig sind, um Lecks zu vermeiden.
T (*ptr)[M] = new T[N][M];
ist die richtige Lösung… Keine Anzahl von Arrays von Zeigern wird jemals die gleiche sein wie ein Array von Arrays…
int** ary = new int[sizeY][sizeX]
sollte sein:
int **ary = new int*[sizeY];
for(int i = 0; i < sizeY; ++i) {
ary[i] = new int[sizeX];
}
und dann aufräumen wäre:
for(int i = 0; i < sizeY; ++i) {
delete [] ary[i];
}
delete [] ary;
EDIT: Wie Dietrich Epp in den Kommentaren betonte, ist dies nicht gerade eine leichte Lösung. Ein alternativer Ansatz wäre die Verwendung eines großen Speicherblocks:
int *ary = new int[sizeX*sizeY];
// ary[i][j] is then rewritten as
ary[i*sizeY+j]
i*sizeX+j
? Wenn ich mich richtig erinnere, sollte es bei der Hauptreihenfolge Zeile * numColumns + col sein.
Obwohl diese beliebte Antwort Ihnen die gewünschte Indizierungssyntax liefert, ist sie doppelt ineffizient: groß und langsam, sowohl räumlich als auch zeitlich. Es gibt einen besseren Weg.
Warum diese Antwort groß und langsam ist
Die vorgeschlagene Lösung besteht darin, ein dynamisches Array von Zeigern zu erstellen und dann jeden Zeiger mit einem eigenen, unabhängigen dynamischen Array zu initialisieren. Der Vorteil dieses Ansatzes besteht darin, dass Sie die gewohnte Indizierungssyntax erhalten. Wenn Sie also den Wert der Matrix an Position x, y ermitteln möchten, sagen Sie:
int val = matrix[ x ][ y ];
Dies funktioniert, weil Matrix [x] einen Zeiger auf ein Array zurückgibt, das dann mit [y] indiziert wird. Brechen sie ab:
int* row = matrix[ x ];
int val = row[ y ];
Praktisch, ja? Wir mögen unsere [x] [y] -Syntax.
Die Lösung hat jedoch einen großen Nachteil : Sie ist sowohl fett als auch langsam.
Warum?
Der Grund, warum es sowohl fett als auch langsam ist, ist tatsächlich der gleiche. Jede "Zeile" in der Matrix ist ein separat zugewiesenes dynamisches Array. Eine Heap-Zuordnung ist sowohl zeitlich als auch räumlich teuer. Der Allokator benötigt Zeit, um die Zuordnung vorzunehmen, und führt manchmal O (n) -Algorithmen aus, um dies zu tun. Und der Allokator "füllt" jedes Ihrer Zeilenarrays mit zusätzlichen Bytes für die Buchhaltung und Ausrichtung auf. Dieser zusätzliche Platz kostet ... na ja ... zusätzlichen Platz. Der Deallocator wird auch zusätzliche Zeit in Anspruch, wenn Sie die Zuordnung der Matrix aufheben, wodurch jede einzelne Zeilenzuordnung sorgfältig . Bringt mich ins Schwitzen, wenn ich nur daran denke.
Es gibt noch einen anderen Grund, warum es langsam ist. Diese getrennten Zuordnungen neigen dazu, in diskontinuierlichen Teilen des Gedächtnisses zu leben. Eine Zeile befindet sich möglicherweise an der Adresse 1.000, eine andere an der Adresse 100.000 - Sie haben die Idee. Dies bedeutet, dass Sie beim Durchqueren der Matrix wie eine wilde Person durch die Erinnerung springen. Dies führt tendenziell zu Cache-Fehlern, die Ihre Verarbeitungszeit erheblich verlangsamen.
Wenn Sie also unbedingt Ihre niedliche [x] [y] Indizierungssyntax haben müssen, verwenden Sie diese Lösung. Wenn Sie Schnelligkeit und Kleinheit wünschen (und wenn Sie sich nicht für diese interessieren, warum arbeiten Sie in C ++?), Benötigen Sie eine andere Lösung.
Eine andere Lösung
Die bessere Lösung besteht darin, Ihre gesamte Matrix als ein einziges dynamisches Array zuzuweisen und dann (leicht) eine eigene clevere Indizierungsmathematik zu verwenden, um auf Zellen zuzugreifen. Die Indizierungsmathematik ist nur sehr wenig klug; Nein, es ist überhaupt nicht klug: Es ist offensichtlich.
class Matrix
{
...
size_t index( int x, int y ) const { return x + m_width * y; }
};
Mit dieser index()
Funktion (von der ich mir vorstelle, dass sie Mitglied einer Klasse ist, weil sie die m_width
Ihrer Matrix kennen muss) können Sie auf Zellen in Ihrem Matrix-Array zugreifen. Das Matrixarray wird wie folgt zugeordnet:
array = new int[ width * height ];
Das Äquivalent dazu in der langsamen, fetten Lösung:
array[ x ][ y ]
... ist das in der schnellen, kleinen Lösung:
array[ index( x, y )]
Traurig, ich weiß. Aber du wirst dich daran gewöhnen. Und Ihre CPU wird es Ihnen danken.
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; } };
Wenn Sie diesen Code korrigieren, ist dies möglicherweise sinnvoll und gibt Aufschluss über die obige Antwort.
#define ROW_COL_TO_INDEX(row, col, num_cols) (row*num_cols + col)
Dann können Sie es als verwenden. int COLS = 4; A[ ROW_COL_TO_INDEX(r, c, COLS) ] = 75;
Der Overhead wirkt sich wirklich aus, wenn wir Matrixmultiplikationen durchführen, die für Strassens Algorithmus die Komplexität O (n ^ 3) oder O (n ^ 2.81) haben .
a[x][y]
, was Sie tatsächlich tun, ist *(*(a + x) + y)
: zwei Ergänzungen und zwei Speicherabrufe. Mit a[index(x, y)]
, das tun , was man eigentlich sind *(a + x + w*y)
: zwei Zugaben, eine Multiplikation und ein Speicher holen. Letzteres ist aus den in dieser Antwort genannten Gründen oft vorzuziehen (dh es lohnt sich, den zusätzlichen Speicherabruf mit einer Multiplikation zu tauschen, insbesondere weil die Daten nicht fragmentiert sind und Sie daher keinen Cache verpassen).
In C ++ 11 ist Folgendes möglich:
auto array = new double[M][N];
Auf diese Weise wird der Speicher nicht initialisiert. Um es zu initialisieren, gehen Sie stattdessen folgendermaßen vor:
auto array = new double[M][N]();
Beispielprogramm (kompilieren mit "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;
}
Ausgabe:
2 4
3 5
0 0
0 0
double (*) [2]
using arr2d = double(*)[2]; arr2d array = new double[M][N];
double (*)[M][N]
oder double(*)[][N]
mit M, wobei N konstante Ausdrücke sind.
Ich gehe von Ihrem statischen Array-Beispiel aus, dass Sie ein rechteckiges Array und kein gezacktes wollen. Sie können Folgendes verwenden:
int *ary = new int[sizeX * sizeY];
Dann können Sie auf folgende Elemente zugreifen:
ary[y*sizeX + x]
Vergessen Sie nicht, delete [] zu verwenden ary
.
Es gibt zwei allgemeine Techniken, die ich in C ++ 11 und höher empfehlen würde, eine für die Dimensionen der Kompilierungszeit und eine für die Laufzeit. Bei beiden Antworten wird davon ausgegangen, dass Sie einheitliche, zweidimensionale Arrays (keine gezackten) wünschen.
Verwenden Sie ein std::array
von std::array
und verwenden Sie es dann new
, um es auf den Haufen zu legen:
// the alias helps cut down on the noise:
using grid = std::array<std::array<int, sizeX>, sizeY>;
grid * ary = new grid;
Dies funktioniert wiederum nur, wenn die Größen der Dimensionen zur Kompilierungszeit bekannt sind.
Der beste Weg, um ein zweidimensionales Array mit Größen zu erstellen, die nur zur Laufzeit bekannt sind, besteht darin, es in eine Klasse zu packen. Die Klasse weist ein 1d-Array zu und überlastet es dannoperator []
es , um die Indizierung für die erste Dimension bereitzustellen. Dies funktioniert, weil in C ++ ein 2D-Array Zeilenmajor ist:
(Entnommen aus http://eli.thegreenplace.net/2015/memory-layout-of-multi-dimensional-arrays/ )
Eine zusammenhängende Speicherfolge ist aus Leistungsgründen gut und auch leicht zu bereinigen. Hier ist eine Beispielklasse, die viele nützliche Methoden auslässt, aber die Grundidee zeigt:
#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];
}
}
Also erstellen wir ein Array mit std::make_unique<int[]>(rows * columns)
Einträgen. Wir überladen, operator []
wodurch die Zeile für uns indiziert wird. Es gibt ein int *
Zeichen zurück, das auf den Anfang der Zeile zeigt, das dann wie gewohnt für die Spalte dereferenziert werden kann. Beachten Sie, dass das make_unique
erste Mal in C ++ 14 ausgeliefert wird, Sie es jedoch bei Bedarf in C ++ 11 mehrfach ausfüllen können.
Es ist auch üblich, dass diese Arten von Strukturen ebenfalls überlastet operator()
werden:
int &operator()(size_t row, size_t column) {
return data[row * _columns + column];
}
Technisch habe ich hier nicht verwendet new
, aber es ist trivial, von std::unique_ptr<int[]>
zu zu wechseln int *
und new
/ zu verwenden delete
.
std::array
von std::array
s : std::array<std::array<int, columns> rows>
.
asserts
Debug-Builds zur Überprüfung von Speicherzugriffen usw. Diese Ergänzungen erleichtern und erleichtern die Arbeit im Allgemeinen.
make_unique
statt new/delete
.
Diese Frage hat mich nervt - es ist ein häufig genug auftretendes Problem, dass es bereits eine gute Lösung geben sollte, etwas Besseres als der Vektorvektor oder das Rollen Ihrer eigenen Array-Indizierung.
Wenn in C ++ etwas vorhanden sein sollte, dies aber nicht ist, sollten Sie zunächst nach boost.org suchen . Dort fand ich die Boost Multidimensional Array Library ,multi_array
. Es enthält sogar eine multi_array_ref
Klasse, mit der Sie Ihren eigenen eindimensionalen Array-Puffer umschließen können.
auto
Schlüsselwort. Ich bin überrascht, dass sie nicht versucht haben, 2D-Arrays in Angriff zu nehmen, zumal Boost bereits den Weg gezeigt hat.
Warum nicht STL: vector verwenden? So einfach, und Sie müssen den Vektor nicht löschen.
int rows = 100;
int cols = 200;
vector< vector<int> > f(rows, vector<int>(cols));
f[rows - 1][cols - 1] = 0; // use it like arrays
Sie können die 'Arrays' auch initialisieren. Geben Sie einfach einen Standardwert ein
const int DEFAULT = 1234;
vector< vector<int> > f(rows, vector<int>(cols, DEFAULT));
Quelle: Wie erstelle ich 2, 3 (oder mehr) dimensionale Arrays in C / C ++?
Ein 2D-Array ist im Grunde ein 1D-Array von Zeigern, wobei jeder Zeiger auf ein 1D-Array zeigt, das die tatsächlichen Daten enthält.
Hier ist N Zeile und M Spalte.
dynamische Zuordnung
int** ary = new int*[N];
for(int i = 0; i < N; i++)
ary[i] = new int[M];
füllen
for(int i = 0; i < N; i++)
for(int j = 0; j < M; j++)
ary[i][j] = i;
for(int i = 0; i < N; i++)
for(int j = 0; j < M; j++)
std::cout << ary[i][j] << "\n";
kostenlos
for(int i = 0; i < N; i++)
delete [] ary[i];
delete [] ary;
Wie ordne ich ein zusammenhängendes mehrdimensionales Array in GNU C ++ zu? Es gibt eine GNU-Erweiterung, mit der die "Standard" -Syntax funktioniert.
Es scheint, dass das Problem vom Operator new [] kommt. Stellen Sie sicher, dass Sie stattdessen den Operator new verwenden:
double (* in)[n][n] = new (double[m][n][n]); // GNU extension
Und das ist alles: Sie erhalten ein C-kompatibles mehrdimensionales Array ...
double (*in)[m][n] = (double (*)[m][n])new double[k*m*n];
funktioniert auch nicht. Ich erhalte C2057- und C2540-Fehler, n
da diese zur Kompilierungszeit nicht bekannt sind. Ich verstehe nicht, warum ich das nicht kann, weil der Speicher richtig zugewiesen ist und es nur Zeiger sind , um diesen Speicher bequem zu handhaben. (VS 2010)
gcc
mich getäuscht, als ich dies schrieb: Die Lieferung -std=c++11
reicht nicht aus, um die strikte Standardkonformität einzuschalten, -pedantic-errors
ist ebenfalls erforderlich. Akzeptiert ohne das spätere Flag gcc
die Besetzung gerne, obwohl sie tatsächlich nicht dem C ++ - Standard entspricht. Nach dem, was ich jetzt weiß, kann ich nur raten, auf C zurückzugreifen, wenn ich Dinge mache, die stark von mehrdimensionalen Arrays abhängen. C99 ist in dieser Hinsicht viel leistungsfähiger als selbst C ++ 17.
typedef ist dein Freund
Nachdem ich viele der anderen Antworten durchgesehen hatte, stellte ich fest, dass eine tiefere Erklärung angebracht ist, da viele der anderen Antworten entweder unter Leistungsproblemen leiden oder Sie dazu zwingen, ungewöhnliche oder lästige Syntax zu verwenden, um das Array zu deklarieren oder auf das Array zuzugreifen Elemente (oder alle oben genannten).
Bei dieser Antwort wird zunächst davon ausgegangen, dass Sie die Dimensionen des Arrays zur Kompilierungszeit kennen. Wenn Sie dies tun, ist dies die beste Lösung, da beide die beste Leistung bieten Verwendung der Standard-Array-Syntax für den Zugriff auf die Array-Elemente ermöglicht .
Der Grund für die beste Leistung liegt darin, dass alle Arrays als zusammenhängender Speicherblock zugewiesen werden, was bedeutet, dass Sie wahrscheinlich weniger Seitenfehler und eine bessere räumliche Lokalität haben. Das Zuweisen in einer Schleife kann dazu führen, dass die einzelnen Arrays auf mehreren nicht zusammenhängenden Seiten im virtuellen Speicherbereich verstreut sind, da die Zuordnungsschleife (möglicherweise mehrmals) durch andere Threads oder Prozesse unterbrochen werden kann oder einfach aufgrund des Ermessens der Allokator füllt kleine, leere Speicherblöcke aus, die zufällig verfügbar sind.
Die anderen Vorteile sind eine einfache Deklarationssyntax und eine Standard-Array-Zugriffssyntax.
In C ++ mit new:
#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;
}
Oder C-Stil mit 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;
}
Dieses Problem hat mich 15 Jahre lang beschäftigt, und alle angebotenen Lösungen waren für mich nicht zufriedenstellend. Wie erstellt man ein dynamisches mehrdimensionales Array zusammenhängend im Speicher? Heute habe ich endlich die Antwort gefunden. Mit dem folgenden Code können Sie genau das tun:
#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;
}
Wenn Sie das Programm mit den Werten sizeX = 20 und sizeY = 15 aufrufen, lautet die Ausgabe wie folgt:
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
Wie Sie sehen können, liegt das mehrdimensionale Array zusammenhängend im Speicher, und keine zwei Speicheradressen überlappen sich. Selbst die Routine zum Freigeben des Arrays ist einfacher als die Standardmethode zum dynamischen Zuweisen von Speicher für jede einzelne Spalte (oder Zeile, je nachdem, wie Sie das Array anzeigen). Da das Array im Wesentlichen aus zwei linearen Arrays besteht, müssen (und können) nur diese beiden freigegeben werden.
Diese Methode kann mit demselben Konzept um mehr als zwei Dimensionen erweitert werden. Ich werde es hier nicht tun, aber wenn Sie die Idee dahinter haben, ist es eine einfache Aufgabe.
Ich hoffe, dieser Code wird Ihnen genauso helfen, wie er mir geholfen hat.
array2d[i] = buffer + i * sizeX
. Dies hilft also in geringem Maße, aber im Code, der das Array verwendet, kann der Compiler nicht einfach Zeiger inkrementieren, um das Array zu scannen.
make_unique<int[]>(sizeX*sizeY)
den zusammenhängenden Speicher make_unique<int*[]>(sizeX)
einrichten und den Speicher für die Zeiger einrichten (die auf die gleiche Weise zugewiesen werden sollten, wie Sie sie zeigen). Dies befreit Sie von der Notwendigkeit, delete[]
am Ende zweimal anzurufen .
temp
? In Anbetracht der Vorteile (Continuos 2d-Array mit unbekannten Dimensionen zur Kompilierungszeit) bin ich mir nicht sicher, ob es mir wichtig ist, dass es baumelt. Ich habe nicht verstanden, was @PeterCordes bedeutet extra layer of indirection
, was ist das? Warum die Klammer array2d[i] = (temp + i * sizeX)
;
Der Zweck dieser Antwort besteht nicht darin, etwas Neues hinzuzufügen, das die anderen noch nicht behandelt haben, sondern die Antwort von @Kevin Loney zu erweitern.
Sie können die Lightweight-Deklaration verwenden:
int *ary = new int[SizeX*SizeY]
und die Zugriffssyntax lautet:
ary[i*SizeY+j] // ary[i][j]
Dies ist jedoch für die meisten umständlich und kann zu Verwirrung führen. Sie können ein Makro also wie folgt definieren:
#define ary(i, j) ary[(i)*SizeY + (j)]
Jetzt können Sie mit der sehr ähnlichen Syntax auf das Array zugreifen ary(i, j) // means ary[i][j]
. Dies hat den Vorteil, einfach und schön zu sein, und gleichzeitig ist die Verwendung von Ausdrücken anstelle der Indizes einfacher und weniger verwirrend.
Um beispielsweise auf ary [2 + 5] [3 + 8] zuzugreifen, können Sie ary(2+5, 3+8)
anstelle des komplex aussehenden schreiben , ary[(2+5)*SizeY + (3+8)]
dh es werden Klammern gespeichert und die Lesbarkeit verbessert.
Vorsichtsmaßnahmen:
SizeY
muss es mit demselben Namen übergeben werden (oder stattdessen als globale Variable deklariert werden).Wenn Sie das Array in mehreren Funktionen verwenden müssen, können Sie SizeY auch wie folgt als weiteren Parameter in die Makrodefinition einfügen:
#define ary(i, j, SizeY) ary[(i)*(SizeY)+(j)]
Du hast die Idee. Natürlich wird dies zu lang, um nützlich zu sein, aber es kann immer noch die Verwechslung von + und * verhindern.
Dies wird definitiv nicht empfohlen und wird von den meisten erfahrenen Benutzern als schlechte Praxis verurteilt, aber ich konnte nicht widerstehen, es wegen seiner Eleganz zu teilen.
Bearbeiten:
Wenn Sie eine tragbare Lösung wünschen, die für eine beliebige Anzahl von Arrays funktioniert, können Sie diese Syntax verwenden:
#define access(ar, i, j, SizeY) ar[(i)*(SizeY)+(j)]
Anschließend können Sie mithilfe der Zugriffssyntax ein beliebiges Array mit einer beliebigen Größe an den Aufruf weitergeben:
access(ary, i, j, SizeY) // ary[i][j]
PS: Ich habe diese getestet und die gleiche Syntax funktioniert (sowohl als l-Wert als auch als r-Wert) auf g ++ 14- und g ++ 11-Compilern.
Versuchen Sie Folgendes:
int **ary = new int* [sizeY];
for (int i = 0; i < sizeY; i++)
ary[i] = new int[sizeX];
Hier habe ich zwei Möglichkeiten. Der erste zeigt das Konzept eines Arrays von Arrays oder eines Zeigers von Zeigern. Ich bevorzuge die zweite, weil die Adressen zusammenhängend sind, wie Sie auf dem Bild sehen können.
#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;
}
Wenn Ihr Projekt CLI (Common Language Runtime Support) ist , dann:
Sie können die Array-Klasse verwenden, nicht die, die Sie beim Schreiben erhalten:
#include <array>
using namespace std;
Mit anderen Worten, nicht die nicht verwaltete Array-Klasse, die Sie erhalten, wenn Sie den Standard-Namespace verwenden und den Array-Header einschließen, nicht die nicht verwaltete Array-Klasse, die im Standard-Namespace und im Array-Header definiert ist, sondern das verwaltete Klassenarray der CLI.
Mit dieser Klasse können Sie ein Array mit einem beliebigen Rang erstellen .
Der folgende Code erstellt ein neues zweidimensionales Array aus 2 Zeilen und 3 Spalten vom Typ int, und ich nenne es "arr":
array<int, 2>^ arr = gcnew array<int, 2>(2, 3);
Jetzt können Sie auf Elemente im Array zugreifen, indem Sie sie benennen und nur eine quadratische Klammer schreiben. Fügen Sie []
in ihnen die Zeile und Spalte hinzu und trennen Sie sie durch das Komma ,
.
Der folgende Code greift auf ein Element in der 2. Zeile und 1. Spalte des Arrays zu, das ich bereits im vorherigen Code oben erstellt habe:
arr[0, 1]
Wenn Sie nur diese Zeile schreiben, lesen Sie den Wert in dieser Zelle, dh Sie erhalten den Wert in dieser Zelle, aber wenn Sie den gleichen Wert hinzufügen =
, schreiben Sie den Wert in diese Zelle, dh legen Sie den Wert in dieser Zelle fest. Sie können die Operatoren + =, - =, * = und / = natürlich auch nur für Zahlen verwenden (int, float, double, __int16, __int32, __int64 usw.), aber Sie wissen es sicher bereits.
Wenn Ihr Projekt keine CLI ist, können Sie die nicht verwaltete Array-Klasse des Standard-Namespace verwenden, wenn Sie dies #include <array>
natürlich tun , aber das Problem ist, dass sich diese Array-Klasse vom CLI-Array unterscheidet. Das Erstellen eines Arrays dieses Typs entspricht der CLI, außer dass Sie das ^
Vorzeichen und das gcnew
Schlüsselwort entfernen müssen . Leider gibt der zweite int-Parameter in den <>
Klammern die Länge (dh die Größe) des Arrays an, nicht seinen Rang!
Es gibt keine Möglichkeit, den Rang in dieser Art von Array anzugeben. Der Rang ist nur die Funktion des CLI-Arrays . .
Das std-Array verhält sich wie ein normales Array in c ++, das Sie beispielsweise mit dem Zeiger definieren int*
und dann: new int[size]
oder ohne Zeiger:, int arr[size]
aber im Gegensatz zum normalen Array des c ++ bietet das std-Array Funktionen, die Sie mit den Elementen des Arrays verwenden können. wie Füllen, Beginnen, Beenden, Größe usw., aber normales Array bietet nichts .
Trotzdem sind Standard-Arrays eindimensionale Arrays, wie die normalen C ++ - Arrays. Aber dank der Lösungen, die die anderen Leute vorschlagen, wie Sie das normale eindimensionale C ++ - Array in ein zweidimensionales Array verwandeln können, können wir dieselben Ideen an das Standardarray anpassen, z. B. können wir nach der Idee von Mehrdad Afshari den folgenden Code schreiben:
array<array<int, 3>, 2> array2d = array<array<int, 3>, 2>();
Diese Codezeile erstellt ein "jugged array" , ein eindimensionales Array, das jede seiner Zellen ist oder auf ein anderes eindimensionales Array zeigt.
Wenn alle eindimensionalen Arrays in einem eindimensionalen Array in ihrer Länge / Größe gleich sind, können Sie die Variable array2d als echtes zweidimensionales Array behandeln. Außerdem können Sie die speziellen Methoden zum Behandeln von Zeilen oder Spalten verwenden, je nachdem, wie Sie sie anzeigen Beachten Sie, dass im Standard-Array dieses Standard-Array unterstützt wird.
Sie können auch die Lösung von Kevin Loney verwenden:
int *ary = new int[sizeX*sizeY];
// ary[i][j] is then rewritten as
ary[i*sizeY+j]
Wenn Sie jedoch ein Standardarray verwenden, muss der Code anders aussehen:
array<int, sizeX*sizeY> ary = array<int, sizeX*sizeY>();
ary.at(i*sizeY+j);
Und haben immer noch die einzigartigen Funktionen des Standard-Arrays.
Beachten Sie, dass Sie weiterhin über die []
Klammern auf die Elemente des Standardarrays zugreifen können und die at
Funktion nicht aufrufen müssen. Sie können auch eine neue int-Variable definieren und zuweisen, die die Gesamtzahl der Elemente im std-Array berechnet und beibehält und deren Wert verwendet, anstatt ihn zu wiederholensizeX*sizeY
Sie können Ihre eigene generische Klasse für zweidimensionale Arrays definieren und den Konstruktor der zweidimensionalen Array-Klasse so definieren, dass zwei Ganzzahlen empfangen werden, um die Anzahl der Zeilen und Spalten im neuen zweidimensionalen Array anzugeben, und die Funktion get abrufen, die zwei Parameter für Ganzzahlen empfängt die auf ein Element im zweidimensionalen Array zugreifen und dessen Wert zurückgeben und eine Funktion festlegen, die drei Parameter empfängt, wobei die beiden ersten Ganzzahlen sind, die die Zeile und Spalte im zweidimensionalen Array angeben, und der dritte Parameter der neue Wert des Element. Der Typ hängt von dem Typ ab, den Sie in der generischen Klasse ausgewählt haben.
Sie können all dies implementieren, indem Sie entweder das normale c ++ - Array (Zeiger oder ohne) oder das std-Array verwenden und eine der Ideen verwenden, die andere vorgeschlagen haben, und die Verwendung wie das cli-Array oder wie die beiden vereinfachen Dimensionsarray, das Sie in C # definieren, zuweisen und verwenden können.
Definieren Sie das Array zunächst mit Zeigern (Zeile 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
Das folgende Beispiel kann helfen,
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;
}
Wenn Sie ein 2d-Array von Ganzzahlen möchten, deren Elemente nacheinander im Speicher zugewiesen werden, müssen Sie es wie folgt deklarieren
int (*intPtr)[n] = new int[x][n]
Dabei können Sie anstelle von x eine beliebige Dimension schreiben, aber n muss an zwei Stellen gleich sein. Beispiel
int (*intPtr)[8] = new int[75][8];
intPtr[5][5] = 6;
cout<<intPtr[0][45]<<endl;
muss drucken 6.
Ich habe Ihnen eine Lösung hinterlassen, die in bestimmten Fällen für mich am besten funktioniert. Besonders wenn man [die Größe von?] Eine Dimension des Arrays kennt. Sehr nützlich für ein Array von Zeichen, zum Beispiel, wenn wir ein Array mit unterschiedlicher Größe von Zeichenfeldern benötigen [20].
int size = 1492;
char (*array)[20];
array = new char[size][20];
...
strcpy(array[5], "hola!");
...
delete [] array;
Der Schlüssel sind die Klammern in der Array-Deklaration.
Ich habe dieses nicht elegante, aber SCHNELLE, EINFACHE und ARBEITSSYSTEM verwendet. Ich verstehe nicht, warum dies nicht funktionieren kann, da das System nur dann ein großes Array erstellen und auf Teile zugreifen kann, wenn es nicht in Teile geschnitten wird:
#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;
}
Ich weiß nicht genau, ob die folgende Antwort nicht gegeben wurde, aber ich habe beschlossen, der Zuweisung von 2D-Arrays einige lokale Optimierungen hinzuzufügen (z. B. wird eine quadratische Matrix nur durch eine Zuordnung erstellt):
int** mat = new int*[n];
mat[0] = new int [n * n];
Das Löschen erfolgt jedoch aufgrund der Linearität der obigen Zuordnung folgendermaßen:
delete [] mat[0];
delete [] mat;
Dynamisches Deklarieren von 2D-Arrays:
#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;
}
}
Im obigen Code haben wir nun einen Doppelzeiger genommen, ihm einen dynamischen Speicher zugewiesen und einen Wert für die Spalten angegeben. Hier ist der zugewiesene Speicher nur für die Spalten, jetzt für die Zeilen benötigen wir nur eine for-Schleife und weisen dem Wert für jede Zeile einen dynamischen Speicher zu. Jetzt können wir den Zeiger genauso verwenden, wie wir ein 2D-Array verwenden. Im obigen Beispiel haben wir dann unserem 2D-Array (Zeiger) Zufallszahlen zugewiesen. Es dreht sich alles um DMA des 2D-Arrays.
Ich verwende dies beim Erstellen eines dynamischen Arrays. Wenn Sie eine Klasse oder eine Struktur haben. Und das funktioniert. Beispiel:
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;
}