malloc/free 管理,向高地址增長,需手動釋放。static 變量、字符串常量。程序生命週期。「指針也是變量,佔 4/8 字節」。無論多少級,函數參數傳遞的是指針變量的值(地址)。
T* → 操作一維數組/單個對象。T** → 操作二維數組/修改一級指針值(輸出參數)。T*** → 極少見,通常表示更複雜的數據結構(如三維數組、指針鏈表頭指針的指針),不再簡單對應「維度」。// 分配內存並返回給調用者
int alloc_buf(char **out_buf, int size) {
*out_buf = malloc(size);
return *out_buf ? 0 : -1;
}
// 調用
char *buf = NULL;
alloc_buf(&buf, 1024); // 傳遞一級指針地址(二級指針參數)
void f(int a[10]); // 退化為 void f(int *a);
void f(int a[]); // 同上
void f(int a[3][4]); // 退化為 void f(int (*a)[4]); // 第二維保留
void f(int a[][4]); // 同上
void f(int a[2][3][4]);// 退化為 void f(int (*a)[3][4]); // 首維丟失,其餘保留
結論:函數參數無法直接傳遞任意維度數組,必須顯式傳遞除第一維外的所有維度大小,或改用扁平化一維數組 + 手動計算索引。
int *p[5]; // 指針數組:5 個 int*,可指向 5 個獨立數組/變量
int (*p)[5]; // 數組指針:指向一個包含 5 個 int 的數組
int (*p)[3][4]; // 指向 3x4 二維數組
char *argv[] = {"prog", "arg1", "arg2"}; // 指針數組,每項指向字符串常量
// main 函數簽名
int main(int argc, char *argv[]); // 等價 char **argv
// 返回 int,接受兩個 int 參數
typedef int (*BinaryOp)(int, int);
BinaryOp op = add; // 函數名隱式轉換為地址
void generic_sort(void *base, size_t n, size_t sz, int (*cmp)(const void*, const void*)) {
// 冒泡演示
for (size_t i = 0; i < n-1; i++)
for (size_t j = 0; j < n-i-1; j++)
if (cmp((char*)base + j*sz, (char*)base + (j+1)*sz) > 0)
swap((char*)base + j*sz, (char*)base + (j+1)*sz, sz);
}
int int_cmp(const void *a, const void *b) { return *(int*)a - *(int*)b; }
generic_sort(arr, n, sizeof(int), int_cmp);
[] 或 (),再向左找 *。int (*p)[5]; // p 是指針,指向含 5 個 int 的數組
int *p[5]; // p 是數組,含 5 個指向 int 的指針
int (*(*p)[5])(); // p 是指針,指向含 5 個函數指針的數組,函數返回 int
int (*(*p)())[5]; // p 是指針,指向函數,函數返回指向含 5 個 int 數組的指針
// sck_client.h
#ifndef SCK_CLIENT_H
#define SCK_CLIENT_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct SckClientHandle *SckClientHandle; // 不透明類型
int sckClient_init(SckClientHandle *handle); // 返回 0 成功
int sckClient_send(SckClientHandle handle, const unsigned char *data, int len);
int sckClient_recv(SckClientHandle handle, unsigned char **out, int *outlen); // 內部分配
void sckClient_recv_free(unsigned char **buf); // 配套釋放
int sckClient_destroy(SckClientHandle *handle); // handle 置 NULL
#ifdef __cplusplus
}
#endif
#endif
typedef struct SckClientHandle *SckClientHandle; 前向聲明,對用戶隱藏結構體定義。SckClientHandle *handle,函數內分配結構體並賦值 *handle = malloc(...)。recv 返回動態分配的緩衝區,提供配套 recv_free 釋放,避免跨模塊 free 問題(不同 CRT 堆)。destroy 接受二級指針,內部 free(*handle); *handle = NULL; 防止懸空指針。高級指針技巧的核心在於:
這些能力是從 C 初級進階為系統級開發者的必經之路。