Experienced C Interview Questions
What is the difference between malloc() and calloc() in C?
| malloc() | calloc() |
|---|---|
malloc(size) takes one argument (total bytes) | calloc(n, size) takes two arguments |
| Memory has garbage values | Memory is set to zero |
| Slightly faster | Slightly slower because of the zeroing |
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *a = calloc(3, sizeof(int));
printf("%d %d %d\n", a[0], a[1], a[2]);
free(a);
return 0;
}
Output:
0 0 0
Both return NULL if the memory is not available, and both must be released with free(). See Dynamic Memory Allocation.
What is a memory leak in C and how to avoid it?
A memory leak happens when the program allocates memory with malloc(), calloc() or realloc() but never frees it. The program keeps using more and more memory, and a long running program can finally crash.
void leak(void) {
int *p = malloc(100 * sizeof(int));
// no free(p) here, and the pointer p is lost when the function ends
}
How to avoid it:
- Call
free()for everymalloc(). - Free the memory on all paths, also on the error paths.
- Set the pointer to
NULLafter freeing. - Use tools like Valgrind or the AddressSanitizer (
-fsanitize=address) to find leaks.
What is a dangling pointer in C?
A dangling pointer is a pointer which still holds an address, but the memory at that address is no longer valid. Using it is undefined behavior.
Common causes:
- The memory was released with
free(), but the pointer was still used. - A function returns the address of its local variable.
- The pointer points to a block which has ended.
int *bad(void) {
int x = 10;
return &x; // x is destroyed when the function ends
}
int *p = malloc(sizeof(int));
free(p);
p = NULL; // good habit: no dangling pointer now
The fix is to set the pointer to NULL after free(), and never return the address of a local variable. See Pointers and Functions.
What is the difference between an array and a pointer in C?
| Array | Pointer |
|---|---|
| Fixed block of memory with its own size | A variable which stores an address |
sizeof(arr) gives the total bytes | sizeof(p) gives the pointer size |
| Name cannot be changed to point elsewhere | Can point to any place |
| Memory is allocated automatically | Memory is given by the programmer, or it points to an existing one |
#include <stdio.h>
int main(void) {
int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;
printf("%zu %zu\n", sizeof(arr), sizeof(p));
printf("%d %d\n", arr[2], p[2]);
return 0;
}
Output:
20 8
3 3
The array name acts like a pointer in most expressions (it “decays”), and that is why they look alike. See Pointers and Arrays.
What is a void pointer in C?
A void * is a generic pointer. It can store the address of any type, but you cannot dereference it directly. You must cast it to the right type first.
#include <stdio.h>
int main(void) {
int n = 42;
float f = 3.5f;
void *p;
p = &n;
printf("%d\n", *(int *)p);
p = &f;
printf("%.1f\n", *(float *)p);
return 0;
}
Output:
42
3.5
malloc() returns a void *, and functions like qsort() and memcpy() use it to work with any type.
What is a function pointer in C?
#include <stdio.h>
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int calc(int (*op)(int, int), int x, int y) {
return op(x, y);
}
int main(void) {
printf("%d\n", calc(add, 10, 4));
printf("%d\n", calc(sub, 10, 4));
return 0;
}
Output:
14
6
The function calc() does not know which operation it will run. This idea is used for callbacks, menus and the compare function of qsort(). See Pointers and Functions.
What is the difference between const and #define in C?
| const | #define |
|---|---|
| Has a data type | No data type, only text |
| Handled by the compiler | Handled by the preprocessor |
| Follows scope rules | Valid from the line it is written |
| Has a memory address | No address |
Example: const int MAX = 10; and #define MAX 10. Prefer const (or enum) for plain values, because it is safer. See C Constants.
What is the difference between #include with angle brackets and with double quotes in C?
#include <stdio.h>searches the standard system include folders. Use it for standard and library headers.#include "myheader.h"searches the folder of the current file first, and then the system folders. Use it for your own headers.
The exact search order depends on the compiler. See Preprocessor and Macros.
What is a segmentation fault in C?
A segmentation fault (segfault) happens when a program reads or writes memory that it should not touch. The operating system stops the program.
Common causes:
- Dereferencing a NULL or uninitialized pointer.
- Accessing an array outside its limits.
- Using memory after
free(). - Very deep recursion (stack overflow).
- Writing to a string literal, like
char *s = "abc"; s[0] = 'x';.
To find it, compile with -g and run with a debugger like GDB, or use -fsanitize=address to see the exact line.
What is the volatile keyword in C?
volatile tells the compiler that the value of a variable can change at any time, from outside the normal program flow. So the compiler must read it from memory each time, and cannot keep it in a register.
volatile int flag = 0; // may be changed by an interrupt or another thread
while (flag == 0) {
// wait
}
Without volatile the compiler may see that the loop never changes flag and turn it into an infinite loop. It is used for hardware registers, interrupt handlers and signal flags. It does not make the code thread safe.
What is structure padding in C?
The compiler adds empty bytes (padding) between structure members so that each member starts at an address that suits its type. So the size of a structure can be more than the sum of its members.
#include <stdio.h>
struct A { char a; int b; char c; };
struct B { int b; char a; char c; };
int main(void) {
printf("%zu\n", sizeof(struct A));
printf("%zu\n", sizeof(struct B));
return 0;
}
Output:
12
8
Both have the same members, but the order in struct B wastes less space. A good habit is to put the bigger members first.
What is the difference between memcpy() and strcpy() in C?
| strcpy() | memcpy() |
|---|---|
| Only for strings | For any data (int arrays, structures) |
| Stops at the null character | Copies exactly n bytes |
| Does not need a size | Needs the number of bytes |
#include <stdio.h>
#include <string.h>
int main(void) {
int a[3] = {1, 2, 3};
int b[3];
memcpy(b, a, sizeof(a));
printf("%d %d %d\n", b[0], b[1], b[2]);
return 0;
}
Output:
1 2 3
For overlapping memory use memmove(), because memcpy() does not handle it.
What is the difference between stack and heap memory in C?
| Stack | Heap |
|---|---|
| Local variables and function calls | Memory from malloc(), calloc(), realloc() |
| Managed automatically | Managed by the programmer with free() |
| Very fast | Slower |
| Limited size (stack overflow) | Much bigger |
| Memory ends when the function ends | Lives until freed |
See Dynamic Memory Allocation and Recursion.
What is undefined behavior in C?
Undefined behavior (UB) means the C standard gives no rule about what the program will do. It may work, crash, or give a wrong result, and it can change with the compiler or the options.
Common examples:
- Reading an uninitialized variable.
- Accessing an array outside its limits.
- Dereferencing a NULL or dangling pointer.
- Signed integer overflow, like
INT_MAX + 1. - Modifying a variable two times in one expression, like
i = i++ + ++i. - Dividing by zero.
The danger is that the program may look fine on your computer. Compile with -Wall -Wextra and use -fsanitize=undefined to catch many of them.
Why should we not use the gets() function in C?
gets() reads a line but has no way to know the size of the array. If the user types more characters than the array can hold, the extra characters are written outside the array. This is a buffer overflow, and attackers can use it. The function was removed from the C11 standard.
#include <stdio.h>
int main(void) {
char name[10];
fgets(name, sizeof(name), stdin); // reads at most 9 characters
printf("%s", name);
return 0;
}
fgets() takes the size, so it is safe. Note that it keeps the new line character. See String Input and Output.
What is the difference between int main() and int main(void) in C?
In C, int main() says nothing about the parameters, so the function can be called with any arguments (in older C standards). int main(void) clearly says that it takes no parameters. So int main(void) is the better and safer form.
If you want the command line arguments, use int main(int argc, char *argv[]). See Command Line Arguments.
Note that in C++ both forms mean the same thing. Also void main() is not standard, so always use int.
What is the difference between a macro and a function in C?
| Macro | Function |
|---|---|
| Text replace by the preprocessor | Compiled code that is called |
| No type checking | Types are checked |
| Code is copied at each use (bigger program) | One copy of the code |
| Faster, no call overhead | Small call overhead |
Arguments can run two times (SQUARE(i++)) | Arguments are evaluated once |
Use a function when you can. Use macros for constants and small tricks only. See Preprocessor and Macros.