Initializing 2D Arrays, such as a 1D Array

Can anyone explain how the values ​​will be stored in this array:

int a[2][3] = {1,2,3,4,5} 

Using a 2D array, but assigning it as a 1D array.

+5
source share
3 answers

They are assigned as follows:

 1 2 3 4 5 0 

Zero is that you have allocated an array of size 6, but only 5 elements specified.

This is called "row order."

You can style your code a bit. Your code is currently:

 int a[2][3] = {1,2,3,4,5}; 

If you compile this with gcc main.c -Wall -pedantic --std=c99 , you will get a few warnings:

temp.c: 2: 17: warning: missing curly braces around the initializer [-Wmissing-braces]

Allow this with

 int a[2][3] = {{1,2,3,4,5}}; 

This will give you a new warning:

temp.c: 2: 25: warning: extra elements in the array initializer

Allow this using:

 int a[2][3] = {{1,2,3},{4,5,0}}; 

This explicitly displays the data as having two rows of three elements.

Some thoughts on memory layout

int a[2][3] will create an "array of arrays". This is similar to, but contradictory, from an "array of pointers to arrays." Both have similar access syntax (e.g., a[1][2] ). But only for the "array of arrays" you can reliably access the elements with a+y*WIDTH+x .

Some codes may clarify:

 #include <stdlib.h> #include <stdio.h> void PrintArray1D(int* a){ for(int i=0;i<6;i++) printf("%d ",a[i]); printf("\n"); } int main(){ //Construct a two dimensional array int a[2][3] = {{1,2,3},{4,5,6}}; //Construct an array of arrays int* b[2]; b[0] = calloc(3,sizeof(int)); b[1] = calloc(3,sizeof(int)); //Initialize the array of arrays for(int y=0;y<2;y++) for(int x=0;x<3;x++) b[y][x] = a[y][x]; PrintArray1D(a[0]); PrintArray1D(b[0]); } 

When you run this, you will get:

 1 2 3 4 5 6 1 2 3 0 0 0 

Printing b gives zeros (on my machine) since it runs in uninitialized memory. The result is that using continuous memory allows you to do convenient things, allowing you to set all values ​​without the need for a double loop.

+5
source

In C, 1D arrays are stored in a single linear buffer in memory in the so-called "main" order. The main line means that the last index changes faster when you go from element to element. The significance of the column means that the first index changes faster, as happens in MATLAB, for example.

The declared array is only 2D in the sense that the compiler helps you by calculating the linear address of the elements for you. The address of the element in the 1D array is calculated linear[x] = linear + x . Similarly, for your 2D array a[y][x] = a + 3 * y + x . In the general case, a[y][x] = a + num_cols * y + x .

You can initialize the array as one element vector that first fills the first row, then the second, and so on. Since you have two rows of three elements each, the first row becomes 1, 2, 3 , and the second row becomes 4, 5, 0 .

Indexing beyond the end of a line is acceptable, since the compiler is at least concerned. In the example you give, a[0][3] refers to the fourth element of the first row in the array, which consists of three elements. Wrapped, you can see that this is only the first element of the second row, which is more clearly specified as a[1][0] .

Due to weak index checking, you can completely omit the first index in any array while you provide an initializer. The formula for calculating the linear address does not depend on the first index (because it is the main line), and the total number of elements is indicated by the initializer itself. Example 1D - int linear[] = {1, 2, 3}; .

Keep in mind that the name of the array also refers to a pointer to its first element. These are two different things that can be accessed with the same name.

+4
source

From the definition of how access to a 2D array is interpreted, for example, a[1][2] , "It follows that the arrays are stored in lowercase order" (cf, for example, this is an online subscription to the standard edition of the project / array ). This means that for the array int a[ROWS][COLUMNS] for access a[r][c] offset in terms of int values ​​is calculated as (r*COLUMNS + c) .

So, for the array int a[2][3] access a[0][1] has an offset of 0*3 + 1 = 1 , and access a[1][0] has an offset of 1*3 + 0 = 3 . However, a[0][3] can lead to an offset of 3 , and a[1][0] will definitely lead to 3 . I wrote “maybe” because I think that accessing the int a[2][3] array using a[0][3] is undefined behavior since the range of the last index is 0..2 . Therefore, in accordance with 6.5.6 (8), the expression a[0][3] refers to the submatrix a[0] from its boundaries, as is stated, for example, here .

Now about how int a[2][3] = {1,2,3,4,5} interpreted. This operator is initialization, as defined in section 6.7.9 of this online project of standard project C, and in paragraphs (20) - (26) the things necessary here are described:

(20) If an aggregate or association contains elements or elements that are aggregates or unions, these rules apply recursively to sub-aggregates or combined unions. If the initializer sub-aggregate or containing the union begins with the left bracket, the initializers enclosed in this bracket and the corresponding right bracket to initialize the elements or elements of the sub-aggregate or containing the union. Otherwise, only initializers from the list are enough. accepted for accounting elements or members of a sub-aggregate or the first member of a joint union; any remaining initializers to initialize the next element or member of the population that is part of or a combined element.

(21) If the list enclosed in curly brackets contains fewer initiators than there are elements or elements of the collection or fewer characters in the string literal used to initialize an array of known size than there are elements in the array, the rest of the collection must be initialized implicitly same as objects having static storage duration.

26 EXAMPLE

(3) Announcement

  int y[4][3] = { { 1, 3, 5 }, { 2, 4, 6 }, { 3, 5, 7 }, }; 

- the definition of a completely bracketed initialization: 1 , 3 and 5 to initialize the first row y (object array y[0] ), namely y[0][0] , y[0][1] and y[0][2] . Similarly, the next two lines are initialized to y[1] and y[2] . The initializer ends earlier, so y[3] initializes zeros. Exactly the same effect could be achieved.

  int y[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 }; 

The initializer for y[0] does not start with the left bracket, therefore, three elements from the list are used. Similarly, the following three are sequentially performed for y[1] and y[2] .

+2
source

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


All Articles