C Programming Basics for GATE CS – Data Types, Operators, Control Flow | EngineeringHulk


C Programming Basics for GATE CS

Data types, sizeof, operators, precedence, storage classes, control flow — with GATE-level output tracing questions and common traps.

Last updated: April 2026  |  GATE CS 2024–2026 syllabus

Key Takeaways for GATE

  • Data type sizes are implementation-defined — GATE uses standard 32-bit assumptions: int=4B, char=1B, float=4B, double=8B, pointer=4B (32-bit) or 8B (64-bit).
  • In C (not C++), character literals like 'a' are int, so sizeof('a')=4.
  • Operator precedence traps: sizeof > arithmetic > relational > logical. Always use parentheses in GATE answers.
  • Storage classes: auto (stack, no init), static (data segment, 0 init, persists), register (hint to compiler), extern (linkage).
  • static local variable retains value across calls — favourite GATE output-prediction trap.
  • Preprocessor runs before compilation — #define does blind text substitution with no type checking.
  • Short-circuit evaluation: && stops on first false, || stops on first true — affects side effects.

1. Data Types & Sizes

TypeSize (32-bit)Range (signed)Format
char1 byte−128 to 127%c, %d
short2 bytes−32768 to 32767%hd
int4 bytes−231 to 231−1%d
long4 bytes (32-bit) / 8 bytes (64-bit)system-dependent%ld
long long8 bytes−263 to 263−1%lld
float4 bytes±3.4×1038%f
double8 bytes±1.7×10308%lf
pointer4 bytes (32-bit) / 8 bytes (64-bit)%p
GATE rule: Unless specified, assume 32-bit system: int=4B, pointer=4B.
sizeof(char) ≤ sizeof(short) ≤ sizeof(int) ≤ sizeof(long) ≤ sizeof(long long)
sizeof(float) ≤ sizeof(double) ≤ sizeof(long double)

C vs C++ trap:
C:    sizeof('a') = sizeof(int) = 4    (char literal is int in C)
C++: sizeof('a') = sizeof(char) = 1

2. Storage Classes

ClassStorageScopeLifetimeDefault init
autoStackBlockBlock durationGarbage
registerRegister (hint)BlockBlock durationGarbage
static (local)Data segmentBlockProgram lifetime0
static (global)Data segmentFile (internal linkage)Program lifetime0
externData segmentFile (external linkage)Program lifetime0
static local — GATE favourite:

int counter() {
    static int c = 0;   // initialised once, persists across calls
    return ++c;
}
// counter() returns 1, 2, 3, ... on successive calls

static global: visible only within the file — prevents name clashes in multi-file programs.
extern: declares a variable defined in another translation unit — no storage allocation.

3. Operators & Precedence

Precedence (high to low, key groups):
1. () [] → . (postfix)   2. ++ — (prefix) * & sizeof (unary)   3. * / %
4. + –   5. << >>   6. < <= > >=   7. == !=
8. & (bitwise)   9. ^   10. |   11. &&   12. ||   13. ?:
14. = += -= etc. (right-to-left)   15. , (comma)
ExpressionResultReason
5 > 3 > 10(5>3)=1, then 1>1=0
2 & 3 | 46(2&3)=2, 2|4=6
1 << 3 + 116+ before <<: 1<<4=16
a++ + ++aUBUndefined behaviour (modify twice)
sizeof(int+3.0)8int+3.0 promotes to double=8B
!0 == 11!0=1, 1==1=1
Short-circuit evaluation (critical for GATE):
f() && g() — if f() returns 0, g() is never called.
f() || g() — if f() returns non-zero, g() is never called.
This affects programs with side effects (printf inside conditions).

4. Control Flow

for loop: for(init; cond; update) — update runs AFTER body.
while vs do-while: do-while executes body at least once (condition checked at bottom).

switch-case fallthrough:

switch(x) {
  case 1: printf("one");      // no break — falls through
  case 2: printf("two"); break;
  case 3: printf("three");
}
// if x=1: prints "onetwo". Fallthrough is intentional C behaviour.

break vs continue vs goto:
break: exits innermost loop/switch.   continue: skips to next iteration.   goto: unconditional jump (avoid).

Dangling else: else binds to the nearest unmatched if.

if (a) if (b) x=1; else x=2;  // else belongs to inner if(b)

