C++ 中的 Array Decay
Array decay 指的是数组类型和维度的丢失。在某些情况下,例如将数组通过指针或值传递给函数时,数组会被视为指向第一个元素的指针,而不是整个数组。因此,原始数组的大小和类型信息会丢失。
由于这种 decay,sizeof 操作符不再返回数组的完整大小,而是返回指针的大小。这会导致依赖于知道元素数量的函数出现不正确行为。

C++ 中数组退化何时发生?
数组退化会在以下场景中发生 −
- 将数组传递给函数
- 将数组赋值给指针
- 在指针运算中使用数组
让我们详细了解这三种场景以及它们如何触发数组退化。
将数组传递给函数
在将array传递给function时,数组会自动退化为pointer。退化后,函数无法接收数组的大小,只接收一个指向数组first element的指针。
以下example演示了将数组arr传递给printSize()函数时如何退化为指向第一个数组元素的指针。
#include <iostream>
using namespace std;
void printSize(int *arr){
cout << "\nSize of array inside function: "
<< sizeof(arr) << " bytes"
<< endl;
}
int main(){
int arr[5] = {1, 2, 3, 4, 5};
cout << "Original Size of the array " << sizeof(arr)
<< " bytes" << endl;
cout << "Number of elements: "
<< sizeof(arr) / sizeof(arr[0]) << endl;
// Array decay occurs here
printSize(arr);
return 0;
}
上述代码的output如下。您可以观察到将数组传递给函数before和after的大小 −
Original Size of the array 20 bytes Number of elements: 5 Size of array inside function: 8 bytes
将数组赋值给指针
在 C++ 中,您可以将数组赋值给指针。当您将数组赋值给指针时,数组会自动退化为指针。
以下是一个example,演示了在将数组arr赋值给指针ptr时发生的数组退化。
#include <iostream>
using namespace std;
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* ptr = arr; // Array decay occurs here
cout << "Accessing elements using pointer:" << endl;
for (int i = 0; i < 5; i++) {
cout << "*(ptr + " << i << ") = " << *(ptr + i) << endl;
}
cout << "Address of arr[0]: " << &arr[0] << endl;
cout << "Value of ptr: " << ptr << endl;
return 0;
}
上述代码的output如下 −
Accessing elements using pointer: *(ptr + 0) = 10 *(ptr + 1) = 20 *(ptr + 2) = 30 *(ptr + 3) = 40 *(ptr + 4) = 50 Address of arr[0]: 0x7ffd7a353890 Value of ptr: 0x7ffd7a353890
在指针运算中使用数组
您可以使用pointer arithmetic通过加法和减法等arithmetic operations来访问数组元素。这会导致数组退化,因为数组loses its size information。
在这个example中,我们使用了*(arr + 2)来访问数组的第三个元素 −
#include <iostream>
using namespace std;
int main() {
int arr[5] = {10, 20, 30, 40, 50};
cout << "Array elements: ";
for (int i = 0; i < 5; i++){
cout << arr[i] << " ";
}
cout << endl;
// Size of array before decay
cout << "Array size before decay: " << sizeof(arr)
<< " bytes" << endl;
// Array decay happens here
cout << "\n3rd element using pointer arithmetic: *(arr + 2) = "
<< *(arr + 2) << endl;
// Size after decay
cout << "Size of (arr + 2): " << sizeof(arr + 2)
<< " bytes " << endl;
return 0;
}
上述代码的output如下。您可以观察到指针before和after的元素大小 −
Array elements: 10 20 30 40 50 Array size before decay: 20 bytes 3rd element using pointer arithmetic: *(arr + 2) = 30 Size of (arr + 2): 8 bytes
C++ 中数组退化为指针引起的问题
在 C++ 编程中,array decay 可能会导致几个问题。以下列出了一些问题:
无法在函数内部确定数组大小
当数组作为function parameter传递时,array会decayed为pointer。该指针仅stores the address,且no information关于数组中的number of elements,因此 sizeof() 函数返回的是size of a pointer,无法确定数组大小。
在下面的示例中,我们将数组arr作为参数传递给函数func。我们在 main 函数和func()函数中计算了数组大小。func()函数返回数组大小。
#include <iostream>
using namespace std;
void func(int arr[]) {
// 这里发生 array decay,因为 arr[] 是作为参数传递的
int size = sizeof(arr) / sizeof(arr[0]);
cout << "Inside function:" << endl;
cout << "sizeof(arr) = " << sizeof(arr) << " bytes (pointer)" << endl;
cout << "sizeof(arr[0]) = " << sizeof(arr[0]) << " bytes" << endl;
cout << "Calculated size = " << size << " (WRONG!)" << endl;
cout << endl;
}
int main() {
int arr[5] = {1, 2, 3, 4, 5};
cout << "In main function:" << endl;
cout << "sizeof(arr) = " << sizeof(arr) << " bytes" << endl;
cout << "sizeof(arr[0]) = " << sizeof(arr[0]) << " bytes" << endl;
int size = sizeof(arr) / sizeof(arr[0]);
cout << "Calculated size = " << size << " (CORRECT!)" << endl;
cout << endl;
func(arr);
return 0;
}
上述代码的output如下 −
In main function:
sizeof(arr) = 20 bytes
sizeof(arr[0]) = 4 bytes
Calculated size = 5 (CORRECT!)
Inside function:
sizeof(arr) = 8 bytes (pointer)
sizeof(arr[0]) = 4 bytes
Calculated size = 2 (WRONG!)
Warnings/Errors:
main.cpp: In function 'void func(int*)':
main.cpp:7:23: warning: 'sizeof' on array function parameter
'arr' will return size of 'int*' [-Wsizeof-array-argument]
7 | int size = sizeof(arr) / sizeof(arr[0]);
| ~^~~~
无法使用 = 操作符复制数组
由于数组退化为指针,因此无法使用"="操作符将一个数组复制到另一个数组。'=' 操作符copies the address,但我们不能重新分配数组内存,因为它已经被固定。因此,会显示error。
以下是一个使用 "=" 操作符将一个数组复制到另一个数组的example。
#include <iostream>
using namespace std;
int main() {
int a[3] = {1, 2, 3};
int b[3];
// 这里发生 Array decay
// 'a' 退化为指向第一个元素的 pointer
b = a;
cout << "b elements: ";
for (int i = 0; i < 3; i++)
cout << b[i] << " ";
return 0;
}
上述代码的output如下 −
Warnings/Errors:
main.cpp: In function 'int main()':
main.cpp:11:7: error: invalid array assignment
11 | b = a;
| ~~^~~
无法直接比较数组
由于array names在使用时会decay to pointers,因此无法使用comparison operators(==, !=)直接比较数组。即使数组具有相同的元素,它也会return false,因为memory address不同,它会比较指针的内存地址。
以下是比较两个数组arr1和arr2的example −
#include <iostream>
using namespace std;
int main() {
int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5] = {1, 2, 3, 4, 5};
cout << "Array 1: ";
for (int i = 0; i < 5; i++)
cout << arr1[i] << " ";
cout << endl;
cout << "Array 2: ";
for (int i = 0; i < 5; i++)
cout << arr2[i] << " ";
cout << endl;
cout << "Are arr1 and arr2 same?: ";
if (arr1 == arr2)
cout << "TRUE" << endl;
else
cout << "\nFALSE" << endl;
cout << "\nAddress of arr1: " << arr1 << endl;
cout << "Address of arr2: " << arr2 << endl;
return 0;
}
上述代码的output如下。可以看出两个数组具有相同的元素,但由于地址不同,它返回 false −
Array 1: 1 2 3 4 5 Array 2: 1 2 3 4 5 Are arr1 and arr2 same?: FALSE Address of arr1: 0x7ffd8d5843b0 Address of arr2: 0x7ffd8d584390
数组退化问题的解决方案
为了避免数组退化问题,我们可以采用以下方法 −
将数组大小作为单独参数传递
为了避免数组退化,你可以将数组大小作为参数传递,与数组一起传递,因为数组的大小不会丢失。
在这个示例中,我们将数组及其大小作为函数参数传递。这里会发生数组退化,但由于有数组大小,不会引起任何问题。
#include <iostream>
using namespace std;
void printArray(int arr[], int size) {
cout << "Given array: ";
for (int i = 0; i < size; i++){
cout << arr[i] << " ";
}
cout << endl;
}
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int size = sizeof(arr) / sizeof(arr[0]);
// Passing both array and size
printArray(arr, size);
return 0;
}
上述代码的输出如下 −
Given array: 10 20 30 40 50
使用 std::array 和 std::vector
你可以使用 std::array 和 std::vector 来避免数组退化,因为这些是 C++ 中的对象,而不是数组,因此不会发生数组退化。
下面是使用 std::array 和 std::vector 避免数组退化的示例 −
#include <iostream>
#include <array>
using namespace std;
void printArray(array<int, 5> arr) {
cout << "Array size: " << arr.size() << endl;
cout << "Elements: ";
for (int num : arr){
cout << num << " ";
}
cout << endl;
}
int main() {
array<int, 5> stdArr = {1, 2, 3, 4, 5};
printArray(stdArr);
return 0;
}
上述代码的输出如下 −
Array size: 5 Elements: 1 2 3 4 5
#include <iostream>
#include <vector>
using namespace std;
void printVector(vector<int> vec) {
cout << "Vector size: " << vec.size() << endl;
cout << "Elements: ";
for(int num : vec) {
cout << num << " ";
}
cout << endl;
}
int main() {
vector<int> vec = {1, 2, 3, 4, 5};
printVector(vec);
return 0;
}
上述代码的输出如下 −
Vector size: 5 Elements: 1 2 3 4 5
结论
C++ 中的数组退化指的是由于各种原因(如将数组传递给函数、将数组赋值给指针或在指针运算中使用数组)而导致数组丢失维度和类型的信息。这可能会引起我们在本章中强调的各种问题,并提供了相应的解决方案。