C stddef.h Library Reference
Complete reference for stddef.h - NULL, size_t, ptrdiff_t, offsetof, and fundamental type definitions.
Track Your Progress
Sign in to save your learning progress
What You Will Learn
- ✓Use NULL pointer correctly
- ✓Understand size_t and ptrdiff_t
- ✓Calculate structure member offsets
- ✓Work with wide characters
?Why Use stddef.h?
stddef.h provides portable type definitions that work correctly on 32-bit AND 64-bit systems. Using size_t instead of intprevents bugs on 64-bit platforms!
NULL
Null pointer constant
size_t
Array/memory sizes
offsetof
Struct member offset
01Introduction to stddef.h
What is stddef.h?
<stddef.h> provides fundamental type definitions and macros used throughout the C standard library. It defines NULL, size_t, ptrdiff_t, and the offsetof macro.
Contents of stddef.h
| Name | Type | Description |
|---|---|---|
| NULL | Macro | Null pointer constant |
| size_t | Type | Unsigned type for sizes |
| ptrdiff_t | Type | Signed type for pointer differences |
| wchar_t | Type | Wide character type |
| offsetof | Macro | Offset of member in structure |
| max_align_t | Type (C11) | Type with maximum alignment |
02NULL Pointer Constant
NULL is a macro that represents a null pointer constant. It's typically defined as ((void*)0) or simply 0.
1#include <stdio.h>2#include <stddef.h>3#include <stdlib.h>45int main() {6 // NULL pointer initialization7 int *ptr = NULL;8 char *str = NULL;9 10 // Check if pointer is NULL11 if (ptr == NULL) {12 printf("ptr is NULL\n");13 }14 15 // Common pattern: check before dereferencing16 if (str != NULL) {17 printf("String: %s\n", str);18 } else {19 printf("String is NULL, cannot print\n");20 }21 22 // Dynamic allocation returns NULL on failure23 int *arr = malloc(1000000000000); // Very large allocation24 if (arr == NULL) {25 printf("Memory allocation failed!\n");26 } else {27 printf("Memory allocated successfully\n");28 free(arr);29 }30 31 // NULL in function returns32 FILE *fp = fopen("nonexistent.txt", "r");33 if (fp == NULL) {34 printf("File open failed\n");35 }36 37 return 0;38}3940/* Output:41ptr is NULL42String is NULL, cannot print43Memory allocation failed!44File open failed45*/Common Mistake:
Never dereference a NULL pointer! It causes undefined behavior (usually a crash). Always check pointers before using them.
03size_t - Size Type
size_t is an unsigned integer type returned by thesizeof operator. It's guaranteed to be large enough to hold the size of any object.
Why use size_t?
- It's the correct type for array sizes and indices
- It matches what
sizeofandstrlen()return - It's portable across 32-bit and 64-bit systems
1#include <stdio.h>2#include <stddef.h>3#include <string.h>45int main() {6 // sizeof returns size_t7 size_t int_size = sizeof(int);8 size_t arr_size = sizeof(int[100]);9 10 printf("Size of int: %zu bytes\n", int_size);11 printf("Size of int[100]: %zu bytes\n", arr_size);12 13 // strlen returns size_t14 const char *str = "Hello, World!";15 size_t len = strlen(str);16 printf("Length of '%s': %zu\n", str, len);17 18 // Use size_t for array indexing19 int arr[] = {10, 20, 30, 40, 50};20 size_t n = sizeof(arr) / sizeof(arr[0]);21 22 printf("\nArray elements:\n");23 for (size_t i = 0; i < n; i++) {24 printf(" arr[%zu] = %d\n", i, arr[i]);25 }26 27 // size_t on different platforms28 printf("\nSize of size_t: %zu bytes\n", sizeof(size_t));29 30 return 0;31}3233/* Output (64-bit):34Size of int: 4 bytes35Size of int[100]: 400 bytes36Length of 'Hello, World!': 133738Array elements:39 arr[0] = 1040 arr[1] = 2041 arr[2] = 3042 arr[3] = 4043 arr[4] = 504445Size of size_t: 8 bytes46*/Format Specifier:
Use %zu to print size_t values. Using %d or %ucan cause issues on 64-bit systems where size_t is 8 bytes.
04ptrdiff_t - Pointer Difference
ptrdiff_t is a signed integer type that can hold the difference between two pointers. It's the result type when you subtract one pointer from another.
1#include <stdio.h>2#include <stddef.h>34int main() {5 int arr[] = {10, 20, 30, 40, 50, 60, 70};6 7 int *start = &arr[0];8 int *end = &arr[6];9 int *mid = &arr[3];10 11 // Pointer subtraction gives ptrdiff_t12 ptrdiff_t diff1 = end - start;13 ptrdiff_t diff2 = mid - start;14 ptrdiff_t diff3 = start - end; // Negative!15 16 printf("Array: ");17 for (int i = 0; i < 7; i++) printf("%d ", arr[i]);18 printf("\n\n");19 20 printf("end - start = %td elements\n", diff1);21 printf("mid - start = %td elements\n", diff2);22 printf("start - end = %td elements\n", diff3);23 24 // Size of ptrdiff_t25 printf("\nSize of ptrdiff_t: %zu bytes\n", sizeof(ptrdiff_t));26 27 // Practical use: distance in array28 int *ptr = arr;29 while (ptr <= end) {30 ptrdiff_t index = ptr - arr;31 printf("arr[%td] = %d\n", index, *ptr);32 ptr++;33 }34 35 return 0;36}3738/* Output:39Array: 10 20 30 40 50 60 704041end - start = 6 elements42mid - start = 3 elements43start - end = -6 elements4445Size of ptrdiff_t: 8 bytes46arr[0] = 1047arr[1] = 2048...49arr[6] = 7050*/Format Specifier:
Use %td to print ptrdiff_t values.
05offsetof Macro
size_t offsetof(type, member);
The offsetof macro returns the byte offset of a member within a structure. This is useful for understanding memory layout and for low-level programming.
1#include <stdio.h>2#include <stddef.h>34// Simple structure5struct Point {6 int x;7 int y;8};910// Structure with different types (padding may occur)11struct Person {12 char name[20];13 int age;14 char gender;15 double salary;16};1718// Packed structure for comparison19#pragma pack(push, 1)20struct PackedPerson {21 char name[20];22 int age;23 char gender;24 double salary;25};26#pragma pack(pop)2728int main() {29 printf("=== struct Point ===\n");30 printf("Size: %zu bytes\n", sizeof(struct Point));31 printf("Offset of x: %zu\n", offsetof(struct Point, x));32 printf("Offset of y: %zu\n", offsetof(struct Point, y));33 34 printf("\n=== struct Person ===\n");35 printf("Size: %zu bytes\n", sizeof(struct Person));36 printf("Offset of name: %zu\n", offsetof(struct Person, name));37 printf("Offset of age: %zu\n", offsetof(struct Person, age));38 printf("Offset of gender: %zu\n", offsetof(struct Person, gender));39 printf("Offset of salary: %zu\n", offsetof(struct Person, salary));40 41 printf("\n=== struct PackedPerson ===\n");42 printf("Size: %zu bytes\n", sizeof(struct PackedPerson));43 printf("Offset of name: %zu\n", offsetof(struct PackedPerson, name));44 printf("Offset of age: %zu\n", offsetof(struct PackedPerson, age));45 printf("Offset of gender: %zu\n", offsetof(struct PackedPerson, gender));46 printf("Offset of salary: %zu\n", offsetof(struct PackedPerson, salary));47 48 return 0;49}5051/* Output (typical):52=== struct Point ===53Size: 8 bytes54Offset of x: 055Offset of y: 45657=== struct Person ===58Size: 40 bytes59Offset of name: 060Offset of age: 2061Offset of gender: 2462Offset of salary: 32 <- Note: padding added for alignment6364=== struct PackedPerson ===65Size: 33 bytes66Offset of name: 067Offset of age: 2068Offset of gender: 2469Offset of salary: 25 <- No padding70*/Advanced: Container-of Pattern
1#include <stdio.h>2#include <stddef.h>34// Common pattern in systems programming5#define container_of(ptr, type, member) \6 ((type *)((char *)(ptr) - offsetof(type, member)))78struct Node {9 int data;10 struct Node *next;11};1213struct Container {14 int id;15 char name[20];16 struct Node node; // Embedded node17};1819int main() {20 struct Container c = {21 .id = 42,22 .name = "MyContainer",23 .node = {.data = 100, .next = NULL}24 };25 26 // Get pointer to embedded node27 struct Node *node_ptr = &c.node;28 printf("node_ptr points to node with data: %d\n", node_ptr->data);29 30 // Recover container from node pointer31 struct Container *container = container_of(node_ptr, struct Container, node);32 printf("Recovered container id: %d\n", container->id);33 printf("Recovered container name: %s\n", container->name);34 35 return 0;36}3738/* Output:39node_ptr points to node with data: 10040Recovered container id: 4241Recovered container name: MyContainer42*/06wchar_t - Wide Character Type
wchar_t is a type for representing wide characters, used for internationalization and Unicode support.
1#include <stdio.h>2#include <stddef.h>3#include <wchar.h>4#include <locale.h>56int main() {7 // Set locale for proper wide character support8 setlocale(LC_ALL, "");9 10 // Wide character11 wchar_t wc = L'你';12 13 // Wide string14 wchar_t wstr[] = L"Hello, 世界!";15 16 printf("Size of char: %zu bytes\n", sizeof(char));17 printf("Size of wchar_t: %zu bytes\n", sizeof(wchar_t));18 19 // Print wide characters20 wprintf(L"Wide char: %lc\n", wc);21 wprintf(L"Wide string: %ls\n", wstr);22 wprintf(L"Length: %zu wide characters\n", wcslen(wstr));23 24 return 0;25}2627/* Output:28Size of char: 1 bytes29Size of wchar_t: 4 bytes (on Linux/macOS) or 2 bytes (on Windows)30Wide char: 你31Wide string: Hello, 世界!32Length: 10 wide characters33*/!Code Pitfalls: Common Mistakes & What to Watch For
Code often uses int for array indices and sizes, causing portability issues and potential bugs on 64-bit systems.
If you search online to "loop through an array," it will likely use for (int i = 0; ...). But array sizes in C should use size_t, which is unsigned and matches pointer size. Using signed int can cause issues with large arrays (over 2 billion elements) or when comparing with strlen() results.
The Trap: Online sources default to simple int types. They might compare a signed int loop counter with an unsigned size_t strlen() result, triggering compiler warnings or bugs with signed/unsigned comparisons. They also might not use offsetof() for portable struct offset calculations.
The Reality: Use size_t for array indices and sizes. Use ptrdiff_t for pointer differences. Use offsetof() for struct member offsets instead of manual calculations. Use the correct format specifiers: %zu for size_t, %td for ptrdiff_t.
08Frequently Asked Questions
Q:When should I use size_t instead of int?
A: Use size_t for array indices, loop counters over arrays, and anything representing sizes or counts. It's unsigned and sized to handle the largest possible array on your platform.
Q:What's the offsetof macro used for?
A: It finds the byte offset of a struct member. Useful for serialization, debugging memory layouts, and the container_of pattern used in Linux kernel and other systems code.
Q:Is NULL the same as 0?
A: In C, NULL is typically defined as (void*)0 or just0. Use NULL for pointers for clarity. In C23, prefer nullptr.
Q:Why use ptrdiff_t for pointer subtraction?
A: Pointer differences can be negative (if the second pointer is before the first). ptrdiff_t is a signed type guaranteed to hold any pointer difference on your platform.
08Quick Reference
Types
size_t- Unsigned, for sizes (%zu)ptrdiff_t- Signed, for pointer diff (%td)wchar_t- Wide characters (%lc)
Macros
NULL- Null pointer constantoffsetof(type, member)- Member offset
09Practical Tips
Always Use size_t for Sizes
Functions like malloc() and strlen()use size_t. Match their types to avoid warnings and ensure your code works correctly on 64-bit systems.
offsetof for Serialization
When writing binary file formats or network protocols, use offsetof()to verify your assumptions about struct layout. Padding can vary between compilers and platforms.
limits.h Library
Next →errno.h Library
Test Your Knowledge
Related Tutorials
C errno.h Library Reference
Complete reference for errno.h - error handling with errno, perror(), strerror(), and common error codes.
C limits.h Library Reference
Complete reference for limits.h - integer limits, overflow prevention, and portable code with INT_MAX, INT_MIN, etc.
Pointers in C
The most powerful feature in C! Pointers store memory addresses. Learn what they are, why they matter, and how to use them safely.
Have Feedback?
Found something missing or have ideas to improve this tutorial? Let us know on GitHub!