Multidimensional Dynamic Arrays, Why Doesn't It Work?

I am not looking for a solution here, I found a lot on Google. I am looking for an explanation.

While playing with arrays, I found that declaring a two-dimensional array does not dynamically work as expected

1D Array Works

int main() { int rows; int* pointer; pointer = new int[rows]; } 

2D array not working

 int main() { int rows; int columns; int* pointer; pointer = new int[rows][columns]; //error on this line } 

It seems to me that this is an intuitive way to do something, because this is how it is done with regular arrays, but it seems to be incorrect and does not compile.

I could not find a clear explanation of why this is so, I hope someone here can enlighten me.

Thanks:)

+4
source share
5 answers

The reason this does not work is because in order to have a two-dimensional array, you need one pointer array that will point to many arrays of the type you want.

In this case, you are trying to save the address in an int * array (from which each "cell" will point to an ints array) in an int * variable, it must be int **.

Recall: 1D array: int * 2D array: int ** 3D array: int ***

The reason all arrays should be one-dimensional is because your memory is one-dimensional (count all memory as one large array of memory addresses), which means arrays with many dimensions must be "fake".

+6
source

This is not only a data type problem, as described in other answers.

Type syntax

 pointer = new int[rows][columns] 

only valid if columns is a constant expression. You cannot use a variable there (but note that rows can be a variable).

Here is an explanation. The C ++ standard allows you to use the syntax of a two-dimensional array with the new operator as follows (from clause 5.3.4 / 1):

 new-expression: ::opt new new-placementopt new-type-id new-initializeropt ::opt new new-placementopt ( type-id ) new-initializeropt new-placement: ( expression-list ) new-type-id: type-specifier-seq new-declaratoropt new-declarator: ptr-operator new-declaratoropt noptr-new-declarator noptr-new-declarator: [ expression ] attribute-specifier-seqopt noptr-new-declarator [ constant-expression ] attribute-specifier-seqopt new-initializer: ( expression-listopt ) braced-init-list 

The relevant part is as follows:

 noptr-new-declarator: [ expression ] attribute-specifier-seqopt noptr-new-declarator [ constant-expression ] attribute-specifier-seqopt 

The first line means that after the type identifier you can have one expression in square brackets. The second line (which is a recursive statement) allows you to use several pairs of brackets after the original, but they must enclose a constant expression.

The standard explains this further (my attention):

(ยง5.3.4 / 5) When the selected object is an array (i.e., the syntax is noptr-new-declarator or the identifier of a new type or the identifier of a type indicates the type of an array), the new -expression gives a pointer to the original element (if any) of the array . [ Note: both new int and new int [10] are of type int *, and the type of new int [i] [10] is int (*) [10] - end note] The attribute is specifier-seq in noptr-new-declarator refers to an associated array type.

(ยง5.3.4 / 6) Each constant expression in noptr-new-declarator must be an integral constant expression (5.19) and be evaluated with a strictly positive value. The expression in noptr-new-declarator must be of the type of an integral type, the type of an enumerated enumeration, or the type of a class for which there is one implicit function of converting to an integral or non-enumerated enumeration type (12.3). [...] [Example: Given the definition of int n = 42, the new float [n] [5] is correctly formed (since n is the expression noptr-new-declarator), but the new float [5] [n] is poorly formed (because n is not a constant expression). - end of example]

+4
source

Well, you can understand it as follows:

A 2-D array looks like a grid with row and columns to represent a person, but in memory it is stored in continuous memory. Therefore, whenever you say a two-dimensional array or size mxn , you are talking about m arrays of elements n , each of which is stored one after another. that is, for 3x3 grid elements, they are saved as:

 (0,0) (0,1) (0,2) (1,0) (1,1) (1,2) (2,0) (2,1) (2,2) 

If you want to access such a data structure, you need to use a pointer to a pointer, that is, a pointer to an array of location addresses of the first element of each row.

Thus, access to the array can be obtained using address 3 (number of rows)

 (Address of element 0,1) (Address of element 1,0) (Address of element 2,0) 

Since the address of the elements is stored like this now, you need a pointer to a pointer to access this array of pointers (by holding the addresses of the first element of each row).

For 1D array:

 int* pointer = new int[3]; Array: (0) (1) (2) pointer: (Address of first element of Array) 

