宣告指標 int *p; 只配置指標本身 (4/8 bytes),不配置指向物件的空間。未初始化指標含隨機位址,解參考導致 UB。
int *i;
char *str;
*i = 7899; /* 災難:寫入隨機位址 */
str = "Good"; /* 合法但指向唯讀區,後續 *str='B' 會崩潰 */
#include
int main(void)
{
int *pi = malloc(sizeof(int)); /* 配置 1 個 int */
if (!pi) return 1; /* 檢查配置失敗 */
*pi = 420;
char *ps = malloc(20); /* 配置 20 bytes */
if (!ps) { free(pi); return 1; }
strcpy(ps, "Good, Answer!");
/* 使用結束 */
free(ps);
free(pi);
return 0;
}
int *pa = malloc(3 * sizeof(int)); /* 3 個 int */
if (!pa) return 1;
pa[0] = 1234; /* 等價 *(pa+0) */
pa[1] = 4567; /* 等價 *(pa+1) */
pa[2] = 234; /* 等價 *(pa+2) */
free(pa);
pa + i 位址 = pa + i * sizeof(*pa) 位元組。
16-bit 環境 sizeof(int)=2 → pa+1 相隔 2 位元組;
32/64-bit 環境 sizeof(int)=4 → pa+1 相隔 4 位元組。
| 函式 | 標頭檔 | 回傳 | 行為 |
|---|---|---|---|
malloc(size_t n) | | void* (對齊足夠最大型別) | 配置 n 位元組,內容不定 |
calloc(n, size) | | void* | 配置 n×size 並歸零 |
realloc(ptr, n) | | void* | 調整大小,可能移動位址 |
free(ptr) | | void | 釋放,ptr=NULL 安全無效 |
NULL,直接解參考 → Crash。if (!p) { handle_error(); }free(p); free(p); → Heap 損壞。free(p); p = NULL;free(&local_var); 或 free("literal"); → UB。malloc/calloc/realloc 回傳位址。free(p); *p = 0; → Use-after-free。NULL。int *p = malloc(10); (漏 sizeof(int)) 只配 10 bytes。int *p = malloc(n * sizeof *p); (推薦寫法,自動適應型別變更)。
/* 靜態記憶池,避免 heap 碎片與非確定性 */
#define POOL_SIZE 4096
static uint8_t pool[POOL_SIZE];
static size_t offset = 0;
void *pool_alloc(size_t n)
{
if (offset + n > POOL_SIZE) return NULL;
void *p = &pool[offset];
offset += n;
return p;
}
void pool_reset(void) { offset = 0; } /* 一次歸還所有 */
std::unique_ptr:RAII 自動釋放。std::vector:動態陣列,自動管理記憶體。std::string:字串處理,免手動 malloc/strcpy。純 C 專案請嚴守「誰配置、誰釋放、配配對、檢查 NULL、釋放置 NULL」六字訣。