5. Preprocessor Directives

Preprocessor runs before compilation. It does text substitution — no type checking.

#define macro traps:

#define SQ(x) x*x
SQ(3+2) → 3+2*3+2 = 11  (not 25!)
// Fix: #define SQ(x) ((x)*(x))

#ifdef / #ifndef: Conditional compilation for platform-specific code.
#include “file” searches current directory first; #include <file> searches system paths.

sizeof vs macro:
sizeof is a compile-time operator, not a function — sizeof(int) not sizeof int().
#define MAX(a,b) ((a)>(b)?(a):(b)) evaluates arguments twice — use inline functions instead.

6. Type Conversion & Implicit Promotion

Integer promotion: char and short are promoted to int in expressions.
Usual arithmetic conversion (lower → higher):
char → int → unsigned int → long → unsigned long → float → double → long double

Common GATE traps:

char c = 255;
printf("%d", c);        // -1 (signed char overflow → implementation-defined)

unsigned int a = 5, b = 10;
printf("%d", a - b);    // large positive number! (wraps around in unsigned)

int x = 3, y = 2;
float f = x/y;          // f = 1.0, not 1.5 (integer division first)
float g = (float)x/y;  // g = 1.5 (correct)

7. GATE Examples

GATE 2018 — What is the output?

#include <stdio.h>
int f(int n) {
    static int r = 0;
    if (n <= 0) return 1;
    if (n > 3) { r = n; return f(n-2) + 2; }
    return f(n-1) + r;
}
int main() { printf("%d", f(5)); }

Trace: f(5): r=5, f(3)+2.   f(3): f(2)+r=f(2)+5.   f(2): f(1)+r=f(1)+5.   f(1): f(0)+r=1+5=6.
f(2)=6+5=11. f(3)=11+5=16. f(5)=16+2=18.   Output: 18

GATE 2020 — What does this print?

#include <stdio.h>
#define MAX(x,y) (x>y?x:y)
int main() {
    int a=2, b=3;
    printf("%d", MAX(a++, b++));
}

Macro expands to: (a++>b++?a++:b++). a++=2, b++=3, 2>3 is false, so b++ = 4 (post-increment after b was already incremented in condition). Output: 4

GATE 2022 — Storage class question:

void f() {
    static int x = 5;
    x++;
    printf("%d ", x);
}
int main() { f(); f(); f(); }

First call: x initialised to 5, incremented to 6. Second: x persists as 6, becomes 7. Third: 8.
Output: 6 7 8

8. Common Mistakes

  • sizeof('a') in C vs C++: In C, char literals are int (size 4). In C++, char literal is char (size 1). GATE usually specifies C — answer 4.
  • Macros with side effects: MAX(a++, b++) increments both arguments — macro arguments are not functions. Use inline functions instead.
  • Unsigned arithmetic underflow: unsigned int a=5, b=10; a-b wraps to a large positive number, not −5. Unsigned subtraction is modular.
  • Integer division: 3/2 = 1 in C, not 1.5. Cast at least one operand to float/double for real division.
  • Dangling else: else always binds to the nearest if, regardless of indentation. Use braces to be explicit.

9. FAQ

What is the size of int in C?
The C standard only guarantees int ≥ 16 bits. On modern 32-bit and 64-bit systems, int is almost always 4 bytes (32 bits). GATE questions assume 4 bytes unless stated otherwise. Always use sizeof(int) in real code to be portable.
What is the difference between static and auto storage class in C?
auto variables live on the stack, have block scope and lifetime, and are uninitialized (garbage values). static local variables live in the BSS/data segment, have block scope but program lifetime, are initialized to 0 by default, and retain their value across function calls — making them useful for counters and caches.
What is the output of printf("%d", sizeof('a')) in C?
In C, character literals like ‘a’ are of type int (not char), so sizeof(‘a’) = sizeof(int) = 4 bytes on most systems. This is a common GATE trap. In C++, ‘a’ is char so sizeof(‘a’) = 1. The question specifies the language — always check.
What is the difference between #define and const in C?
#define is a preprocessor macro — text is substituted before compilation, so it has no type, no scope, and can’t be watched in a debugger. const creates a typed, scoped variable that the compiler can check and optimize. In C, const variables are not true compile-time constants (unlike C++), so use enum or #define for array sizes in C.