Tutorials Logic, IN info@tutorialslogic.com
C Language

Top 50 C Language Interview Questions

Curated questions covering pointers, memory management, arrays, strings, structures, file handling, and data structures in C.

01

What is C and what are its key features?

C is a general-purpose procedural language developed by Dennis Ritchie in 1972. Key features: low-level memory access via pointers, efficient execution, portable across platforms, structured programming, rich operators, and it is the foundation for C++, Java, and many other languages.

02

What is the difference between compiled and interpreted languages?

Compiled languages (C, C++) translate source code to machine code before execution - faster runtime. Interpreted languages (Python, JavaScript) translate at runtime - slower but more flexible. C is compiled: gcc/clang converts .c files to optimized machine code.

03

What is the difference between int, long, short, and char?

  • char - 1 byte. Stores characters or small integers (-128 to 127 signed).
  • short - 2 bytes. Range: -32,768 to 32,767.
  • int - typically 4 bytes. Range: -2,147,483,648 to 2,147,483,647.
  • long - 4 or 8 bytes depending on platform. Use long long for guaranteed 8 bytes.
Example
printf("%zu\n", sizeof(int));   // 4
printf("%zu\n", sizeof(long));  // 4 or 8
printf("%zu\n", sizeof(char));  // 1
04

What is a pointer in C?

A pointer is a variable that stores the memory address of another variable. Pointers enable dynamic memory allocation, efficient array handling, and passing variables by reference.

Example
int x = 10;
int *ptr = &x;  // ptr holds address of x
printf("%d\n", *ptr);  // 10 (dereference)
*ptr = 20;  // modifies x through pointer
printf("%d\n", x);  // 20
05

What is the difference between * and & operators?

  • & (address-of) - returns the memory address of a variable.
  • * (dereference) - accesses the value at the memory address stored in a pointer.
  • * in declaration - declares a pointer variable.
Example
int x = 5;
int *p = &x;      // & gets address, * declares pointer
printf("%d", *p); // * dereferences to get value 5
06

What is the difference between pass by value and pass by reference?

  • Pass by value - a copy is passed. Changes inside the function do not affect the original.
  • Pass by reference - the address is passed via pointer. Changes inside the function affect the original.
Example
void byValue(int x) { x = 100; }  // original unchanged
void byRef(int *x) { *x = 100; }  // original changed
int n = 5;
byValue(n);  // n still 5
byRef(&n);   // n is now 100
07

What is the difference between arrays and pointers?

  • Array name is a constant pointer to the first element. Cannot be reassigned.
  • Pointer is a variable that can point to any memory location and can be reassigned.
  • sizeof(array) returns total array size; sizeof(pointer) returns pointer size (4 or 8 bytes).
Example
int arr[5] = {1,2,3,4,5};
int *ptr = arr;  // ptr points to arr[0]
printf("%d", *(ptr + 2));  // 3 (pointer arithmetic)
printf("%d", arr[2]);      // 3 (same result)
08

What is pointer arithmetic?

When you add 1 to a pointer, it advances by sizeof(type) bytes, not 1 byte. This allows traversing arrays efficiently.

Example
int arr[] = {10, 20, 30, 40};
int *p = arr;
p++;  // advances by sizeof(int) = 4 bytes
printf("%d\n", *p);  // 20
printf("%d\n", *(arr + 3));  // 40
09

What is a null pointer?

A null pointer does not point to any valid memory location. Represented by NULL (0 or (void*)0). Always initialize pointers to NULL and check before dereferencing to avoid undefined behavior.

Example
int *ptr = NULL;
if (ptr != NULL) {
  printf("%d", *ptr);
} else {
  printf("Null pointer");
}
10

What is a dangling pointer?

A dangling pointer points to memory that has been freed or gone out of scope. Dereferencing it causes undefined behavior. Always set pointers to NULL after freeing.

