Arrays and Pointers in C: Complete Guide with Worked Examples for GATE and Interviews

Build one clear mental model for C arrays and pointers. Trace addresses, decode tricky expressions, solve a 2D-array numerical, and practise an in-place reversal.

KnowledgeGate Team

Exam prep & CS education

Updated 9 Aug 20266 min read129 views

You may be comfortable writing a loop over an array, then freeze when a question mixes * with ++ or asks for the address of b[2][1]. Arrays and pointers are one connected topic: an array is a block of memory, and a pointer is how C walks through that block. One five-element array, traced end to end, carries the whole relationship, so you can work an answer out instead of recalling a rule.

What an array really is: one block of memory with a formula

An array stores elements contiguously. It has a base address, each element has a fixed size, and indexing begins at zero. That gives us the central formula:

address of a[i] = base address + i * sizeof(element)

Every address and expression below is computed on this array:

int a[5] = {12, 25, 37, 41, 58};

Assume that the base address is 2000 and one int occupies 4 bytes.

Element

Value

Address

a[0]

12

2000

a[1]

25

2004

a[2]

37

2008

a[3]

41

2012

a[4]

58

2016

For example, address of a[3] = 2000 + 3 * 4 = 2012. Array access is constant time because the compiler computes this address directly. It does not search from the first element.

Pointers on the same array: declare, dereference, walk

Now declare int *p = a;. The pointer p holds 2000, so *p reads the value at address 2000, which is 12.

Pointer arithmetic moves in units of the pointed-to type. Therefore, p + 2 is not 2002. It is 2000 + 2 * 4 = 2008, and *(p + 2) = 37.

Pointer subtraction also works in elements, not bytes:

&a[4] - &a[1] = (2016 - 2004) / 4 = 3

Five-box memory diagram of int a[5] holding 12 to 58 at addresses 2000 to 2016, with pointer p and p + 2 landing on 37.

The expression a[i] is defined as *(a + i). This also explains the strange but valid expression 2[a], which means *(2 + a) and evaluates to a[2], or 37. Treat it as an exam curiosity, not as code you should write.

Where arrays and pointers differ: decay and the sizeof trap

An array name decays to a pointer to its first element in most expressions, but an array is not a pointer. In the scope where our array is defined, sizeof(a) = 20 because it contains five 4-byte integers. On a typical 64-bit machine, sizeof(p) = 8 because p is a pointer.

Function parameters expose the difference:

void f(int arr[])

The compiler treats that parameter as void f(int *arr). Inside f, sizeof(arr) is therefore 8 on that typical machine, not 20. Pass the length separately whenever a function receives an array.

There is an assignment difference too. p = a is legal, but a = p is a compile error because the array name is not a modifiable lvalue.

2D arrays and the address question GATE loves

For int b[3][4], C stores 12 integers in one contiguous, row-major block. All of row 0 comes first, followed by row 1 and then row 2.

Suppose the base address is 5000 and each element occupies 4 bytes. Compute the row-major address of b[2][1] step by step:

  1. Elements before it: 2 * 4 + 1 = 9.

  2. Byte offset: 9 * 4 = 36.

  3. Final address: 5000 + 36 = 5036.

So, address of b[2][1] = 5000 + (2 * 4 + 1) * 4 = 5000 + 9 * 4 = 5036.

An exam may add a column-major what-if. Then the calculation becomes 5000 + (1 * 3 + 2) * 4 = 5000 + 5 * 4 = 5020. C itself always stores this array in row-major order.

A 3 by 4 grid for b[3][4] flattened into a row-major strip from address 5000, with b[2][1] as the tenth cell at address 5036.

The pointer types matter. b[2] decays to an int * pointing to row 2. The name b decays to int (*)[4], a pointer to a complete four-integer row, so b + 1 jumps 16 bytes.

The classic traps: * and ++, and lookalike declarations

Reset p to address 2000 before each expression:

Expression

What happens

Result

*p++

Read through p, then advance p

evaluates to 12; p becomes 2004

(*p)++

Increment the pointed-to value

evaluates to 12; a[0] becomes 13; p stays 2000

*++p

Advance p, then dereference it

p becomes 2004; evaluates to 25

The first expression is parsed as *(p++), because ++ binds to p. Parentheses make the second expression change the array element instead.

Declarations create another common trap. int *arr[4] is an array of four pointers to int. int (*arr)[4] is one pointer to an array of four integers. Read a declaration from the identifier outwards.

At runtime, reading or writing a[5] in our five-element array is undefined behaviour, and so is dereferencing an uninitialised pointer or one whose target has gone out of scope. C performs no automatic bounds checking.

Multi-level pointers, the swap-by-address idiom and dangling pointers sit one layer beyond this array. Pointers in C for GATE: Memory Diagrams and Output Traces covers each of those cases in full.

How GATE and interviews test arrays and pointers

GATE questions commonly combine output prediction from the three precedence expressions with address calculations based on the row-major formula. Programming and Data Structures is a named subject area of the GATE CS paper, and the exact syllabus and paper pattern for the current cycle sit in the official GATE brochure published by the organising institute. The wider syllabus is covered across the GATE CS exam preparation courses.

In interviews, expect a trace-and-explain task followed by a small in-place algorithm. Reverse our array with i = 0 and j = 4:

  1. Swap 12 and 58. The array becomes {58, 25, 37, 41, 12}.

  2. Move inward and swap 25 and 41. It becomes {58, 41, 37, 25, 12}.

  3. The indices meet at index 2, so 37 never moves.

The reversal takes exactly two swaps. Once tracing feels comfortable, Data Structures MCQs is the next layer of practice.

Arrays and pointers: what to study next, in order

Climb from this foundation in a fixed order. Start with pointer-arithmetic drills. Then study strings as character arrays ending in the \0 terminator, learn pointers to functions, and finally handle dynamic memory with malloc and free.

The payoff appears in linked structures. A linked list or tree begins with a struct and one or more pointers to other nodes. Once you can trace addresses and dereferences without guessing, following a tree traversal becomes a natural next step.

The short version and your next step

  • An array is a contiguous block plus an address formula.

  • Pointer arithmetic moves in element-sized units.

  • Arrays decay to pointers in most expressions, but they are not pointers. Here, sizeof(a) is 20 while sizeof(p) is typically 8.

  • For the row-major example, b[2][1] is at address 5036.

  • Starting from 2000 each time, *p++, (*p)++, and *++p give 12, 12 with a side effect, and 25.

For a taught path through the full language, the C Programming Course places arrays and pointers inside a complete C sequence. The Coding & DSA Courses for Placements catalogue carries the language and data-structures track that follows it.

Redraw the five-box memory diagram from memory, including every address, then hand-trace the three precedence expressions. If all three answers match, you are ready for the harder pointer and 2D-address questions.