Pointers and manual memory management define C, and cause most of its bugs. Once pointers click, arrays, strings, and dynamic structures turn out to be one idea.
Addresses and pointers
Every object lives at some address. &x yields the address of x, a pointer stores it, and *p (dereferencing) reads or writes the object it points to.
#include <stdio.h>
void swap(int *a, int *b) { /* modifies the caller's variables */
int tmp = *a;
*a = *b;
*b = tmp;
}
int main(void) {
int x = 10, y = 20;
int *p = &x; /* p holds the address of x */
printf("address of x: %p\n", (void *)p);
*p = 15; /* x is now 15 */
swap(&x, &y);
printf("x=%d y=%d\n", x, y); /* x=20 y=15 */
return 0;
}
Arguments are still passed by value, but a copied address still reaches the caller's object. Use NULL for pointers with no target and check before dereferencing.
Pointer arithmetic and arrays
Pointer arithmetic counts elements, not bytes: for an int *p, p + 1 is the next int. An array name usually converts to a pointer to its first element, so a[i] is *(a + i).
#include <stdio.h>
int sum(const int *begin, const int *end) {
int total = 0;
for (const int *p = begin; p != end; p++) {
total += *p;
}
return total;
}
int main(void) {
int a[] = {1, 2, 3, 4, 5};
size_t n = sizeof a / sizeof a[0];
int *p = a; /* same as &a[0] */
printf("%d %d\n", *(p + 2), a[2]); /* 3 3 */
printf("%d\n", sum(a, a + n)); /* a + n: one past the end */
return 0;
}
A pointer may point into an array or one past its end, but that last position is for comparisons only. Subtracting two pointers gives a ptrdiff_t element count, and only within the same array.
malloc and free
Data sized at run time, or that outlives its function, goes on the heap (<stdlib.h>):
malloc(size) allocates size bytes with indeterminate contents.calloc(count, size) allocates and zero-fills.realloc(ptr, size) resizes, possibly moving the block to a new address.free(ptr) releases the block; free(NULL) is a no-op.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t cap = 4, len = 0;
int *items = malloc(cap * sizeof *items);
if (items == NULL) return 1; /* allocation can fail */
for (int v = 1; v <= 10; v++) {
if (len == cap) {
size_t new_cap = cap * 2;
int *tmp = realloc(items, new_cap * sizeof *tmp);
if (tmp == NULL) { /* items is still valid */
free(items);
return 1;
}
items = tmp;
cap = new_cap;
}
items[len++] = v * v;
}
printf("len=%zu cap=%zu last=%d\n", len, cap, items[len - 1]);
free(items);
items = NULL; /* guard against reuse */
return 0;
}
Assigning realloc straight back to the original pointer leaks the block on failure, hence the temporary. sizeof *items stays right if the element type changes.
Ownership conventions
Nothing frees memory for you, so every allocation needs a clear owner:
- Pair every
xxx_create that allocates with an xxx_destroy. - A
const T * parameter is borrowed: the function neither frees nor keeps it. - Each block has exactly one owner that releases it.
#include <stdlib.h>
#include <string.h>
typedef struct {
char *name; /* owned; freed in player_destroy */
int score;
} Player;
/* Returns a new Player or NULL. Caller releases it with player_destroy. */
Player *player_create(const char *name, int score) {
Player *p = malloc(sizeof *p);
if (p == NULL) return NULL;
p->name = malloc(strlen(name) + 1);
if (p->name == NULL) {
free(p);
return NULL;
}
strcpy(p->name, name); /* safe: buffer sized exactly */
p->score = score;
return p;
}
void player_destroy(Player *p) {
if (p == NULL) return;
free(p->name);
free(p);
}
Undefined behavior to avoid
Undefined behavior (UB) means the standard places no requirements on the result: code can work today and break under another compiler or optimization level.
Warnings, sanitizers, and tools like Valgrind catch most of these during development.
Summary
- Pointers hold addresses:
& takes one, * dereferences. Check for NULL first. - Pointer arithmetic is valid only within an array or one past its end.
- Check every
malloc, route realloc through a temporary, and free each block exactly once. - Make ownership explicit with create/destroy pairs.
- Find undefined behavior with tools; prevent it with discipline.
Further reading
0 comments
Sign in · Sign in to leave a comment.