Pointers in C for GATE

Draw pointers as addresses in boxes, then trace double pointers, arrays, swaps and precedence without guessing. The worked outputs show the method GATE rewards.

Prashant Jain

KnowledgeGate AI educator

Updated 14 Jul 20265 min read

Pointer questions feel unpredictable when you try to execute every symbol in your head. They become mechanical when you draw memory and separate an address from the value stored at that address. GATE is usually testing that model, not obscure syntax trivia.

This guide builds one drawing convention and uses it through output traces, arrays and function calls. Once the boxes are correct, the answer is often visible.

The pointer mental model: address versus value

Every variable occupies memory, has an address and stores a value. If x is an int, &x means the address of x. If p stores that address, *p means the object reached by following the address in p.

Use this convention on paper:

  • Draw one box for each variable.

  • Write the variable name above the box and its illustrative address below it.

  • Write the stored value inside the box.

  • For a pointer, draw an arrow from its stored address to the box at that address.

The actual addresses chosen by a running program are not predictable. Small round addresses in a diagram are labels for reasoning, not claims about a real machine.

Three labeled boxes for worked example 1: x at illustrative address 1000 storing 12, p at address 2000 storing 1000 with an arrow to x, and q at address 3000 storing 2000 with an arrow to p, so following q twice reaches x.

Worked double-pointer output trace

Consider this program fragment:

int x = 12;
int *p = &x;
int **q = &p;

printf("%d\n", x);
printf("%d\n", *p + 3);
printf("%d\n", **q * 2);

Trace it box by box.

  1. x stores 12, so the first output is 12.

  2. p stores &x. Following it once gives *p = 12. Therefore *p + 3 = 12 + 3 = 15.

  3. q stores &p. The first dereference, *q, gives p. The second, **q, gives x, whose value is 12. Therefore **q * 2 = 12 * 2 = 24.

The exact output is:

12
15
24

The declaration also reads from the variable outward. In int **q, q is a pointer to a pointer to an int. Count the stars to count the pointer levels, then follow the same number of arrows to reach the integer.

Pointer arithmetic and array indexing

For a pointer p of type T *, p + 1 points to the next T object. The machine address advances by sizeof(T) bytes. C scales the arithmetic for you, so you do not manually multiply the offset by sizeof(T).

Array indexing is defined through the same rule:

a[i] == *(a + i)

Now trace an array walk:

int a[] = {4, 7, 1, 9};
int *p = a;

printf("%d %d %d\n", *p, *(p + 2), p[3]);

In most expressions, a is converted to a pointer to its first element. Thus p points at a[0].

  • *p is a[0], which is 4.

  • *(p + 2) is a[2], which is 1.

  • p[3] is *(p + 3), which is a[3], or 9.

The output is 4 1 9.

An array is not a pointer variable, even though its name is converted to a pointer in many expressions. For example, sizeof(a) inside the array's own scope gives the size of the whole array, while sizeof(p) gives the size of the pointer. Also, you may increment p, but not the array name a.

Pointers and functions: why one swap fails

C passes function arguments by value. This failed swap receives copies:

void swap_bad(int a, int b) {
    int t = a;
    a = b;
    b = t;
}

Calling swap_bad(x, y) changes only local variables a and b. The caller's x and y remain untouched.

Pass their addresses when the function must change the caller's objects:

void swap(int *a, int *b) {
    int t = *a;
    *a = *b;
    *b = t;
}

int x = 3, y = 8;
swap(&x, &y);

Inside swap, dereferencing a reaches x, and dereferencing b reaches y. After the call, x = 8 and y = 3. GATE often disguises this idea as a question about whether an update survives a function return. Ask whether the function received a value or an address.

Classic pointer traps

Dangling pointers

A dangling pointer holds the address of an object whose lifetime has ended. Returning the address of a local automatic variable is the standard mistake. Dereferencing that returned pointer has undefined behaviour because the local object no longer exists.

*p++ versus (*p)++

Postfix ++ has higher precedence than unary *. Therefore *p++ is parsed as *(p++): use the current pointee, then advance the pointer. Parentheses change the other expression to increment the pointed value.

int a[] = {5, 8};
int *p = a;
int u = *p++;
int v = (*p)++;

After u = *p++, u is 5 and p points to a[1]. Then v = (*p)++ assigns the old value 8 to v and increments a[1] to 9. Final state: u = 5, v = 8, a = {5, 9}.

String literals

Code such as char *s = "GATE"; may compile, but attempting s[0] = 'L'; has undefined behaviour because a string literal is not modifiable. Use const char *s when pointing to a literal. Use char s[] = "GATE"; when you need a writable array copy.

How GATE tests pointers

Expect output traces, pointer arithmetic, arrays passed to functions, multi-level pointers and precedence. A strong order of work is: draw boxes, mark types, follow each dereference, and apply an update only to the box it actually reaches.

KnowledgeGate has about 950 published C programming questions for practice. The GATE CS subject notes help place pointers inside the wider programming syllabus, while Coding and CS fundamentals connects the same memory model to placement coding.

For the syllabus and instructions that apply to a particular attempt, check the official GATE exam papers and syllabus page. The organising site changes by cycle, so use the official site named for your attempt.

The short version

Treat a pointer as a typed box that stores an address. & produces an address, * follows one, p + i advances by i objects, and a function can update caller state only by reaching it through an address.

Revise the wider subject through the GATE category, then test this drawing method under time pressure with the GATE test series. Do not guess an output. Draw the boxes and let the arrows answer it.