sizeof is an operator, not a function. That distinction matters. It is evaluated at compile time in most cases, which means it can surprise you in ways that runtime functions cannot. Here are the edge cases that trip up experienced C programmers.
Basic Usage
#include <stdio.h>
int main() {
printf("sizeof(char) = %zun", sizeof(char)); /* always 1 */
printf("sizeof(int) = %zun", sizeof(int)); /* typically 4 */
printf("sizeof(long) = %zun", sizeof(long)); /* 4 or 8, platform-dependent */
printf("sizeof(double) = %zun", sizeof(double)); /* typically 8 */
printf("sizeof(void*) = %zun", sizeof(void*)); /* 8 on 64-bit, 4 on 32-bit */
return 0;
}
Use %zu (not %d) to print size_t — the type that sizeof returns. Using %d is technically undefined behaviour on 64-bit systems where size_t is 8 bytes.
Edge Case 1: sizeof on an Array Gives the Total Size
#include <stdio.h>
int main() {
int arr[10];
printf("sizeof(arr) = %zun", sizeof(arr)); /* 40 — total bytes */
printf("sizeof(arr[0]) = %zun", sizeof(arr[0])); /* 4 — one element */
printf("number of elements = %zun", sizeof(arr) / sizeof(arr[0])); /* 10 */
return 0;
}
The idiom sizeof(arr) / sizeof(arr[0]) gives the element count. This is the correct way to get array length in C — there is no .length property.
Edge Case 2: sizeof Loses Array Information in Functions
#include <stdio.h>
void print_size(int arr[]) {
printf("sizeof inside function = %zun", sizeof(arr));
/* prints 8 (pointer size) — NOT 40 */
}
int main() {
int arr[10];
printf("sizeof in main = %zun", sizeof(arr)); /* 40 */
print_size(arr);
return 0;
}
When you pass an array to a function, it decays to a pointer. Inside the function, sizeof(arr) gives the size of the pointer (8 bytes on 64-bit), not the size of the array. This is the most common sizeof mistake. Always pass the length as a separate parameter. For a full explanation of array-to-pointer decay, see our article on how pointers work in C.
Edge Case 3: sizeof on a Struct Includes Padding
#include <stdio.h>
struct Example {
char a; /* 1 byte */
int b; /* 4 bytes */
char c; /* 1 byte */
};
int main() {
printf("sizeof(struct Example) = %zun", sizeof(struct Example));
/* likely prints 12, not 6 */
return 0;
}
The compiler inserts padding bytes between struct members to align each field to its natural alignment boundary. int requires 4-byte alignment, so 3 padding bytes are inserted after a. Another 3 bytes are added after c to pad the struct to a multiple of 4.
Layout:
[a][pad][pad][pad][b b b b][c][pad][pad][pad]
1 2 3 4 5 6 7 8 9 10 11 12
Reorder members from largest to smallest to minimise padding:
struct Packed {
int b; /* 4 bytes */
char a; /* 1 byte */
char c; /* 1 byte */
/* 2 bytes padding to align struct to 4 bytes */
};
/* sizeof = 8, not 12 */
Edge Case 4: sizeof Does Not Evaluate Its Argument
#include <stdio.h>
int main() {
int x = 5;
size_t s = sizeof(x++); /* x++ is NOT evaluated */
printf("x = %d, s = %zun", x, s);
/* prints: x = 5, s = 4 */
return 0;
}
The operand of sizeof is not evaluated at runtime (except for variable-length arrays). Side effects like x++ or function calls inside sizeof do not execute. The compiler only needs the type to compute the size.
Edge Case 5: sizeof on a Pointer vs What It Points To
#include <stdio.h>
int main() {
int arr[10];
int *ptr = arr;
printf("sizeof(arr) = %zun", sizeof(arr)); /* 40 */
printf("sizeof(ptr) = %zun", sizeof(ptr)); /* 8 — pointer size */
return 0;
}
This directly relates to the char* vs char[] difference — the same rule applies to all pointer/array pairs. sizeof(pointer) always gives the pointer size, regardless of what the pointer points to.
Edge Case 6: Variable-Length Arrays (C99)
#include <stdio.h>
int main() {
int n = 5;
int arr[n]; /* variable-length array */
printf("sizeof(arr) = %zun", sizeof(arr)); /* evaluated at runtime: 20 */
n = 10;
printf("sizeof(arr) = %zun", sizeof(arr)); /* still 20 — VLA size is fixed at creation */
return 0;
}
VLAs are the one case where sizeof is evaluated at runtime. The size is determined when the VLA is created and does not change even if the variable used to size it changes afterward.
TL;DR
sizeofis a compile-time operator, not a function — it does not evaluate its operand- Use
sizeof(arr) / sizeof(arr[0])to get array element count - Array size is lost when passed to a function — always pass length separately
- Struct size includes padding — not just the sum of member sizes
sizeof(pointer)gives pointer size (4 or 8 bytes), not the pointed-to data size- Use
%zuto printsize_tvalues