void reverse_array(int arr[], int n); // 等價於
void reverse_array(int *arr, int n); // 等價於
void reverse_array(int arr[10], int n); // 10 被忽略,仍退化為指標
**函數內部無法得知原始陣列大小**,必須額外傳遞 n。
void reverse(int x[], int n) {
int m = (n - 1) / 2; // 交換次數
for (int i = 0; i <= m; ++i) {
int j = n - 1 - i; // 對稱位置
int temp = x[i];
x[i] = x[j];
x[j] = temp;
}
}
// 呼叫:reverse(a, 10); // a 退化為 &a[0]
主程式 a[10] 與函數參數 x[] **共享同一塊記憶體**,函數內交換直接修改原陣列。
void reverse_ptr(int *x, int n) {
int *i = x; // 指向首元素
int *p = x + (n - 1) / 2; // 指向中間元素(終止條件)
int *j = x + n - 1; // 指向尾元素
for (; i <= p; ++i, --j) {
int temp = *i;
*i = *j;
*j = temp;
}
}
i、j,直接移動指標。| 維度 | 陣列名版本 int x[] | 指標版本 int *x |
|---|---|---|
| 語意 | 暗示「這是一個陣列」 | 明確「這是一個指標」 |
| 內部操作 | x[i] 索引訪問 | *x 解引用 + 指標算術 |
| 編譯器視角 | 完全相同,均退化為 int* | 完全相同 |
| 可讀性 | 初學者友好 | 資深開發者偏好 |
| 現代 C++ 建議 | 棄用兩者,改用 std::span<T> (C++20) 或迭代器對 std::reverse(begin, end) | |
#include <algorithm>
#include <vector>
#include <span> // C++20
// C++98 風格
void legacy_reverse(int *arr, int n) {
std::reverse(arr, arr + n);
}
// C++20 std::span:保留大小、邊界檢查、支援陣列/容器/指標
void modern_reverse(std::span<int> s) {
std::reverse(s.begin(), s.end());
}
// 容器版本
void container_reverse(std::vector<int> &v) {
std::reverse(v.begin(), v.end());
}
int main() {
int a[10] = {0,1,2,3,4,5,6,7,8,9};
modern_reverse(a); // 陣列隱式轉 span
std::vector<int> v = {0,1,2,3,4,5,6,7,8,9};
container_reverse(v);
}
| 錯誤代碼 | 問題 | 修正 |
|---|---|---|
void f(int a[]) { int n = sizeof(a)/sizeof(a[0]); } | sizeof(a) 取得指標大小,非陣列大小 | 額外傳遞 size 參數或用 std::span |
void f(int a[10]) { ... } 傳入 5 元素陣列 | 參數退化為指標,編譯器不檢查大小 | 用 std::array<int,10> 強制大小 |
函數內 delete[] arr; | 釋放非堆記憶體 → 未定義行為 | 只有 new[] 分配的記憶體才能 delete[] |
int a[]、int *a、int a[N] 在函數簽名中**完全等價**。std::span、std::vector、std::array + STL 算法**,獲得型別安全、邊界檢查、大小感知、意圖清晰的介面。