char * const p:指標本身不可改(常量指標)char const * p / const char * p:指向內容不可改(指向常量的指標)const char * const p:雙重不可改char str1[] = "abc"; // 栈上各自分配,地址不同
char str2[] = "abc";
const char *p1 = "abc"; // 指向唯讀區同一字面常數
const char *p2 = "abc";
printf("%d %d %d %d", str1==str2, p1==p2, str1==p1, str2==p2);
// 輸出:0 0 0 0(若編譯器合併字面常數 p1==p2 可能為 1)
關鍵:[] 每次分配新空間;* 指向字面常數區,編譯器可合併相同常數。
void Upper(char str[]) {
for (size_t i=0; i
陣列作參數退化為指標,失去長度資訊。解法:額外傳長度或結構體封裝。
int a[5] = {1,2,3,4,5};
int *ptr = (int*)(&a + 1);
printf("%d %d", *(a+1), *(ptr-1));
// a+1 → &a[1] → 2
// &a+1 → 跨越整個陣列 → &a[5] → ptr-1 → &a[4] → 5
// 輸出:2 5
&a 型態為 int(*)[5],+1 跳過 5 個 int。
char c; char *p = &c; strcpy(p, "hello"); // 僅 1 byte,寫入 6 byte → 越界崩潰
必須 malloc 或用足夠大陣列。
char *s = "AAA"; s[0] = 'B'; // 未定義行為,通常崩潰
// 正確:char s[] = "AAA"; 或 malloc + strcpy
int (*pf[10])(int); // 10 個指標,每個指向 int func(int)
void GetMem(char *p) { p = malloc(100); } // p 為副本,外部不變
// 正確:void GetMem(char **p) { *p = malloc(100); } 呼叫 GetMem(&str);
char a[10]; printf("%zu", strlen(a)); // 未以\0結尾,讀到隨機\0 → 亂數
// sizeof 不受影響,strlen 依賴\0
char (*p)[20]; // 陣列指標
char *p[20]; // 指標陣列
struct { int b1:5; int b2:2; } s;
char buf[] = "0123456789...";
memcpy(&s, buf, sizeof(s));
// buf 前 4 byte ASCII: 0x30 0x31 0x32 0x33
// b1 取低 5 bits: 0x30 & 0x1F = 0x10 = 16 → 有號視為 -16
// b2 取次 2 bits: (0x30>>5)|(0x31<<3) ... = 1
// 輸出:-16 1
void (*fp)() = (void(*)())0x100000;
fp(); // 或 *((void(*)())0x100000)();
free(p); // p 值不變,指向已釋放記憶體
if (p) strcpy(p, "danger"); // 未定義行為,記憶體可能已重新分配
// 習慣:free(p); p = NULL;
extern int g; 告訴編譯器 g 在別處定義,連結時解析。
int *(*(*a)())[10];
// a → 函數指標 → 回傳 → 陣列指標[10] → 元素 → 指標 → int
malloc/free、strcpy、鏈表反轉const、volatile、restrict 語義