Example
int *ptr = (int*)malloc(sizeof(int));
*ptr = 10;
free(ptr);
ptr = NULL;  // prevent dangling pointer

// Also: returning address of local variable
int* bad() { int x = 5; return &x; } // WRONG
11

What is the difference between malloc, calloc, realloc, and free?

  • malloc(size) - allocates size bytes. Memory is uninitialized (contains garbage).
  • calloc(n, size) - allocates n*size bytes. Memory is zero-initialized.
  • realloc(ptr, newSize) - resizes previously allocated memory.
  • free(ptr) - releases allocated memory. Always free to prevent memory leaks.
Example
int *a = (int*)malloc(5 * sizeof(int));   // uninitialized
int *b = (int*)calloc(5, sizeof(int));    // zero-initialized
a = (int*)realloc(a, 10 * sizeof(int));   // resize
free(a); a = NULL;
12

What is a memory leak?

A memory leak occurs when dynamically allocated memory is not freed after use. The memory remains allocated but inaccessible, gradually consuming available memory. Use Valgrind to detect leaks.

Example
void leak() {
  int *p = (int*)malloc(100 * sizeof(int));
  // forgot free(p) - memory leak!
}
void noLeak() {
  int *p = (int*)malloc(100 * sizeof(int));
  free(p); p = NULL;
}
13

What is the difference between stack and heap memory?

  • Stack - automatic memory for local variables and function calls. Fast. Limited size. Managed automatically.
  • Heap - dynamic memory allocated with malloc/calloc. Larger. Must be manually freed. Slower allocation.
14

What is a structure in C?

A structure (struct) groups variables of different types under a single name.

Example
struct Student {
  char name[50];
  int age;
  float gpa;
};
struct Student s1;
strcpy(s1.name, "Alice");
s1.age = 20;
s1.gpa = 3.8;

typedef struct { char name[50]; int age; } Student;
15

What is the difference between struct and union?

  • struct - each member has its own memory. Total size = sum of all member sizes (plus padding).
  • union - all members share the same memory. Total size = size of the largest member. Only one member holds a value at a time.
Example
union Data {
  int i;    // 4 bytes
  float f;  // 4 bytes
  char c;   // 1 byte
}; // sizeof = 4 (largest member)
union Data d;
d.i = 10;  // only d.i is valid now
16

What is the difference between #define and const?

  • #define - preprocessor macro. No type checking. Replaced textually before compilation. No memory allocated.
  • const - typed constant. Type-checked by compiler. Has memory address. Preferred in C99+.
Example
#define MAX 100        // no type, no memory
const int MAX = 100;  // typed, has address

// #define can cause bugs:
#define SQUARE(x) x*x
SQUARE(2+3)  // expands to 2+3*2+3 = 11, not 25!
17

What is the difference between #include with angle brackets and quotes?

  • #include - searches in system/compiler include directories. Used for standard library headers.
  • #include "file.h" - searches in the current directory first, then system directories. Used for user-defined headers.
18

What is the difference between local and global variables?

  • Local variables - declared inside a function. Stored on stack. Accessible only within that function. Destroyed when function returns.
  • Global variables - declared outside all functions. Stored in data segment. Accessible throughout the program. Persist for program lifetime.
Example
int globalVar = 10;  // global
void func() {
  int localVar = 5;  // local
  printf("%d %d", globalVar, localVar);
}
19

What is the static keyword in C?

  • Static local variable - retains its value between function calls. Initialized only once.
  • Static global variable/function - limits scope to the current file (internal linkage).
Example
void counter() {
  static int count = 0;  // persists between calls
  count++;
  printf("%d\n", count);
}
counter(); // 1
counter(); // 2
20

What is the extern keyword?

extern declares a variable or function defined in another file. It tells the compiler the definition exists elsewhere, allowing multi-file programs to share variables.

Example
// file1.c
int globalVar = 10;

// file2.c
extern int globalVar;  // declaration only
void func() { printf("%d", globalVar); }
21

