【问题标题】:Pointer Arithmetic? What is the difference between these three expressions?指针算术?这三种表达方式有什么区别?
【发布时间】:2011-05-12 23:11:27
【问题描述】:

所以我试图理解两件事:

  1. 这三种表达方式有什么区别?
  2. 第一个表达式 (A) 的等价物是什么?

这里是代码(固定):

#include "stdafx.h"

void someFunc(double** pArray, int length)
{
    for(int i = 0; i < length; i++)
    {
        //this works perfectly
        double expressionA = *(*pArray + i);
        //this crashes : Unhandled exception at 0x00da13ff in pptrtest.exe: 0xC0000005: Access violation reading location 0xcccccccc.
        double expressionB = **(pArray + i);
        //this crashes : Unhandled exception at 0x00da13ff in pptrtest.exe: 0xC0000005: Access violation reading location 0xcccccccc.
        double expressionC = *pArray[i];
    }
}
int main()
{
    double arr[] = { 1, 2, 3, 4, 5 };

    double* pArr = arr;

    someFunc(&pArr, sizeof arr / sizeof arr[0]);

    return 0;
}

【问题讨论】:

  • 如果您添加代码以显示您如何为 ppDoubleArray 分配内存会更好。这将使回答您问题的人更好地了解您在做什么。
  • 您的意思是+ i,而不是+ 1
  • 如果您说出“这崩溃”是什么意思,这也会有所帮助。有什么东西会爆炸吗?是否有异常或错误消息?如果您不打算提供所有代码,至少提供一个特定错误描述。 “这崩溃了”在大多数情况下是没有意义的。

标签: c++ pointers pointer-arithmetic


【解决方案1】:

我认为问题是,[] 在 * 之前应用,所以在 expr C 中你正在做

*(ppDoubleArray[i])

实际上等价于 expr B,但 expr A 可以

(*ppDoubleArray)[i]

(假设表达式中的 1 应该是 i,否则无论如何都不同)。

【讨论】:

  • 求值顺序和运算符优先级是正交的。
  • 嗯?我使用了错误的终点站,还是有其他问题?我的意思是运算符优先级。
  • @Christian:是的,您确实是指运算符优先级。 :) 但是您在答案中写了“评估”。
  • 优先级较高的运算符首先被评估,不是吗?评价还有什么意思?
  • @Christian:序列点之间表达式的评估顺序未指定。我知道你在说什么,而且你基本上是正确的,但严格来说,“评估”在这里并不合适。
【解决方案2】:

你有一个指向双精度指针的指针。将其视为指向双精度数组的指针。无论哪种方式,以下是它们的含义:

  1. double expressionA = *(*ppDoubleArray + 1); 等同于:double expressionA = *((*ppDoubleArray) + 1);
  2. double expressionB = **(ppDoubleArray + 1); 与:double expressionB = *(*(ppDoubleArray + 1)); 相同,这意味着您要取消引用 ppDoubleArray[1],而我猜测它不存在。
  3. double expressionC = *ppDoubleArray[i]; 与:double expressionC = *(ppDoubleArray[i]); 相同——同样,您正在取消引用不存在的 ppDoubleArray[i]

就像其他人所说的那样,您需要注意优先顺序。基本上,首先取消引用然后索引您的数组。

【讨论】:

    【解决方案3】:
    double expressionB = **(ppDoubleArray + 1);
    

    让我们看看这个家伙的内存,在堆栈上你有一个指向双精度指针的指针。因此,如果它是 32 位处理器的内存地址,堆栈可能类似于:

    堆栈:|ppDoubleArray ptr |local vars、其他 args 或垃圾 |more locals/etc addr: |0 个来自堆栈的字节 |4 个来自堆栈的字节 |8bytes...

    所以当我们看表达式的第一部分时

      (ppDoubleArray + 1)
    

    这表示“指针越过ppDoubleArray”。通过转到内存中的下一个位置来转到下一个指针。 ppDoubleArray 之后的下一个记忆点是什么?查看上面的堆栈,它可能是一些局部变量或其他参数。所以现在你有谁知道什么(可能是长度的内容?其中一个双打?垃圾?)你将把它当作某个地方的有效地址。然后,您可以通过取消引用来遵循那个假定的指针:

       **(ppDoubleArray + 1)
    

    然后崩溃!

    因此,例如,如果长度为 5,则 ppDoubleArray+1 可能会抓取 5 并取消引用“5”以在该地址处查找内容。

    这段代码:

       double expressionC = *ppDoubleArray[i];
    

    工作方式相同,[] take precedence 在取消引用上。因此,您转到 ppDoubleArray 之后的第 i 个内存位置,并假设它指向您的数组。

    用父级重新排列操作顺序是可行的:

       (*ppDoubleArray)[i]
    

    【讨论】:

      【解决方案4】:

      假设 ppDoubleArray 是一个指向双精度数组的指针:

      第二个崩溃,因为您将一个添加到指向数组的指针中,而没有从中选择正确的索引。

      第三个由于运算符的优先级而崩溃。您正在选择不是数组的 ith 元素(除非 i 为 0),然后取消引用它。

      这里要记住的重要一点是如何处理指向数组的指针(或指向指针的指针)您取消引用一次以获取数组,此时您可以进行算术运算然后再次取消引用到达元素。

      【讨论】:

        【解决方案5】:

        aSCII 艺术时间:
        ---&gt; = 取消引用

        double expressionA = *(*ppDoubleArray + 1);

        ppDoubleArray  ---> .  
                            +1  
                            . ---> expressionA
        

        double expressionB = **(ppDoubleArray + 1);

        ppDoubleArray
             +1
              . ---> . ---> expressionB
        

        double expressionC = *ppDoubleArray[i];

        ppDoubleArray
             +i
              . ---> . ---> expressionC
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-01-12
          • 2012-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多