CS Atlas GATE 2027
PDS course
0 / 103 complete

PDS/Phase 1 · Programming in C

Lesson 1.5.2 · Item 26 of 103

2-D arrays; row-major layout; pointer to array vs array of pointers; reading complex declarations

Read at your own pace. Try the questions before opening the answers.

On this page

0 · Recall Warm-up

Answer from memory first. Answers are in the Answer Vault at the bottom.

1 · The Hook

🎣

A cinema hall has 10 rows of 20 seats. Seat (3, 5) is easy to describe on a ticket, but memory is a single long line of bytes. So C lays the rows out one after another: all of row 0, then all of row 1, and so on. Finding a seat becomes arithmetic.

2 · Predict First

🤔

int a[10][20]; starts at address 1000, with 4-byte ints. At what address is a[3][5]? Make a guess in your head. The answer opens Section 3.

3 · Core Concept

💡

Predict First — the answer

1260. Rows 0, 1, 2 come first: 3 × 20 = 60 elements; then 5 more in row 3: 65 elements × 4 bytes = 260 bytes after 1000.

Declaring a 2-D array

int m[3][4]; is an array of 3 rows, each an array of 4 ints. m[i][j] is row i, column j.

  • int m[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
  • Inner braces may be dropped: values fill row by row. Missing values are 0.
  • Only the first size may be omitted: int m[][4] = {…};
int z[3][4] = {{1}, {2, 3}};
printf("%d %d %d %d\n", z[0][0], z[0][1], z[1][1], z[2][3]);

Output

1 0 3 0

Row-major layout

C stores 2-D arrays in row-major order: row 0 entirely, then row 1, and so on. For T a[R][C] starting at B with element size w:

address of a[i][j] = B + (i × C + j) × w

Note that the number of rows R is not needed; the number of columns C is.

Rows are arrays, and decay too

m[i] is row i, an array of 4 ints, which decays to &m[i][0]. m itself decays to a pointer to row 0, a pointer to an array of 4 ints, so m + 1 jumps a whole row (16 bytes). Therefore m[i][j] == *(*(m + i) + j) == *(m[i] + j).

int m[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
printf("%d %d %d\n", m[1][2], *(*(m + 2) + 1), *(m[0] + 3));
printf("%d %d\n", (int)((char *)(m + 1) - (char *)m), (int)((char *)(m[0] + 1) - (char *)m[0]));

Output

7 10 4
16 4

Passing a 2-D array

The parameter must state the column count, so the function can compute row starts: int f(int m[][3], int rows) (equivalently int (*m)[3]).

int sumAll(int m[][3], int rows)
{
    int i, j, s = 0;
    for (i = 0; i < rows; i++)
        for (j = 0; j < 3; j++)
            s += m[i][j];
    return s;
}

int main(void)
{
    int t[2][3] = {{1, 2, 3}, {4, 5, 6}};
    printf("%d\n", sumAll(t, 2));
    return 0;
}

Output

21

Pointer to array vs array of pointers

DeclarationRead assizeof here
int *p[4];p is an array of 4 pointers to int16 (4 pointers)
int (*q)[4];q is a pointer to an array of 4 ints4 (one pointer)
int *p[4];
int (*q)[4];
printf("%u %u %u\n", sizeof(p), sizeof(q), sizeof(*q));

Output

16 4 16

A pointer to an array is exactly what a 2-D array decays to; stepping it moves a whole row:

int m[2][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}};
int (*row)[4] = m;
row++;
printf("%d %d\n", (*row)[0], row[0][3]);

Output

5 8

Reading declarations: start at the name, go right, then left

Brackets [] on the right bind tighter than * on the left; parentheses override.

DeclarationMeaning
int *p[10];p is an array of 10 — pointers to int
int (*p)[10];p is a pointer — to an array of 10 ints
int **p;p is a pointer — to a pointer to int
int *(*p)[5];p is a pointer — to an array of 5 — pointers to int
int *f(int);f is a function taking int, returning a pointer to int

4 · Visual

Diagram: 1 · [0] · 2000 · 2 · [1] · 2004 · 3 · [2] · 2008 · 4 · [3] · 2012 · 5 · [4] · 2016 · 6 · [5] · 2020 · 7 · [6] · 2024 · 8 · [7] · 2028 · 9 · [8] · 2032 · 10 · [9] · 2036 · 11 · [10] · 2040 · 12 · [11] · 2044 · m, m[0] · m + 1, m[1] · m + 2

int m[3][4] laid out row-major from 2000: row 0 (orange-free blue cells 0–3), row 1 (4–7), row 2 (8–11). m[1][2] is element 1 × 4 + 2 = 6 → address 2024.

Table view                         Memory view (row-major, one long line)

        col0 col1 col2 col3
 row0 [  1    2    3    4 ]        | 1 2 3 4 | 5 6 7 8 | 9 10 11 12 |
 row1 [  5    6    7    8 ]          row 0     row 1     row 2
 row2 [  9   10   11   12 ]

 m[i][j] = *(*(m + i) + j)          address = base + (i * 4 + j) * sizeof(int)

The table is an illusion; memory holds the rows end to end.

5 · Worked Examples

Example 1 Easy

short s[8][6]; starts at 2000 (2-byte shorts). Where is s[4][1]?

Solution

(4 × 6 + 1) × 2 = 50 bytes in: 2050.

Example 2 Medium

double d[5][10]; starts at 500 (8-byte doubles). Where is d[2][7]? Why is the number of rows (5) not needed?

Solution

(2 × 10 + 7) × 8 = 216: 716. Only the elements before d[2][7] matter: complete rows (each 10 wide) and the start of row 2. The total row count only matters for the array’s end.

Example 3 GATE

What does this print?

int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int *p = &a[0][0];
printf("%d %d %d %d\n", p[4], *(a[1] + 2), **(a + 2), *(*(a + 1) + 1));

Solution

p walks the 9 ints in order: p[4] = 5. a[1] + 2 points at a[1][2] = 6. a + 2 is row 2, **(a + 2) = a[2][0] = 7. ((a + 1) + 1) = a[1][1] = 5.

Output

5 6 7 5

6 · GATE Traps

⚠️

  • Row-major: address uses the number of columns, not rows.
  • In a 2-D parameter, every size except the first must be given.
  • int *p[4] (array of pointers) vs int (*p)[4] (pointer to array): different sizes and meanings.
  • m + 1 jumps a whole row; m[0] + 1 jumps one element.
  • Missing inner initializers are zero; inner braces decide which row values go to.

8 · Memory Hook

🧠

“Rows are streets laid end to end.” To reach seat (i, j): skip i whole streets of C houses, then walk j houses.

9 · Connect the Dots

Lessons 1.5.1–1.5.2 built one- and two-dimensional arrays and their pointer meanings. The most common array in real programs holds characters: names, messages, file paths. Next lesson answers: how does C store text, and how does a function know where a piece of text ends?

10 · Self-Test

GATE format. Try every question before opening the vault.

Q1NAT1 markAddress

int a[10][20]; starts at 1000 (4-byte ints, row-major). What is the address of a[3][5]?

Numerical answer: ________

Q2MCQ1 markDeclarations

int (*p)[10]; declares p as:

  • (A) an array of 10 pointers to int
  • (B) a pointer to a pointer to int
  • (C) a function returning a pointer
  • (D) a pointer to an array of 10 ints

Q3NAT2 markssizeof

With 4-byte ints and pointers, what is sizeof(int *[8]) (an array of 8 pointers to int)?

Numerical answer: ________

Q4MCQ2 marksOutput

What does this print?

int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
int *p = a[0];
int (*q)[3] = a;
printf("%d %d %d\n", *(p + 4), (*(q + 1))[2], *(*q + 1));
  • (A) 5 6 4
  • (B) 5 3 2
  • (C) 4 6 2
  • (D) 5 6 2

Q5MSQ1 mark2-D arrays

For int m[3][4];, which equal m[2][1]?

  • (A) **(m + 2) + 1
  • (B) *(*(m + 2) + 1)
  • (C) *(m[2] + 1)
  • (D) *(*m + 9)

11 · Rule Card

  • T a[R][C]: &a[i][j] = B + (i·C + j)·w (row-major).
  • a[i][j] ≡ ((a + i) + j) ≡ *(a[i] + j).
  • a decays to T (*)[C]; a + 1 jumps a row; a[i] + 1 jumps an element.
  • Parameter: int m[][C] or int (*m)[C] — columns required.
  • int *p[N] array of pointers; int (*p)[N] pointer to array.
  • Read declarations: name → right ([] , ()) → left (*), parentheses first.

12 · Concept Ledger

Unlocked in this lesson. From here on, these terms may be used.

2-D arrayrow-major orderaddress formula B + (iC + j)wpointer to arrayarray of pointersreading declarations

13 · Answer Vault

Answer Vault

Try the questions first. Open when you are ready to check.

Recall Warm-up

  • The whole array: 20 bytes.
  • Take pointer parameters and be called with their addresses.
  • A declaration of the function’s name and types, written before calls when the body comes later.

Self-Test

Q1 Answer: 12601 mark

(3 × 20 + 5) × 4 = 260 → 1260.

Re-read: Lesson 1.5.2 — 2-D arrays; row-major layout; pointer to array vs array of pointers; reading complex declarations

Q2 Answer: (D)1 mark

Parentheses bind * to p first.

  • (A) is wrong: That is int *p[10].
  • (B) is wrong: That is int **p.
  • (C) is wrong: No function is involved.

Re-read: Lesson 1.5.2 — 2-D arrays; row-major layout; pointer to array vs array of pointers; reading complex declarations

Q3 Answer: 322 marks

8 × 4 = 32.

Re-read: Lesson 1.5.2 — 2-D arrays; row-major layout; pointer to array vs array of pointers; reading complex declarations

Q4 Answer: (D)2 marks

p walks the 6 ints: (p + 4) = 5. q + 1 is row 1: ((q + 1))[2] = 6. *q + 1 points at a[0][1] = 2.

Output

5 6 2
  • (A) is wrong: *q + 1 is element a[0][1].
  • (B) is wrong: q + 1 is row 1, whose index 2 is 6.
  • (C) is wrong: Index 4 from the start is 5.

Re-read: Lesson 1.5.2 — 2-D arrays; row-major layout; pointer to array vs array of pointers; reading complex declarations

Q5 Answer: (B) (C) (D)1 mark

*m + 9 is element 9 counted from the start = 2 × 4 + 1.

  • (A) is wrong: That is m[2][0] + 1.

Re-read: Lesson 1.5.2 — 2-D arrays; row-major layout; pointer to array vs array of pointers; reading complex declarations

Ready for the next idea?

Mark this item complete when you’ve finished reading and working through it.