What is a function pointer?

A function pointer stores the address of a function and can be used to call it indirectly. Used for callbacks, dispatch tables, and implementing polymorphism in C.

Example
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }

int (*op)(int, int);  // function pointer
op = add;
printf("%d\n", op(3, 2));  // 5
op = sub;
printf("%d\n", op(3, 2));  // 1
22

What is string handling in C?

Strings in C are null-terminated character arrays. The standard library (string.h) provides functions for string manipulation.

Example
char str[50] = "Hello";
strlen(str);           // 5
strcpy(dest, str);     // copy
strcat(str, " World"); // concatenate
strcmp(s1, s2);        // compare (0 if equal)
strncpy(dest, src, n); // safe copy with limit
23

What is the difference between gets() and fgets()?

  • gets() - reads a line from stdin. Does NOT check buffer size - vulnerable to buffer overflow. Removed in C11.
  • fgets(str, size, stream) - reads at most size-1 characters. Safe. Always use fgets().
Example
char buf[100];
fgets(buf, sizeof(buf), stdin);  // safe
buf[strcspn(buf, "\n")] = 0;     // remove trailing newline
24

What is file handling in C?

C provides FILE* type and functions from stdio.h for file operations.

Example
FILE *fp = fopen("data.txt", "r");
if (fp == NULL) { perror("Error"); exit(1); }
char line[256];
while (fgets(line, sizeof(line), fp)) {
  printf("%s", line);
}
fclose(fp);
25

What is the difference between fread/fwrite and fprintf/fscanf?

  • fprintf/fscanf - text mode I/O. Data stored as human-readable text.
  • fread/fwrite - binary mode I/O. Data stored as raw bytes. Faster for structured data.
Example
FILE *fp = fopen("data.bin", "wb");
fwrite(&student, sizeof(Student), 1, fp);
fclose(fp);
fp = fopen("data.bin", "rb");
fread(&student, sizeof(Student), 1, fp);
26

What is the difference between typedef and #define for type aliases?

  • typedef - creates a true type alias. Type-checked by compiler. Works correctly with pointers.
  • #define - textual substitution. No type checking. Can cause subtle bugs with pointer types.
Example
typedef unsigned int uint;  // proper type alias
typedef struct Node* NodePtr;

#define UINT unsigned int
// UINT *p1, p2; -> p2 is NOT a pointer!
27

What is a linked list in C?

A linked list is a dynamic data structure where each node contains data and a pointer to the next node.

Example
struct Node {
  int data;
  struct Node *next;
};
struct Node* createNode(int data) {
  struct Node *n = (struct Node*)malloc(sizeof(struct Node));
  n->data = data;
  n->next = NULL;
  return n;
}
28

What is the difference between -> and . operators?

  • . (dot) - accesses members of a structure variable directly.
  • -> (arrow) - accesses members of a structure through a pointer. Equivalent to (*ptr).member.
Example
struct Point p = {3, 4};
printf("%d", p.x);    // dot: direct access
struct Point *ptr = &p;
printf("%d", ptr->x); // arrow: pointer access
29

What is the difference between pre-increment and post-increment?

  • ++i (pre-increment) - increments i first, then returns the new value.
  • i++ (post-increment) - returns the current value first, then increments i.
Example
int i = 5;
printf("%d", ++i);  // prints 6, i is 6
printf("%d", i++);  // prints 6, i becomes 7
printf("%d", i);    // prints 7
30

What is the difference between signed and unsigned integers?

  • signed int - can represent negative and positive values. Range: -2^31 to 2^31-1 for 32-bit.
  • unsigned int - only non-negative values. Range: 0 to 2^32-1 for 32-bit.
Example
unsigned int u = 4294967295; // max uint32
int s = -1;
printf("%u", (unsigned int)s); // 4294967295 (same bits)
31