For a two-dimensional array:

 int **pointer = new int[3][3]; Array: (0,0) (0,1) (0,2) (1,0) (1,1) (1,2) (2,0) (2,1) (2,2) Row Address Array: (Address of 0,1) (Address of 1,0) (Address of 2,0) pointer: (Address of first element of Row Address Array) 

Hope this helps!

+3
source

Other people have explained it well, but here is an example that can shed light on creating multidimensional arrays of dynamic size using new :

 int rows = 20; int columns = 30; // the following is essentially just an array of int pointers int **pointer = new int*[rows]; // so, loop through the array creating the second dimension for (int i = 0;i < rows;i++) pointer[i] = new int[columns]; 
0
source

This is a one-dimensional array of char pointers: char* Dynamic_One_Dimensional_Char_Pointer_Array . Pay attention to char * .

This is a two-dimensional array of char pointers: char **Dynamic_Two_Dimensional_Char_Pointer_Array . Pay attention to char ** .

This way you allocate memory for a two-dimensional array of char pointers:

  //memory allocated for elements of rows. Dynamic_Two_Dimensional_Char_Pointer_Array = new char *[ROWS] ; //memory allocated for elements of each column. for( i = 0 ; i < ROWS ; i++ ) Dynamic_Two_Dimensional_Char_Pointer_Array[i] = new char[COLUMNS]; 

Here's how to print a 2D array ( [rows][columns] ):

  for(rows=0;rows<maxLines;rows++) { for(int columns=0;columns<strlen(Dynamic_Two_Dimensional_Char_Pointer_Array[rows]);columns++) { cout<<Dynamic_Two_Dimensional_Char_Pointer_Array[rows][columns]<<""; } cout<<" \n"; } 

its is how you allocate memory for a two-dimensional array of char pointers:

 //free the allocated memory for( i = 0 ; i < ROWS ; i++ ) delete [] Dynamic_Two_Dimensional_Char_Pointer_Array[i] ; delete [] Dynamic_Two_Dimensional_Char_Pointer_Array ; 

Full sample code:

 #include<vector> #include<string> #include<iostream> using namespace std; int main() { int COLUMNS =80; //80 characters wide int ROWS =20;// 20 lines int i,maxLines=0; char* Dynamic_One_Dimensional_Char_Pointer_Array = new char[80]; char **Dynamic_Two_Dimensional_Char_Pointer_Array = 0; //memory allocated for elements of rows. Dynamic_Two_Dimensional_Char_Pointer_Array = new char *[ROWS] ; //memory allocated for elements of each column. for( i = 0 ; i < ROWS ; i++ ) Dynamic_Two_Dimensional_Char_Pointer_Array[i] = new char[COLUMNS]; strcpy(Dynamic_One_Dimensional_Char_Pointer_Array,"apples 123 oranges 456 bananas 789 lemons 101112 kiwi 132415 grapes 161718" ); cout<<" \ninput = "<<Dynamic_One_Dimensional_Char_Pointer_Array<<" \n\n"; cout<<"Output = \n"; char seperators[] = " ,\t\n"; char *token; token = strtok( Dynamic_One_Dimensional_Char_Pointer_Array, seperators ); i=0; while( token != NULL ) { strcpy(Dynamic_Two_Dimensional_Char_Pointer_Array[i],token); token = strtok( NULL, seperators ); i++; } maxLines=i; cout<<" \n"; cout<<"show contents 1 print [rows] \n"; cout<<"-------------------------------------------\n"; for(int rows=0;rows<maxLines;rows++) { cout<<Dynamic_Two_Dimensional_Char_Pointer_Array[rows]<<" \n"; } cout<<" \n"; cout<<"show contents 2 print [rows][columns]\n"; cout<<"-------------------------------------------\n"; for(rows=0;rows<maxLines;rows++) { //cout<<Dynamic_Two_Dimensional_Char_Pointer_Array[rows]<<" \n"; for(int columns=0;columns<strlen(Dynamic_Two_Dimensional_Char_Pointer_Array[rows]);columns++) { cout<<Dynamic_Two_Dimensional_Char_Pointer_Array[rows][columns]<<""; } cout<<" \n"; } delete[] Dynamic_One_Dimensional_Char_Pointer_Array; //free the allocated memory for( i = 0 ; i < ROWS ; i++ ) delete [] Dynamic_Two_Dimensional_Char_Pointer_Array[i] ; delete [] Dynamic_Two_Dimensional_Char_Pointer_Array ; return 0; } 
0
source

Source: https://habr.com/ru/post/1433934/


All Articles