int (*p) [4]?

9

int (*p) [4] ;

这里的 "p" 是指向一个包含 4 个整数的数组的指针吗?

那么如何为这个指针调用 "new" 呢?


如下所示的答案表明,这种类型声明令人困惑且不直观,因此最好避免使用(除非要添加过多注释)。如果您使用其他结构,可以以更可读的方式实现相同的结果(例如std::vector<>或boost::array)。 - Martin York
@Martin:std::vector<>int (*p)[4]是完全不同的东西! - Seth
2
@Seth: 但是,int (*p)[4] 可以更好地被两个维度的 std::vector<std::vector<int> > 或一个带有手动索引算术的一维 std::vector<int> 或者是 boost::multi_array<int, 2> 替换。 - fredoverflow
@Martin York,@FredOverflow:感谢你们的回答,但我在我的项目中没有使用这个数组来存储数据。 但是我们大学有一位医生非常喜欢这种问题:(虽然它很令人困惑:( - Farah_online
3个回答

7

“p”是指向一个包含4个整数的数组的指针吗?

正确!

我该如何为这个指针调用“new”?

例如,p = new int[7][4]


3
编辑前,“was +1” 的意思不明确。新建一个 int[7][4] 数组会给你一个单个块宽度为 28 的数组。 - Billy ONeal
嗯...所以我认为p是4个整数指针的指针,每个指针都指向一个包含4个整数的数组,对吗? - Farah_online
3
@Billy: 我的示例没有问题。 new int[7][4] 的类型确实是 int (*)[4]。也许使用typedef更明显?typedef int row[4]; row *p = new row[7]; 这与我的代码完全等效,只是更易读。你会认为这也是错误的吗? - fredoverflow
@Farah:不,它不是指向4个整数指针的指针,它实际上是指向4个整数的指针。请记住,指针可以指向数组的单个元素(就像char*可以指向C字符串的字符一样)。 - fredoverflow
3
@Billy:欢迎来到C声明符的语法地狱;-) 我找到的最好的参考资料是5.3.4(§5和§6)。 - fredoverflow
显示剩余3条评论

6

int (*p)[4] 实际上是一个指向包含四个 int 的数组的指针。

您可以通过以下方式动态分配类型为“指向四个 int 数组”的对象。

int (**ptr)[4] = new (int (*)[4]);

注意,不会分配任何int的空间;只有指针本身。
您可以按如下方式分配一个包含4个int的数组:
int *ptr = new int[4];

你不能(未经显式转换)将指向动态分配的4个int数组的指针分配给类型为int(*)[4]的指针。无论您是否使用typedef通过new分配数组,新表达式的类型始终是指向数组第一个元素的指针;数组的大小不保留在new表达式的类型中。
这是因为new[]表达式可以分配在运行时选择数组大小的数组,因此不总是可能(甚至不可取)将数组大小编码到new表达式的类型中。
正如建议的那样,您可以动态分配一个包含4个int数组的数组。第一个数组的大小从类型信息中丢失,您得到的是一个指向四个int数组的大小为1的数组的第一个元素的指针。
int (*p)[4] = new int[1][4];

即使它只是一个长度为1的数组(包含4个整数的数组),您仍然需要使用delete[]来释放p

delete[] p;

2
当然,一个人永远不应该处于需要手动调用delete的位置。 - GManNickG
那么,int (*p)[4] = new int[4][4] ... 我该如何调用删除操作符?我尝试了:for (int i=0;i<4;i++) delete[] p[i] ; delete[] p ;但这并没有起作用 :( - Farah_online
2
@Farah_online:无论数组大小如何,您始终使用delete[] p;删除数组。因此,p = new int[1][4]; ... delete[] pp = new int [4][4]; ... delete[] p。调用数组成员上的delete(delete[] p[i]delete p[i])是无效的。 - CB Bailey
+1 对于数组的大小是在运行时选择的,因此将数组大小编码到新表达式的类型中并不总是可能(甚至不可取)。 - legends2k
嗯...我同意new[]可以分配由运行时状态决定大小的数组,但是现在,9年后,我们确实有编译器非常好地跟踪constexpr,并且在new int[6]new int[x]之间存在明显的编译时与运行时差异,其中x是intnew int[x]其中x是constexpr.. 在我看来,第一个可以轻松返回(int(*)[6])类型,而最后一个则为(int(*)[x])...我只希望这在某个时候被纳入标准中。 - quetzalcoatl

3

在线CDECL评估器是一个对于此类问题非常有帮助的资源:


cdecl

C gibberish ↔ English

int (*p)[4];

    declare p as pointer to array 4 of int

除了 int (*p)[4]; 不是 声明 p,而是 定义 它。(至少在本问题所涉及的 C++ 中是这样。正如 Johannes 曾经指出的那样,在某些领域,C 和 C++ 在什么是定义和什么是声明方面存在差异。) - sbi
@sbi:好的,但每个定义也是一个声明;“C声明符语法”是一个被广泛接受的术语。 - fredoverflow
在C和C++中,每个定义也是一个语句。尽管如此,人们很少混淆“定义”和“语句”,但却经常混淆“定义”和“声明”。 - sbi
@sbi:我非常确定定义int foo() { return 42; }不是一个语句 ;) - fredoverflow
@FredOverflow: <blush> 撤销上一条评论。那么它是什么?本地自动变量的定义不被认为是语句吗?无论如何,我的观点是:人们总是搞混声明和定义。(例如,超过一半的答案在https://dev59.com/V3M_5IYBdhLWcg3wXx1N上要么误导,要么完全错误,在评论中,人们不断提出愚蠢的反例(`int i;`不是定义),我不得不添加标准引用来解决关于类定义与类声明的讨论)。所以我想用精确的方式表达它。 - sbi
@sbi:是的,一个本地自动变量是一个“语句”:一个“声明语句”。一个“函数体”由一个复合语句组成,即 { statement-seq[OPT] }。局部自动变量声明(和定义)是一个“声明语句”,由一个“块声明”组成,其中包含一个“简单声明”。在函数体之外,一个“简单声明”可以出现在不是“语句”的上下文中。 - CB Bailey

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