C 標準規定:**函數參數宣告為陣列時,自動調整為指向首元素的指標**。因此 void f(char ca[]) 與 void f(char *pa) 在編譯器眼中完全等價,sizeof(ca) 回傳指標大小而非陣列大小。
#include <stdio.h>
void print_array_test(char ca[]) {
printf("ca : %s\n", ca);
printf("&ca : %p\n", (void*)&ca); // 參數自身位址(棧上)
printf("&ca[0] : %s\n", &ca[0]); // 首元素位址 = 陣列位址
printf("&ca[1] : %s\n", &ca[1]); // 次元素位址
printf("*(ca+0) : %c\n", *(ca+0));
printf("*(ca+1) : %c\n", *(ca+1));
printf("ca+1 : %s\n", ca+1);
}
void print_ptr_test(char *pa) {
printf("pa : %s\n", pa);
printf("&pa : %p\n", (void*)&pa); // 參數自身位址
printf("&pa[0] : %s\n", &pa[0]);
printf("&pa[1] : %s\n", &pa[1]);
printf("pa+1 : %s\n", pa+1);
printf("pa[1] : %c\n", pa[1]);
printf("*(pa+1) : %c\n", *(pa+1));
printf("++pa : %s\n", ++pa); // 指標可修改
}
int main() {
char abc[] = "hello,world!";
print_array_test(abc);
print_ptr_test(abc);
return 0;
}
ca : hello,world!
&ca : 0x7ffd... // 不同於 &ca[0],證明 ca 是區域指標變數
&ca[0] : hello,world!
&ca[1] : ello,world!
*(ca+0) : h
*(ca+1) : e
ca+1 : ello,world!
pa : hello,world!
&pa : 0x7ffd... // 與 &ca 相同位置(同一棧框)
&pa[0] : hello,world!
&pa[1] : ello,world!
pa+1 : ello,world!
pa[1] : e
*(pa+1) : e
++pa : ello,world! // pa 可自增,ca 則不可
&ca 是函數參數(指標變數)在棧上的位址,&ca[0] 是實際陣列首元素位址(呼叫端記憶體)。兩者數值不同,徹底證明 ca 是指標而非陣列。[] 在指標上同樣有效,本質皆為指標算術。ca 雖是指標,但屬區域變數,C 標準禁止修改參數陣列宣告的指標值(雖部分編譯器允許並發出警告)。A declaration of a parameter as ''array of type'' shall be adjusted to ''qualified pointer to type''...
編譯器在語義分析階段即完成調整,故函數體內完全看不見原始陣列大小資訊。
void f(char *pa, size_t len) 或 void f(char pa[], size_t len) 兩種寫法效果相同,前者語意更清晰。const:void f(const char *pa, size_t len)。void f(int a[3][4]); // 調整為 int (*a)[4] —— 指向 4 元素 int 陣列的指標
void f(int a[][4]); // 同樣,第一維退化,第二維保留
void f(int *a[4]); // 這是「指標陣列」,非二維陣列!
只有**最左維**會退化,後續維度資訊保留在指標型別中,這也是為何動態分配二維陣列常用「指標陣列」或「單一連續區塊 + 手動索引」的原因。