【问题标题】:Why do a[] and *a behave differently?为什么 a[] 和 *a 的行为不同?
【发布时间】:2017-05-19 22:49:55
【问题描述】:

我认为a[]*a 是同一个东西,因为它们的工作方式类似于指针。然而我在下面的代码中遇到了一些意想不到的东西:

#include <iostream>
using namespace std;

class F {
public:
    bool a[];
    F();
};

F::F() {
    *a = new bool[5];
    a[2] = true;
}

int main() {
    F obj;
    if(obj.a[2])
        cout << '?';
    return 0;
}

这段代码打印?,但我不明白它是如何工作的。时间:

*a = new bool[5];

改为:

a = new bool[5];

编译器报告:

F:\main.cpp|11|error: incompatible types in assignment of 'bool*' to 'bool [0]'|

我发现这种行为很奇怪,所以我在玩这个代码。当我把a的类型从bool改成int编译器总是报错

F:\main.cpp|11|error: invalid conversion from 'int*' to 'int' [-fpermissive]|

为什么会这样?

【问题讨论】:

  • bool a[]; 作为成员是编译器扩展,而不是标准 C++。你不使用std::vector有什么原因吗?
  • @TartanLlama 也许他喜欢他的内存泄漏;)
  • 当你写new时,它是在堆上创建一个指向bool数组的指针。由于a本身就是数组,所以*a是bool数组指针的正确等价。
  • @TartanLlama 我不太擅长 STL,所以我尝试使用默认数据类型。
  • @MarkoDivjak 你忘记了释放你的数组的析构函数new[]

标签: c++ arrays oop pointers


【解决方案1】:

我认为a[]*a 是同一个东西,因为它们的工作方式类似于指针。

我们来说说这段声明:

int a[4] = { 1, 2, 3, 5 };
int *b = NULL;

这是它们在可执行文件中进入内存的方式:

   +----+----+----+----+
a: |  1 |  2 |  3 |  5 |        <-- 4 integers
   +----+----+----+----+

   +----------+
b: |   NULL   |                   <-- 1 pointer that points to nowhere
   +----------+

如您所见,它们不是相同的东西。

b = new int[4]; 之后会发生什么?

b 的新内存布局是这样的:

   +----------+
b: | 0xacf3de |               <-- 1 pointer that points to a block of 4 integers
   +----------+

Somewhere else in memory (at address 0xacf3de)...

          +----+----+----+----+
0xacf3de: |  ? |  ? |  ? |  ? |         <-- 4 integers
          +----+----+----+----+

但是等等,有人告诉我数组的工作方式类似于指针......

不,那不是真的。数组不像指针那样工作。

数组名 (a, f.e.) 可以用作它在内存中的地址(实际上是它的第一个元素的地址)的快捷方式。以下符号是等价的:

a
&a
&a[0]

它们的值都是内存中存储a的第一个元素(上例中的1)的地址。

a[0]int&amp;a[0]int *。这是完整的表格。另外两个是该语言提供的快捷方式,以使代码更易于阅读和理解。

指针的情况有所不同。

b 是存储在b 变量中的值(上例中的NULL0xacf3de。它是int * 类型的值——int 所在的内存地址存储。&amp;b 是内存中存储b 的地址(的值)。它的类型是int ** -- 指向指向int 的指针的指针;或“存储在内存中的地址int"的地址。

但是等等,在某些情况下它们可以相互替换

在某种程度上,是的,指针和数组是可以互换的。正如您在上面看到的,涉及到一个常见的数据类型:int *。它是b 的类型(存储int 的地址),也是&amp;a[0] 的类型(也是int 的地址)。

这意味着在可以使用b 的地方,可以使用a&amp;a[0] 的缩写)代替,反之亦然。

另外,在可以使用*b 的地方,可以使用*a 代替。它是*&amp;a[0]的缩写,意思是“存储在a[0]的地址(&amp;)的值(*),实际上和a[0]一样。

但是,在&amp;b可以使用的地方,&amp;a不能改为使用;请记住&amp;a&amp;a[0] 相同,其类型为int *(但&amp;b 的类型为int **)。

【讨论】:

    【解决方案2】:

    行:

    *a = new bool[5];
    

    相当于:

    a[0] = new bool[5];
    

    您不是在初始化您的数组,而是分配一个 bool 数组,然后将其隐式转换为 bool 以分配给 a[0]:该值应为 true,因为指针由 new 返回应该不同于0。这种隐式转换不适用于ints:这就是您在更改a 的类型时收到错误的原因。


    现在,考虑这一行:

    a = new bool[5];
    

    在这里,您尝试将动态分配的数组分配给a,换句话说,将指向数组bool* 的指针分配给静态数组bool[0]:正如编译器所说,类型不兼容。静态数组a[] 可以用作指针,例如在以下代码中:

    int foo(bool* a) { /* ... */ }
    
    bool my_array[5];
    foo(my_array);
    

    但是指针不能像你试图做的那样转换成静态数组。

    【讨论】:

    • new返回的指针始终有效且非空:如果分配失败,则抛出异常。
    • @EdgarRokyan ...在这种情况下,它是不言自明的;)
    • @Quentin 是的,当然:)
    • 也许你可以对这个问题更明确一点(“为什么 a[] 和 *a 的行为不同?”)。我会想象一些关于它们何时可以等效使用(函数参数,...)以及初始化的不同之处。
    【解决方案3】:

    new Type[x] 返回的值的类型是Type *,即该类型的指针

    例如: 所以正确的语法是 bool a;

    *a = new bool[x];

    所以这样做是错误的

    a=new bool[x] 语法错误,因为将指针分配给普通变量是无效的

    see for more details

    【讨论】:

      猜你喜欢
      • 2017-03-21
      • 1970-01-01
      • 2019-03-07
      • 2015-09-14
      • 2014-03-29
      • 1970-01-01
      • 1970-01-01
      • 2021-10-06
      • 2020-04-13
      相关资源
      最近更新 更多