无法将'int *'转换为'int []'?

10

我知道这可能是一个常见的问题,但我已经尝试过搜索,仍然找不到清晰的答案。

我有以下代码:

int* f() {
    int a[] = {1,2,3};
    return a;
}

int main() {

    int a[] = f(); // Error here

    getch();
    return 0;
}

这段代码会产生错误信息:"无法将'int *'转换为'int []'"

我觉得这很奇怪,因为我读过指针和数组是相似的。例如,我们可以使用a[i]代替*(a + i)。 有人能给我一个清晰的解释吗?


"a[i] instead of *(a + i)" 这个在非 char 类型的数组中不成立。也许可以用 *(a + sizeof(a[0])*i)。但我不确定这种写法是否适用于所有情况。 - Vinicius Kamakura
4
@a[i] == *(a+i) 这个等式通常是正确的,除非数组 a 的类型不完整或者是 void* 类型。 - Alexander Gessler
8
数组不是指针,指针也不是数组。建议您阅读c-faq的第6节。提示:选择“逐节阅读”。 - pmg
2
@hexa:即使是除了char以外的类型,该身份仍然是正确的;您没有考虑指针算术运算的工作方式。 - Matteo Italia
这里没有人提到,但你可能想使用一个vector返回值。 - Neil G
4个回答

23

这段代码中实际上存在两个错误。

首先,你返回的是一个临时变量的地址(在 f 中的 int 数组),因此函数返回后它的内容是未定义的。任何尝试访问所返回指针指向的内存都会导致未定义行为。

其次,在 C++ 中指针和数组类型之间不存在隐式转换。虽然它们相似但并不完全相同。数组可以衰减为指针,但反过来则不起作用,因为在这个过程中信息会丢失——一个指针只表示一个内存地址,而一个数组表示具有特定大小的连续区域的地址。另外,你不能对数组进行赋值。

例如,我们可以使用 a[i] 而不是 *(a + i)

然而,这与数组和指针之间的差异关系不大,它只是一个针对指针类型的语法规则。由于数组衰减为指针,因此它也适用于数组。


12

类型int[]实际上并不存在。

当您定义和初始化一个数组时,例如:

int a[] = {1,2,3};

编译器会计算初始化器中的元素数量,并创建一个合适大小的数组;这种情况下,它会自动变成:

int a[3] = {1,2,3};

函数的参数类型应该是int[],但实际上是一个普通的int *,也就是指向数组第一个元素的指针。它没有携带任何其他信息,特别是没有保留有关数组大小的信息。同样的情况也出现在返回指针时。

需要注意的是,数组不是指针:指针可以被改变来指向其他的东西,而数组始终指向相同的内存;指针并不知道它所指向的内存空间有多大,而数组的大小在编译时总是已知的。混淆的原因在于,许多情况下数组会退化为指向其第一个元素的指针,而将其传递给函数/从函数返回是其中之一。

那么,为什么你的代码不起作用呢?这里有两个大错误:

  1. 你试图用一个指针来初始化一个数组。我们说过,int *并不携带任何关于数组大小的信息。它只是指向第一个元素的指针。因此编译器无法知道应将a设置为多大以容纳f()返回的东西。

  2. f函数中,你返回了一个指向该函数局部变量的指针。这是错误的,因为指针并不实际存储数据,它只是指向数据存储的位置,即在你的情况下是局部于f中的a。由于这个数组是局部的,当函数退出时(即在return处),它就不存在了。

    这意味着你返回的指针指向的是已经不存在的东西;请考虑以下代码:

int * a = f();

这种初始化方式是可以工作的,您可以尝试在函数中稍后使用a,但是a将指向不再存在的f数组;在最好的情况下,您的程序将崩溃(并且您会立即注意到自己做错了什么),在最坏的情况下,它似乎会运行一段时间,然后开始产生奇怪的结果。


2

int *和int []类似但又不同。int *是一个真正的指针,而int []是一个数组引用(一种指向数据开头的“常量指针”),不能被修改。因此,int *可以像int []一样处理,但反之则不行。


2
int[] 不是一个常量指针。我建议您阅读c-faq的第6节。 - pmg
@pmg:我尝试修改我的答案。请看一下。有时候我仍然在用英语写作中遇到一些问题。 - Heisenbug
现在好多了...如果不是那个“引用”在里面,哈哈,但我认为那是C++的东西 :) - pmg

0

您可以互换使用a[b]*(a+b),因为当其中一个是指针而另一个是整数或枚举类型时,这正是a[b]的定义方式。

注意:这也意味着像42[a]这样的表达式是完全合法的。尽管人类读者可能会强烈反对,但编译器不会对此感到惊讶。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接