【问题标题】:Casting pointer to Array (int* to int[2])将指针转换为数组(int* 到 int[2])
【发布时间】:2013-11-18 11:16:31
【问题描述】:

如何将 int* 转换或转换为 int[x]?

首先,我知道指针可以被索引。所以我知道我可以遍历指针和数组并手动转换指针。 (例如,带有arr[i] = p[i] 的 for 循环)。我想知道是否可以用更少的代码行来实现相同的结果。

作为示例,我尝试将指针 int* c = new int[x] 转换为数组 int b[2]

int a    = 1;
int b[2] = { 2, 3 };
int* c   = new int[b[1]];

c[0] = b[0];
c[1] = b[1];
c[2] = a;

我想看看值在哪里,所以我做了一个简单的程序来输出地址和值。输出如下:

Address of {type: int}    &a    =       0031FEF4; a    = 1
Address of {type: int[2]} &b    =       0031FEE4; b    = 0031FEE4
Address of {type: int[2]} &b[0] =       0031FEE4; b[0] = 2
Address of {type: int[2]} &b[1] =       0031FEE8; b[1] = 3
Address of {type: int*}   &c    =       0031FED8; c    = 008428C8
Address of {type: int*}   &c[0] =       008428C8; c[0] = 2
Address of {type: int*}   &c[2] =       008428D0; c[2] = 1

一旦我确定我知道我在哪里尝试了一些东西。想到的第一个想法是获取指针分配的第二个元素的地址,然后用它替换数组的内存地址(参见下面的代码)。我所做的一切尝试最终都失败了,通常是语法错误。

这是我尝试过的。我真的希望它能够工作,因为这将是最简单的解决方案。

b = &c[1];

这显然不起作用。

编辑:解决方案: 别这样! 如果必要创建一个指向数组的指针,然后指向该数组;对于我能理解的任何目的,这都是毫无意义的。 有关更多详细信息,请参阅下面 rodrigo 的答案。

【问题讨论】:

  • 首先,你为什么需要它?提示:int*int [2] 有不同的用途(虽然第二个可以衰减到第一个)。
  • 我正在尝试简化文件读取功能。这是我正在努力解决的概念,以便进行所述简化。
  • 使用指向数组的指针永远不会变得更简单。只需使用简单的指针和大小。
  • @rodrigo 数组永远不会变得更简单。只需使用std::vector
  • @Caleth 确实!这正是我在下面回答中的结论;-)。

标签: c++ arrays pointers


【解决方案1】:

首先b是一个数组,不是指针,所以不能赋值。

此外,您不能将任何内容强制转换为数组类型。但是,您可以强制转换为指向数组的指针。 请注意,在 C 和 C++ 中,指向数组的指针相当少见。使用普通指针或指向指针并避免指向数组的指针几乎总是更好。

无论如何,你所要求的,或多或少都可以做到:

int (*c)[2] = (int(*)[2])new int[2];

但是typedef 会更容易:

typedef int ai[2];
ai *c = (ai*)new int[2];

为了安全起见,删除应该使用原始类型:

delete [](int*)c;

如果你只是为了好玩,那就太好了。对于现实生活,通常最好使用std::vector

【讨论】:

  • 那么这是获取内存地址并将其作为数组开头的唯一方法吗?通过改变我定义所述数组的方式;把它变成一个指向数组的指针,然后再转换成那个?
  • 实际上 C 的方式是按原样使用指针:记住你可以为指针下标就好了。转换为指向数组的指针大多是无用的,除非在多维数组中。我的意思是,您可以将 int* 视为指向单个整数,或指向整数数组中的第一个。
  • C++ 中这种未定义的行为。 int*int(*)[2] 是两种不同的指针类型。您实际上是在从一种类型到另一种类型执行非法 reinterpret_case 并违反 严格别名规则
  • @ThomasMcLeod 没时间在标准中查找它,但我相信聚合类型及其第一个元素的类型并非不相关,并且指向每个元素的指针都可以之间进行转换。
  • @ThomasMcLeod 实际上将int * 转换为int(*)[] 确实是一个别名违规(你原来的评论是正确的),因为从来没有一个数组对象——这看起来很有趣,因为我们通常分配数组“替代品”——但如果地址确实是数组的位置,则反向转换是可以的。我想到了后者。
【解决方案2】:

首先,将指针转换为 C 样式数组,这通常是一种非常糟糕的做法。

但您可以将临时数组(“右值数组”)衰减为地址/指针。 就这样写吧

#include <stdio.h>

int main()
{
    int *array  = (int[2]){1, 2};
    printf("%d", array[0]); /* array[0] contains 1 now */

    return 0;
} 

虽然我再次强调:当你这样做时,你应该有充分的理由使用这种技巧。

P.S. 上面列出的代码仅适用于 C99/C11,不适用于现代 C++ 编译器。

【讨论】:

  • 您没有将指针投射到答案中提到的 C 样式数组。您正在将临时数组衰减为地址/指针。像这样的临时数组不应该首先有地址,这一定是旧编译器的疏忽。
  • @JoshC,谢谢。我根据您的评论进行了更正。
  • @JoshC,复合文字是 l-values,它们的生命周期限制了定义它们的块(而不是表达式)。获取他们的地址是绝对安全的。
  • 很高兴知道。我检查了一下,它确实可以编译,但只有 clang(使用 c++17)gcc 仍然会产生编译错误。因此,在每个环境中编译代码的常规意义上,它绝对不是“安全”的。
  • @JoshC,编译失败,因为复合文字不是 C++ 标准的一部分。以迂腐模式编译会产生警告ISO C++ forbids compound-literals
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-02
  • 2014-05-02
  • 2017-02-12
  • 2017-07-25
  • 1970-01-01
  • 2013-11-18
相关资源
最近更新 更多