Pointers in C for GATE: Memory Diagrams and Output Traces

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

KnowledgeGate Team

Exam prep & CS education

Updated 20 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.

The same three moves settle almost every pointer question: draw the boxes, mark which boxes hold addresses, and follow each address exactly as many times as the expression says. Get that right and output traces, array arithmetic and function calls stop behaving like separate topics.

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 memory boxes: 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.

Arrays are the special case in this rule. Passing an array does let the function change the caller's elements, because the array name converts to a pointer to its first element. What the function does not receive is the size: in void show(int a[]) the parameter is really int *a.

void show(int a[]) {
    /* a is int *a here */
    printf("%zu\n", sizeof(a));
}

int v[10];
printf("%zu\n", sizeof(v));
show(v);

With a 4-byte int and 8-byte pointers, sizeof(v) at the caller is 40, while sizeof(a) inside show is 8. A function that walks an array therefore needs the element count passed alongside the pointer.

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. The parentheses in (*p)++ force the dereference to happen first, so it is the pointed-to value that is incremented, and the pointer itself does not move.

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 over 1,000 C programming questions to practise this on. GATE CS Subject Weightage shows where programming sits against the rest of the GATE CS syllabus, and C Programming Interview Questions for Freshers carries the same memory model into placement rounds.

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.