【问题标题】:pointer to array c++指向数组 c++ 的指针
【发布时间】:2012-05-02 10:17:57
【问题描述】:

下面的代码在做什么?

int g[] = {9,8};
int (*j) = g;

据我了解,它创建了一个指向 2 个整数数组的指针。 但是为什么这会起作用:

int x = j[0];

这不起作用:

int x = (*j)[0];

【问题讨论】:

  • @mjfgates:数组不是指针。别再告诉别人了。
  • @mjfgates 实际上在 C 和 C++ 中有一个数组对象。碰巧有一些奇怪的规则,例如,导致从数组到指向数组第一个元素的指针的隐式转换。

标签: c++ arrays pointers


【解决方案1】:
int g[] = {9,8};

这声明了一个 int[2] 类型的对象,并将其元素初始化为 {9,8}

int (*j) = g;

这声明了一个int *类型的对象,并用一个指向g的第一个元素的指针初始化它

第二个声明用 g 以外的东西初始化 j 的事实很奇怪。 C 和 C++ 只是对数组有这些奇怪的规则,这就是其中之一。这里的表达式g 被隐式地从引用对象g 的左值转换为指向g 的第一个元素的int* 类型的右值。

这种转换发生在多个地方。事实上,当您执行g[0] 时,它就会发生。数组索引运算符实际上不适用于数组,仅适用于指针。因此,int x = j[0]; 语句有效,因为 g[0] 恰好进行了与 j 初始化时相同的隐式转换。

指向数组的指针是这样声明的

int (*k)[2];

你是完全正确的关于如何使用它

int x = (*k)[0];

(注意"declaration follows use",即声明类型变量的语法如何模仿使用该类型变量的语法。)

但是,通常不使用指向数组的指针。围绕数组的特殊规则的全部目的是让您可以像使用数组一样使用指向数组元素的指针。所以惯用的 C 通常不关心数组和指针不是一回事,而且规则阻止你直接对数组做很多有用的事情。 (例如,您不能复制数组,例如:int g[2] = {1,2}; int h[2]; h = g;


例子:

void foo(int c[10]); // looks like we're taking an array by value.
// Wrong, the parameter type is 'adjusted' to be int*

int bar[3] = {1,2};
foo(bar); // compile error due to wrong types (int[3] vs. int[10])?
// No, compiles fine but you'll probably get undefined behavior at runtime

// if you want type checking, you can pass arrays by reference (or just use std::array):
void foo2(int (&c)[10]); // paramater type isn't 'adjusted'
foo2(bar); // compiler error, cannot convert int[3] to int (&)[10]

int baz()[10]; // returning an array by value?
// No, return types are prohibited from being an array.

int g[2] = {1,2};
int h[2] = g; // initializing the array? No, initializing an array requires {} syntax
h = g; // copying an array? No, assigning to arrays is prohibited

因为数组与 C 和 C++ 中的其他类型非常不一致,所以您应该避免使用它们。 C++ 的std::array 更加一致,当您需要静态大小的数组时应该使用它。如果您需要动态大小的数组,您的第一个选择是 std::vector。

【讨论】:

  • +1 用于准确描述数组/指针关系,不使用衰减二字。
【解决方案2】:

括号在您的示例中是多余的。指针不关心是否涉及到一个数组——它只知道它指向一个 int

  int g[] = {9,8};
  int (*j) = g;

也可以改写成

  int g[] = {9,8};
  int *j = g;

也可以改写为

  int g[] = {9,8};
  int *j = &g[0];

指向数组的指针看起来像

  int g[] = {9,8};
  int (*j)[2] = &g;

  //Dereference 'j' and access array element zero
  int n = (*j)[0];

在此链接中可以很好地阅读指针声明(以及如何理解它们):http://www.codeproject.com/Articles/7042/How-to-interpret-complex-C-C-declarations

【讨论】:

  • 这篇文章很有帮助,尤其是从右到左的规则,谢谢。
  • 2int (*j)[2] = &g; 中是必需的吗?如果2 被省略,它不还是一个指向数组的指针吗?
  • @johnbakers 是的,绝对有必要指定数组的长度,否则您将没有指向数组的指针,然后除非您使用强制转换,否则代码将无法编译。指向一个数组意味着您在编译时就知道它的长度。在 MSVC++ 中省略数组长度导致的编译器消息读取 error C2440: 'initializing': cannot convert from 'int (*)[2]' to 'int (*)[]'
  • 赞成,感谢您详细说明这个答案,尽管时间已经过去了
【解决方案3】:

j[0]; 取消引用指向int 的指针,因此其类型为int

(*j)[0] 没有类型。 *j 取消引用指向 int 的指针,因此它返回 int(*j)[0] 尝试取消引用 int。这就像尝试int x = 8; x[0];

【讨论】:

  • 另外,请记住j[0] 等价于*(j + 0)。因此(*j)[0] 等价于j[0][0],后者等价于*(*(j + 0) + 0),即**j。不管你怎么看,它都行不通。
  • 那么你将如何创建指向一组数组元素的指针?
  • 您将指针设置为第一个元素,并像使用数组一样使用它,因为j[1] == *(j + 1) == the next element in the array
  • @SamAdams 问道:“如何创建指向一组数组元素的指针?”像这样:int (*j)[2]cdecl is your friend
  • @Robᵩ 虽然这是一个指向数组的指针,但通常您实际上并不想要指向数组的指针。惯用 C 使用指向其中一个元素的指针,我会说完全避免使用原始数组。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-25
  • 2013-04-19
  • 2023-03-11
  • 2010-10-25
  • 1970-01-01
  • 2016-09-17
相关资源
最近更新 更多