int const* p / const int* p → 指向常量的指針(內容不可改);int* const p → 常量指針(指向不可改)。&a[0]),但類型不同:a 類型 int(*)[N],&a 類型 int(*)[N](值相同,語義不同)。sizeof(a) = 整個數組字節數;sizeof(&a) = 指針大小。// 1.c char* p = "abcd"; // 2.c extern char* p[]; // 錯誤聲明:應為 extern char p[] 或 extern char* p // 直接打印 p:前者輸出字符串地址,後者若聲明正確則輸出數組首址。 // 關鍵:數組名不佔存儲空間(無地址的地址),指針變量佔空間存地址。
int a[] = {1,2,3,4,5};
int* p1 = (int*)(a + 1); // a+1 → &a[1] → 值 2
int* p2 = (int*)(&a + 1); // &a+1 → 跳過整個數組 → &a[5](越界)
int* p3 = (int*)((int)a + 1); // 地址+1 字節 → 截斷/對齊導致亂值
printf("%d %d %d\n", p1[3], p2[-1], p3[0]);
// 輸出:5 5 33554432 (視具體內存佈局而定)
核心公式:p + n = (uintptr_t)p + n * sizeof(*p)。a+1 步長 sizeof(int);&a+1 步長 sizeof(a)。
int main() {
int a = 0x1234;
char* p1 = (char*)&a;
char* p2 = (char*)&a + 1;
printf("p1=%p *p1=%x\n", p1, *p1);
printf("p2=%p *p2=%x\n", p2, *p2);
if (*p1 == 0x34 && *p2 == 0x12)
puts("Little Endian");
else
puts("Big Endian");
}
輸出:*p1=34(低位在低地址)→ 小端模式(x86/ARM 默認)。
strlen(遞歸+斷言)int strlen(char* s) {
return (assert(s), (*s ? strlen(s+1)+1 : 0));
}
利用逗號表達式、三元運算符、遞歸終止條件 *s=='\0'。僅供展示,生產環境用標準庫或迭代版。
a vs &a 是經典陷阱。htonl/ntohl 轉換。本文為「C語言指針和數組知識總結」系列上篇,下篇將覆蓋函數指針、多維數組、動態內存管理等進階主題。整理自 51CTO 技術博客筆記。