C 語言函數參數中數組退化為指針:void func(int arr[]) 等價於 void func(int *arr)。函數內無法獲取數組長度,必須額外傳遞 size_t len。修改參數指向的內容會影響原數組(傳址語義)。
#include <stdio.h>
void changeArr(int arr[]) { // 等價 int *arr
arr[0] = 100; // 修改原數組內容
}
int main() {
int arr[2] = {1, 2};
printf("Before: %d\n", arr[0]); // 1
changeArr(arr);
printf("After: %d\n", arr[0]); // 100
return 0;
}
輸出證明:changeArr 直接修改了主調函數的數組內容,無需像 PHP 那樣顯式傳引用 &$arr。
count()?PHP 變量是 zval 容器,內部攜帶類型、引用計數、長度等元數據。C 數組只是連續內存塊,編譯期只知道類型與大小,運行期無任何元數據。
count() 內核實現簡析源碼位於 ext/standard/array.c:
PHP_FUNCTION(count) {
zval *array;
long mode = COUNT_NORMAL;
zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &array, &mode);
switch (Z_TYPE_P(array)) {
case IS_NULL: RETURN_LONG(0);
case IS_ARRAY: RETURN_LONG(php_count_recursive(array, mode));
case IS_OBJECT: // 實現 Countable 接口則調用 count()
// ...
default: RETURN_LONG(1); // 標量視為 1
}
}
核心 php_count_recursive 遍歷 HashTable 統計元素,支持遞歸計數。這一切建立在 PHP 變量自帶類型信息的基礎上——C 語言完全沒有這套機制。
typedef struct { int *data; size_t len; } IntArray;
void print_arr(const IntArray *a) {
for (size_t i = 0; i < a->len; i++) printf("%d ", a->data[i]);
}
typedef struct { size_t len; int data[]; } IntArrayFlex;
IntArrayFlex *create(size_t n) {
IntArrayFlex *a = malloc(sizeof(IntArrayFlex) + n * sizeof(int));
a->len = n;
return a;
}
#define ARR_LEN(arr) (sizeof(arr) / sizeof((arr)[0]))
int a[10];
printf("%zu\n", ARR_LEN(a)); // 10
// 注意:傳入函數後退化為指針,宏失效!
| 特性 | C 數組參數 | PHP 數組參數 |
|---|---|---|
| 傳遞機制 | 退化為指針(傳址) | 複製 zval 引用(寫時複製) |
| 長度信息 | 丟失,需額外傳遞 | zval 內部攜帶 |
| 修改影響 | 直接修改原內存 | 觸發 COW 複製,隔離副作用 |
| 類型安全 | 無(編譯期僅檢查指針類型) | 運行期類型檢查 |
void func(Type *arr, size_t len),名稱體現「指針+長度」。const 修飾只讀數組:void func(const int *arr, size_t len)。sizeof 獲取長度(永遠返回指針大小)。