request-free-img

C语言中数组名与指针的关系详解

在C语言中,数组名和指针的关系非常紧密,但它们又不是完全等价的,这让很多新手感到困惑。其实数组名本质上不是指针,但在大多数情况下,它会被隐式转换为指向数组首元素的指针。

数组名与指针的基本区别

#include <iostream>
int main()
{
int arr[5] = { 1, 2, 3, 4, 5 };
int* p = arr; // arr 被隐式转换为 &arr[0]
int size1 = sizeof(arr);
int size2 = sizeof(p);
std::cout << "size1=" << size1
<< ", size2=" << size2
<< std::endl;
return 0;
}

在这个例子中arr是一个指向5个INT元素的数组,P是一个INT型的指针。

在这个示例中,大家应该都知道sizeof(arr) 返回整个数组的大小(在我们的示例中是5 * sizeof(int))。

而p是一个指针,所以sizeof(p) 返回的是指针的大小,它在32位程序下是4个字节,而在64位系统下是8个字节。

这应该没什么疑问,是吧?

数组作为函数参数时的行为

我们这里会将有5个元素的数组ARR传给printSize函数。

在MAIN函数中,我们可以肯定sizeof(arr)的大小是5 * sizeof(int)。

但是在printSize中 sizeof(arr)的大小又是多少呢?

咱们看printSize函数的参数指定了arr是含有5个元素的int型数组,可能有人会说那它的大小肯定也是5 * sizeof(int)。

我们运行一下代码来验证一下,可以看到在printSize中sizeof(arr)是4,它只是一个int指针在32位程序下的大小。

这是很容易令新手产生疑惑的,明明在printSize函数中指定arr参数为5个元素的int型数组,为什么实际上它又只是一个指针呢?

这是因为在 C 语言中,当数组作为参数传递给函数时,数组会自动退化为指向其首元素的指针。

即使你写的是 int arr[5],编译器实际上会把它当作 int *arr 来处理。

在我们的示例中,int arr[5] 中的 5 在函数参数列表中是“装饰品”,并不会限制数组大小。

编译器只是把它当作语法糖,方便代码阅读,它表示预期处理的是数组,但不会在编译时保留数组的大小信息。

#include <iostream>
void printSize(int arr[5]) { // 这里的参数并不是数组,而是指针
std::cout << "sizeof(arr) =" << sizeof(arr)
<< std::endl;
}
int main()
{
int arr[5] = { 1, 2, 3, 4, 5 };
std::cout << "sizeof(arr) = " << sizeof(arr)
<< std::endl;
printSize(arr);
return 0;
}

如何在函数中保留数组大小信息

我们可以采用显式传递数组长度的办法。

例如在我们的函数中,可以在函数第二个参数指定了arr数组的大小。

void printArray(int *arr, int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() { int arr[5] = {1, 2, 3, 4, 5}; printArray(arr, 5); // 需要额外传递数组大小 return 0; }

总结

好了,关于数组和指针。你现在明白了吗?


更多问题探讨,请关注公众号:程序员角