Let’s see the following example:
These 3 1D arrays can be represented as a 2D array as follows:
Let’s see another example:
These 3 1D arrays cannot be representing as a 2D array because the sizes of the arrays are different.
Declaration of 2D array
data-type array-name[ROW][COL]
- Data-type is the data type of the array elements.
- Array-name is the name of the array.
- Two subscripts represent the number of rows and columns of the array. The total number of elements of the array will be ROW*COL.
int a[2][3];
Using the above C code, we can declare an integer array, a of size 2*3 (2 Rows and 3 Columns).
char b[3][2];
Using the above C code, we can declare a character array, b of size 2*3 (3 Rows and 2 Columns).
Initialization of 2D array
We can initialize during declaration in following ways:
- int a[3][2] = {1,2,3,4,5,6};
- int a[][2] = {1,2,3,4,5,6};
- int a[3][2] = {{1, 2},{3, 4},{5, 6}};
- int a[][2] = {{1, 2},{3, 4},{5, 6}};
Note that in 2 and 4 we have not mentioned the 1st subscript. The C compiler automatically calculates number of rows from the number of elements. But the 2nd subscript must be specified. Following initializations are invalid:
- int a[3][] = {1,2,3,4,5,6};
- int a[][] = {1,2,3,4,5,6};
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | //Example1.c #include #define ROW 3 #define COL 2 int main() { int i,j; int a[ROW][COL] = { {1,2}, {3,4}, {5,6} }; printf("Row wise Elements of the array a are :\n"); for(i=0;i<ROW;i++) { printf("Row %d:",i); for(j=0;j<COL;j++) { printf(" %d",a[i][j]); } printf("\n"); } printf("\n\nColumn wise Elements of the array a are :\n"); for(i=0;i<COL;i++) { printf("Column %d:",i); for(j=0;j<ROW;j++) { printf(" %d",a[j][i]); } printf("\n"); } return 0; } |
In Example1.c, we have declared an integer array of size 3*2 and initialized. To access array elements, we use two for loop.
To access row-wise, the outer loop is for rows, and the inner loop is for columns.
To access column-wise, the outer loop is for columns, and the inner loop is for rows.
Note that when we declare a 2D array, we use a[2][3], which means 2 rows and 3 columns. Array indexing starts from 0. To access the 2nd row and 3rd column, we have to use the notation a[1][2].
Memory mapping of a 2D array
The logical view of an array a[3][2] may be as follows:
Computer memory is a 1D sequence of bytes. In C language, a 2D array store in the memory in row-major order. Some other programming languages (e.g., FORTRAN), it stores in column-major order in the memory.
Pointer Arithmetic of a 2D array
To understand the pointer arithmetic of the 2D array, first, have a look at the 1D array.
Consider a 1D array:
In 1D array, a is a constant, and its value is the address of the 0th location of the array a[5]. Value of a+1 is the address of the 1st location of the array a[5]. a+i is the address of the ith location of the array.
If we increment a by 1, it is incremented by the size of the data type.
a[1] is equivalent to *(a+1)
a[2] is equivalent to *(a+2)
a[i] is equivalent to *(a+i)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | //Example2.c #include #define ROW 3 #define COL 2 int main() { int a[5]={10,20,30,40,50}; printf("sizeof(int): %ld\n\n",sizeof(int)); printf("a: %p\n",a); printf("a+1: %p\n",a+1); printf("a+2: %p\n\n",a+2); printf("a[1]: %d, *(a+1): %d\n",a[1],*(a+1)); printf("a[2]: %d, *(a+2): %d\n",a[1],*(a+1)); printf("a[3]: %d, *(a+3): %d\n",a[1],*(a+1)); return 0; } |
In Example2.c, the memory address is showing in hexadecimal. The difference between a and a+1 is 4, which is the size of an integer in bytes.
Now, consider a 2D array:
b is a pointer of type: int[ ][4] or int(*)[4]
int[ ][4] is a row of 4 integer. If we increment b by 1, it is incremented by the size of the row.
b is the address of the 0th row.
b+1 is the address of the 1st row.
b+i is the address of ith row.
The size of a row is: ( Number of column * sizeof(data-type)) bytes
Size of a row of an integer array b[3][4] is: 4 * sizeof(int) = 4 * 4 = 16 bytes
A row of a 2D array may be viewed as a 1D array. b is the address of the 0th row. So, we get the following
- *b+1 is the address of the 1st element of the 0th
- *b+j is the address of the jth element of the 0th
- *(b+i) is the address of the 0th element of the ith
- *(b+i)+j is the address of the jth element of the ith
- b[0][0] is equivalent to **b
- b[0][1] is equivalent to *(*b+1)
- b[1][0] is equivalent to *(*(b+1))
- b[1][1] is equivalent to *(*(b+1)+1)
- b[i][j] is equivalent to *(*(b+i)+j)
Address of b[i][j]: b + sizeof(data-type) * ( Number of column * i + j)
Consider a 2D array: int b[3][4]
Address of b[2][1] is : b + sizeof(int) * (4*2 + 1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | //Example3.c #include #define ROW 3 #define COL 4 int main() { int i,j; int b[ROW][COL] = { {10,20,30,40}, {50,60,70,80}, {90,100,110,120} }; printf("sizeof(int): %ld\n",sizeof(int)); printf("Size of a row: %ld\n",COL*sizeof(int)); printf("b: %p\n",b); printf("b+1: %p\n",b+1); printf("b+2: %p\n",b+2); printf("*b: %p\n",*b); printf("*b+1: %p\n",*b+1); printf("*b+2: %p\n",*b+2); printf("b[0][0]: %d **b: %d\n",b[0][0],**b); printf("b[0][1]: %d *(*b+1): %d\n",b[0][1],*(*b+1)); printf("b[0][2]: %d *(*b+2): %d\n",b[0][2],*(*b+2)); printf("b[1][0]: %d *(*(b+1)): %d\n",b[1][0],*(*(b+1))); printf("b[1][1]: %d *(*(b+1)+1): %d\n",b[1][1],*(*(b+1)+1)); return 0; } |
In Example3.c, we have seen that size of a row is 16 in decimal notation. The difference between b+1 and b is 10 in hexadecimal. 10 in hexadecimal is equivalent to 16 in decimal.
Conclusion
So, in this article, we have learned about
- Declaration of 2D array
- Initialization of 2D array
- Memory mapping of 2D array
- Pointer Arithmetic of 2D array
Now we can use 2D array in our C program without any doubt,
References
Credit for some ideas in this work were inspired by the course, Pointers and 2-D Arrays, by Palash Dey Department of Computer Science & Engg. Indian Institute of Technology Kharagpur