Equivalence of two and one-dimensional arrays in C ++

It is known that two- and one-dimensional arrays can be used equivalently by a simple coordinate transformation. Is such equivalence a guarantee with the C ++ standard, or perhaps the most convenient way to organize data, but is it not necessary that it be implemented everywhere? For example, is the following compiler independent of code?

std::ofstream ofbStream; ofbStream.open("File", std::ios::binary); char Data[3][5]; for(int i=0; i<3; ++i) for(int j=0; j<5; ++j) { Data[i][j] = (char) 5*i+j; } ofbStream.write(&Data[0][0], 15); ofbStream.close(); 

It is expected that the program will write the numbers: 0, 1, 2, ..., 14 to a file.

+4
source share
5 answers

In practice, this is just great. Any compiler that does not do this will have countless problems with existing code.

Strictly speaking, we need Undefined Behavior pointer arithmetic.

 char Data[3][5]; char* p = &Data[0][0]; p + 7; // UB! 

5.7 / 5 (my attention):

When an expression that has an integral type is added or subtracted from the pointer, the result is the type of the operand of the pointer. If the pointer operand points to an element of the array object and the array is large enough, the result indicates the offset of the element from the original element, so this difference in the indices of the resulting and initial elements of the array is equal to the integral expression ... If both pointer operands and the result point to elements of the same the same array object or one after the last element of the array object, the estimate should not lead to overflow; otherwise, the behavior is undefined.

The standard ensures that all elements of the array are contiguous in memory and in a specific order, and that dereferencing a pointer with the correct address (regardless of how you got it) refers to the object at that address, but this does not guarantee that p + 7 does anything predictable, since p and p + 7 do not point to elements of the same array or at the end. (Instead, they point to elements of the elements of the same array.)

+4
source

In his book , The C ++ Programming Language, Bjarne Stroustrup mentions (C.7.2, p. 838 Special Edition, 2000):

... We can initialize ma as follows:

 void int_ma() { for(int i=0; i<3; i++) for(int j=0; j<5; j++) ma[i][j] = 10 * i + j; } 

...

The ma array is just 15 int that we are accessing, as if it were 3 arrays of 5 int s. In particular, there is no single object in the memory, that is, the matrix ma - only elements are stored. Sizes 3 and 5 exist only in the compiler source.

(a main attention).

In other words, the notation [][]...[] is a compiler construct; syntactic sugar if you want.

For entertainment purposes, I wrote the following code:

 #include<cstdlib> #include<iostream> #include<iterator> #include<algorithm> int main() { double ma[5][3]; double *beg = &ma[0][0]; // case 1 //double ma[3][5]; double *beg = &ma[0][0]; // case 2 //double ma[15]; double *beg = &ma[0]; // case 3 double *end = beg + 15; // fill array with random numbers std::generate(beg, end, std::rand); // display array contents std::copy(beg, end, std::ostream_iterator<double>(std::cout, " ")); std::cout<<std::endl; return 0; } 

And compared the assembly generated for three cases using the compilation command (GCC 4.7.2):

 g++ test.cpp -O3 -S -oc1.s 

Cases are called c1.s , c2.s and c3.s The result of the shasum *.s command is:

 5360e2438aebea682d88277da69c88a3f4af10f3 c1.s 5360e2438aebea682d88277da69c88a3f4af10f3 c2.s 5360e2438aebea682d88277da69c88a3f4af10f3 c3.s 

Now I must mention that the most natural construction seems to be a one-dimensional declaration of ma , that is: double ma[N] , because then the starting position is just ma , and the ending position is just ma + N (this is in contrast to the address of the first element of the array).

I find that the algorithms provided by the <algorithm> C ++ Standard Library header are much more complex in this case.

Finally, I should recommend you use std::array or std::vector , if at all possible.

Greetings.

+4
source

C ++ stores multidimensional arrays in row major , as a one-dimensional array expanding through memory.

+1
source

As other commentators noted, a 2-dimensional array will be mapped to 1-dimensional memory. Whatever your assumption platform? I would expect so, but you should always check it out.

 #include <iostream> #include <iterator> #include <algorithm> int main() { char Data[3][5]; int count = 0; for (int i = 0; i < 3; ++i) for (int j = 0; j < 5; ++j) Data[i][j] = count++; std::copy(&Data[0][0], &Data[0][0] + 15, std::ostream_iterator<int>(std::cout,", ")); } 

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,

http://www.fredosaurus.com/notes-cpp/arrayptr/23two-dim-array-memory-layout.html

How are multidimensional arrays formatted in memory?

Memory card for a 2D array in C

0
source

Quote

From all this, it follows that arrays in C ++ are stored differently (the last index changes faster), and that the first index in the declaration helps determine the amount of memory consumed by the array, but plays no other part in substring calculations.

C ++ ISO Standard

0
source

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


All Articles