What is the difference between logical and bitwise operators?

  • Logical (&&, ||, !) - work on boolean values. Short-circuit evaluation.
  • Bitwise (&, |, ^, ~, <<, >>) - work on individual bits of integers.
Example
int a = 5;  // 0101
int b = 3;  // 0011
printf("%d", a & b);  // 1  (0001)
printf("%d", a | b);  // 7  (0111)
printf("%d", a ^ b);  // 6  (0110)
printf("%d", a << 1); // 10 (1010)
32

What is the difference between void pointer and NULL pointer?

  • void* (generic pointer) - can point to any data type. Must be cast before dereferencing.
  • NULL pointer - a pointer with value 0. Points to nothing. Dereferencing causes undefined behavior.
Example
void *vp;
int x = 10;
vp = &x;
printf("%d", *(int*)vp);  // must cast
int *np = NULL;
// *np = 5;  // undefined behavior!
33

What is the difference between recursive and iterative solutions?

  • Recursive - function calls itself. Cleaner for tree/graph problems. Uses stack space. Risk of stack overflow.
  • Iterative - uses loops. More memory-efficient. Generally faster.
Example
int factR(int n) { return n <= 1 ? 1 : n * factR(n-1); }
int factI(int n) {
  int r = 1;
  for (int i = 2; i <= n; i++) r *= i;
  return r;
}
34

What is the difference between enum and #define for constants?

  • enum - creates a named integer type. Values auto-assigned (0,1,2...). Type-checked. Debugger-friendly.
  • #define - textual substitution. No type. No automatic sequencing.
Example
enum Direction { NORTH, SOUTH, EAST, WEST }; // 0,1,2,3
enum Status { OK=200, NOT_FOUND=404, ERROR=500 };
enum Direction d = NORTH;
35

What is the difference between memcpy and memmove?

  • memcpy(dest, src, n) - copies n bytes. Undefined behavior if regions overlap.
  • memmove(dest, src, n) - copies n bytes safely even if regions overlap. Slightly slower.
Example
char str[] = "Hello World";
memmove(str + 6, str, 5);  // safe overlap
char dest[20];
memcpy(dest, str, strlen(str) + 1); // non-overlapping
36

What is the difference between sizeof and strlen?

  • sizeof(arr) - compile-time operator. Returns total bytes allocated including null terminator.
  • strlen(str) - runtime function. Returns number of characters before the null terminator.
Example
char str[] = "Hello";
printf("%zu", sizeof(str));  // 6 (5 chars + null)
printf("%zu", strlen(str));  // 5 (without null)
37

What is the difference between atoi and strtol?

  • atoi(str) - converts string to int. No error detection. Returns 0 for invalid input.
  • strtol(str, endptr, base) - converts string to long. Detects errors via endptr. Preferred.
Example
int n = atoi("42");          // 42, no error check
char *end;
long l = strtol("42abc", &end, 10);
printf("%s", end);  // "abc" - where conversion stopped
38

What is the difference between const pointer and pointer to const?

  • const int *ptr - pointer to const int. Cannot modify the value. Pointer can be reassigned.
  • int * const ptr - const pointer to int. Cannot reassign the pointer. Can modify the value.
  • const int * const ptr - both pointer and value are const.
Example
int x = 5, y = 10;
const int *p1 = &x;  // *p1 = 6 is error; p1 = &y is OK
int * const p2 = &x; // p2 = &y is error; *p2 = 6 is OK
39

