【问题标题】:Initialize pointer to pointer using multiple address operators in C or C++在 C 或 C++ 中使用多个地址运算符初始化指向指针的指针
【发布时间】:2010-09-28 07:45:07
【问题描述】:

我突然想到,我不知道如何用 C++ 中的一条语句从非指针值初始化指向指针的指针:

int a = 1;
int** ppa = &&a; //Does not compile
int** ppa = &(&a); //Does not compile
int* pa = &a;   //Works but is a
int** ppa = &pa; //Two step solution

我是否遗漏了什么,这两个语句是唯一的方法吗?

【问题讨论】:

  • 在这种情况下,为什么你认为你需要一个指向指针的指针?
  • @Jens Gustedt,这不是重复的。链接的问题一般询问指针。这个问题是关于具体案例的。
  • @TokenMacGuy:在什么情况下?他只是给出了一个最简单的例子来说明这个问题;没有用例
  • @Patric:这就是我的观点。发帖人没有解释他试图初始化的指针的指针应该是什么意思。 &&a 的表达当然毫无意义。

标签: c++ c


【解决方案1】:

如果你想要一个指向指针的指针,你想要指向的指针必须位于内存中的某个位置,所以我认为不可能有“一步解决方案”,因为你需要一个可以指向的指针变量.

(注意:这句话并不是要在一个句子中尽可能多地使用“点”的语言试验:-))

【讨论】:

    【解决方案2】:

    您无法获得指向临时对象的指针。 &a 产生一个 r 值。允许没有实际地址。

    【讨论】:

    • 这是 100% 正确的,但我接受了 Philip 的回答,因为它涉及为什么会这样的理由,而不是仅仅指出标准。
    【解决方案3】:

    其他许多是正确的:指向指针的指针必须指向某个东西。但是,在 C99 中,您可以使用 compound literals 作弊:

    int a = 1;
    int **ppa = &(int *){ &a };
    

    复合文字基本上只是未命名的对象,并且具有与普通对象相同的存储规则。 (但是您不能使用 static 关键字给函数范围复合文字静态存储持续时间)。你甚至可以嵌套它们,这样你就可以将前面的示例重写为一行:

    int **ppa =  &(int *) { &(int) { 1 } };
    

    【讨论】:

    • 这很可能是未定义的行为,并且可能在第一次使用指针时使应用程序崩溃。复合文字是临时的,编译器可以重用该空间,因此*ppa 在第二行执行期间指向&a,但之后可能指向其他任何内容。
    • @David Rodriguez:不,你错了。复合文字将具有与 a 和 ppa 相同的存储持续时间:在函数外部时为静态,否则在关闭块的持续时间内自动。见 C99 6.5.2.5 (6)。
    • 你完全正确。我应该在发表评论之前检查标准......如果您在任何时候修改答案,评论并且我会将-1变成+1,它现在不允许我更改它。无论如何,取决于你想用指针做什么,它与中间变量解决方案一样危险。
    • @David Rodriguez:没问题。事实上,指针总是很危险的。复合文字的规则并不广为人知,这是避免这些结构的原因。
    • 复合文字的规则只有在人们使用它们时才会广为人知。
    【解决方案4】:

    C++03 [Section 5.3.1] 说

    一元 & 运算符的结果是指向其操作数的指针。操作数应为 左值 或限定 ID。在第一种情况下,如果表达式的类型是“T”,则结果的类型是“指向 T 的指针”。

    在&&a 中,& 运算符不能应用于&a 的结果,因为结果不是lvalue。

    另请阅读this 线程

    【讨论】:

      【解决方案5】:

      您想要一个指向指针(称为P)的指针(称为PP)吗?

      那么P 必须实际存在。这意味着你必须声明它。

      当然编译器会在&&a 处失败——因为你不能获取地址的地址。您可以获取指针的地址 - 但您必须先声明指针。

      因此:

      int a = 1;
      int *P = &a;
      int **PP = &P;
      

      【讨论】:

      • 解析器在&&a 处失败不是因为您不能获取地址的地址,而是因为&& 是一个单一的标记,在声明中此时无效。 int **ppa = x &&a; 可能是适当类型的 x 和适当重载的 &&(邪恶!)的有效初始化,但它不会是地址的地址。
      【解决方案6】:

      地址是一个数字。如果它保存在变量中,即指针,它只有自己的地址。所以

      int *i1 = &a;
      

      有道理,但是

      int **i2 = &&a;
      

      没有意义。不过

      int **i2 = &i1;
      

      确实有道理。有意义吗?

      【讨论】:

      • 您的术语有误。地址操作符 does 产生一个指针,参见 [ISO03, 5.3.1 expr.unary.op §2]。将指针值称为“地址”,将指针变量称为“指针”是很常见的,但严格来说,这是错误的。
      • 我使用的术语是常用的。标准意义上的指针值是任何意义上的地址,而地址又是任何意义上的数字。换句话说,& 不会产生一个变量, 所以它不会产生任何可以获取地址的东西。
      【解决方案7】:

      当您执行以下操作时:

      char a;
      char* b = &a;
      char** c = &b;
      

      首先 a 现在存在于堆栈中。它显然有一个内存地址(即它的堆栈位置),这是你分配给 b 的。 b 现在也存在于堆栈中,然后您可以将其内存地址传递给 c。但是,您不能在没有中间堆栈的情况下获取值的地址,因为如果不先显式创建它,它就不存在。

      【讨论】:

        【解决方案8】:

        当您执行&&a; 之类的操作时,问题在于您要求的是“a 地址的地址”。

        这没有意义。我们可以得到a 的地址就好了,但这并没有给我们一个可以获取地址的变量。它只是给了我们一个指针值。在该值存储在某处之前,我们无法获取其地址。

        如果您有2+2 之类的代码,则结果也没有地址。它只是值 4,但它还没有存储在任何地方,所以我们无法获取地址。一旦我们将它存储到 int 变量中,我们就可以获取该变量的地址。

        基本上,问题在于值和变量之间的差异。值只是一个数字(或一个字符,或一些其他数据)。变量是内存中存储值的地方。变量有地址,但值没有。

        在 C++ 中,它是右值和左值之间的区别。右值本质上是一个临时值,它通常是从另一个操作返回的值(例如您的情况下的 & 运算符),但尚未存储在任何地方。

        一旦你将它存储到一个变量中,你就会得到一个左值,而左值有一个你可以取的地址。

        所以是的,您需要两个单独的语句。首先,您获取地址,然后将该地址存储在某个地方。然后你就可以拿到这个“某处”的地址了。

        【讨论】:

        • 您的术语有误。地址操作符 does 产生一个指针,参见 [ISO03, 5.3.1 expr.unary.op §2]。将指针值称为“地址”,将指针变量称为“指针”是很常见的,但严格来说,这是错误的。
        • @Fred:很公平。我怀疑我会因此惹上麻烦。 ;) 那会教我尝试改写 C++ 语义:p
        • 修复了一点。希望我得到了最具误导性的部分。
        【解决方案9】:

        这可能有效:

        int** ppa = &(int*){&a};

        【讨论】:

        • 嗯不,它不会,它会创建一个临时的
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-10
        • 1970-01-01
        • 2011-05-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多