リリース・改善中
C ガイド · 6/6
この章は現在、英語でのみ提供しています。
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.
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 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.
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.
Nothing frees memory for you, so every allocation needs a clear owner:
xxx_create that allocates with an xxx_destroy.const T * parameter is borrowed: the function neither frees nor keeps 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 (UB) means the standard places no requirements on the result: code can work today and break under another compiler or optimization level.
| Mistake | Example | Prevention |
|---|---|---|
| Null dereference | *p with p == NULL | Check before dereferencing |
| Out-of-bounds access | a[n] | Pass lengths and check them |
| Use after free | free(p); p->x | Set pointers to NULL after freeing |
| Double free | free(p); free(p); | Give each block one owner |
| Uninitialized read | int x; x + 1 | Initialize at declaration |
| Returning a local's address | return &local; | Allocate or use a caller buffer |
| Signed overflow | INT_MAX + 1 | Check ranges before the operation |
| Modifying a string literal | char *s = "hi"; s[0] = 'H'; | Use char s[] = "hi"; |
Warnings, sanitizers, and tools like Valgrind catch most of these during development.
& takes one, * dereferences. Check for NULL first.malloc, route realloc through a temporary, and free each block exactly once.
コメント 0件
ログイン · ログインするとコメントできます。
最初のコメントを書いてみましょう。