What is the difference between a macro function and a regular function?

  • Macro function (#define) - expanded inline by preprocessor. No type checking. No call overhead. Side effects with expressions.
  • Regular function - type-checked. Has call overhead. Safer. Use inline for performance.
Example
#define MAX(a,b) ((a)>(b)?(a):(b))  // macro
MAX(x++, y++);  // x or y incremented twice!
static inline int max(int a, int b) { return a > b ? a : b; }
40

What is the difference between stack overflow and buffer overflow?

  • Stack overflow - call stack exceeds its limit. Usually from infinite recursion or very large local arrays.
  • Buffer overflow - writing beyond the bounds of an array. Can corrupt adjacent memory and cause security vulnerabilities.
Example
void infinite() { infinite(); }  // stack overflow
char buf[10];
strcpy(buf, "This is way too long"); // buffer overflow!
41

What is the difference between while and do-while loops?

  • while - condition checked before each iteration. May not execute at all if condition is false initially.
  • do-while - executes at least once. Condition checked after each iteration.
Example
int i = 10;
while (i < 5) { printf("never"); }  // never executes
do { printf("once"); } while (i < 5); // executes once
42

What is the difference between break and continue?

  • break - exits the loop or switch statement immediately.
  • continue - skips the rest of the current iteration and moves to the next.
Example
for (int i = 0; i < 10; i++) {
  if (i == 3) continue;  // skip 3
  if (i == 7) break;     // stop at 7
  printf("%d ", i);      // 0 1 2 4 5 6
}
43

What is the difference between call by value and call by reference for arrays?

Arrays are always passed by reference in C - the function receives a pointer to the first element. Modifying the array inside the function modifies the original.

Example
void modify(int arr[], int n) {
  arr[0] = 99;  // modifies original
}
void readOnly(const int arr[], int n) {
  // arr[0] = 99;  // compile error
}
44

What is the difference between exit() and return in main()?

  • return in main() - returns control to the OS. Calls atexit() handlers and flushes buffers.
  • exit(status) - terminates from anywhere. Also calls atexit() handlers and flushes buffers.
  • _exit(status) - terminates immediately without cleanup. Use only in child processes after fork().
45

What is the difference between printf format specifiers %d, %u, %f, %s, %p?

  • %d / %i - signed decimal integer.
  • %u - unsigned decimal integer.
  • %f - floating point (decimal notation).
  • %s - null-terminated string.
  • %p - pointer address.
  • %c - single character.
  • %x - hexadecimal integer.
  • %zu - size_t (use for sizeof/strlen results).
46

What is the difference between memset and bzero?

  • memset(ptr, value, n) - fills n bytes with value. Standard C function.
  • bzero(ptr, n) - fills n bytes with zeros. POSIX only, deprecated. Use memset(ptr, 0, n) instead.
Example
int arr[10];
memset(arr, 0, sizeof(arr));  // zero all elements
memset(arr, -1, sizeof(arr)); // fill with 0xFF bytes
47

What is the difference between fopen modes r, w, a, r+, w+, a+?

  • "r" - read only. File must exist.
  • "w" - write only. Creates or truncates.
  • "a" - append only. Creates if not exists.
  • "r+" - read and write. File must exist. No truncation.
  • "w+" - read and write. Creates or truncates.
  • "a+" - read and append. Creates if not exists.
48

What is the difference between local scope, file scope, and block scope?

  • Block scope - variables inside {} braces. Accessible only within that block.
  • Function scope - labels (goto targets) are function-scoped.
  • File scope - variables declared outside all functions. Accessible throughout the file.
  • Global scope - extern variables accessible across multiple files.
49

What is the difference between structure padding and packing?

  • Structure padding - compiler adds extra bytes between members to align them to their natural alignment. Improves performance but wastes memory.
  • Structure packing - forces no padding using __attribute__((packed)) or #pragma pack. Saves memory but may be slower.
Example
struct Padded { char c; int i; };   // sizeof = 8 (padding added)
struct __attribute__((packed)) Packed { char c; int i; }; // sizeof = 5
50

What is the difference between static and dynamic memory allocation?

  • Static allocation - size determined at compile time. Stack or data segment. Fast. Cannot resize.
  • Dynamic allocation - size determined at runtime using malloc/calloc. Heap. Can resize with realloc. Must be freed manually.
Next Step

Use C Programming interview prep to move into practice and application.

After reviewing interview answers, strengthen the same topic with tutorials, coding practice, or a stronger resume story.

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.