我正在自学C++,并且对数组和指针有一些疑问。 我的理解是,数组实际上只是指针,但是,数组是无法更改的地址常量。
如果是这种情况,我想知道为什么在我的函数show2()
中我能够更改指针list
的地址。 与变量不同,我认为数组是通过引用传递的,因此我预计在调用函数show2()
时会出现编译器错误,因为我增加了list
的地址。 但是代码工作得很好。 有人可以解释一下吗?
谢谢!
#include<iostream>
#include<iomanip>
using namespace std;
void show1(double *list, int SIZE)
{
for(int i=0; i < SIZE; i++)
{
cout << setw(5) << *(list+i);
}
cout << endl;
return;
}
void show2(double *list, int SIZE)
{
double *ptr = list;
for(int i=0; i < SIZE; i++)
cout << setw(5) << *list++;
cout << endl;
return;
}
int main()
{
double rates[] = {6.5, 7.2, 7.5, 8.3, 8.6,
9.4, 9.6, 9.8, 10.0};
const int SIZE = sizeof(rates) / sizeof(double);
show1(rates, SIZE);
show2(rates, SIZE);
return 0;
}
我的理解是数组实际上只是指针
让我们把它排除在外。 不,数组不是指针。 数组是一系列对象,所有对象类型相同,在内存中是连续的。
数组可以通过引用传递,但这不是通常的做法。 通常所做的,也就是你正在做的,是传递一个指向数组第一个元素的指针。 数组可以并且将根据需要"衰减"到指向其第一个元素的指针。 这就是当您将rates
传递给show1
和show2
时正在发生的事情.
在show1
和show2
中,list
开始是指向rates[0]
的指针。 您可以随意修改此指针以指向任何其他double
。
如果要通过引用传递数组,它将如下所示:
void show3(double (&list)[9]) { ... }
或者更通用:
template<size_t SIZE>
void show3(double (&list)[SIZE]) { ... }
请注意,你不能做的是按值传递数组(除非它包含在另一个对象中)。 如果您编写的函数看起来像是按值获取数组,例如
void show4(double list[9]) { ... }
它实际上是一个指针,数字 9 毫无意义。 本机数组很糟糕。
首先,当数组作为函数参数传递时,数组将转换为指向第一个元素的指针。顺便说一句,数组不是指针,例如,代码中的sizeof(rates)
不是指针的大小。
其次,数组是按值传递的,因为您没有使用引用。
所以在函数show2
中,你正在修改一个指针,这很好。
数组不是指针。C++从 C 继承了"数组指针等价",这意味着一个众所周知的数组变量可以衰减到指针,主要是为了偏移数学和避免按值传递数组:
int array[64];
int* a = array; // equivalent to a = &array[0];
数组不是指针。如果在指针上下文中使用数组变量名称,它将"衰减"到指针 - 也就是说,丢失数组对象中可用的扩展属性。
int array[64];
int* a = array;
std::cout << "array size = " << sizeof(array) << "n";
std::cout << "a size = " << sizeof(a) << "n";
std::cout << "(int*)(array) size = " << sizeof((int*)array)) << "n";
"数组大小"将为 256(int 为 4 个字节,其中 64 个 = 256 字节),"a size"将为 4 或 8 个字节,具体取决于 32/64 位,"(int*)(array)"大小将与指针大小相同。
人们通常认为数组是按值传递的。这不是真的:http://ideone.com/hAeH18
#include <iostream>
void bump(int arr[3]) {
for (size_t i = 0; i < 3; ++i)
arr[i]++;
}
int main() {
int array[] = { 1, 2, 3 };
bump(array);
for (size_t i = 0; i < 3; ++i)
std::cout << array[i] << "n";
return 0;
}
这将输出"2, 3, 4"而不是"1, 2, 3"。
发生这种情况是因为数组在作为函数参数传递时衰减到指针。但是为了支持将数组作为数组接收的语法,C 必须能够在某些上下文中像数组一样处理指针:
void f1(int* a) { a[0]++; }
void f2(int* a) { (*a)++; }
void f3(int a[]) { a[0]++; }
void f4(int a[]) { (*a)++; }
void f5(int a[1]) { a[0]++; }
void f6(int a[1]) { (*a)++; }
所有这些函数都生成相同的代码。
在 C 语言中,这源于数组信息在编译时丢失的事实。所以这个函数:
void f(int array[])
无法判断它接收的阵列有多大。他们希望程序员意识到这一点,并小心他们如何/是否传递大小信息 - 例如,在char数组的情况下,我们有nul终止符字节,而不是大小。
不幸的是,他们没有选择通过分散表示来使其变得明显,这使它看起来像您正在接收一个大小信息完整的数组:(