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.

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.
xstores12, so the first output is12.pstores&x. Following it once gives*p = 12. Therefore*p + 3 = 12 + 3 = 15.qstores&p. The first dereference,*q, givesp. The second,**q, givesx, whose value is12. Therefore**q * 2 = 12 * 2 = 24.
The exact output is:
12
15
24The 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].
*pisa[0], which is4.*(p + 2)isa[2], which is1.p[3]is*(p + 3), which isa[3], or9.
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.


