【问题标题】:Question about pointer in C?关于C中指针的问题?
【发布时间】:2009-06-15 08:53:47
【问题描述】:
int a[A][B];
int* p = a[i];  //i<A-1

那么下面这句话的实际操作是什么?

p++;
p+=B;

【问题讨论】:

  • 为什么要问为什么?这是一个非常基本但很棘手的概念,值得在 stackoverflow 上提问。
  • 我想到如果代码只是一个例子来了解指针是如何工作的,那没关系,但如果它试图用矩阵做实际工作,它应该更好地将它封装在函数中像 GetElement() 一样,它进行边界检查并将高度容易出错的指针算法抽象掉。

标签: c pointers


【解决方案1】:

p++ -> 转到矩阵中的下一列

p+=B -> 转到矩阵中的下一行(同一列)。

【讨论】:

    【解决方案2】:

    对于多维数组,必须记住维度是从左到右应用的,这样更容易可视化。例如:

    int p[A][B][C];
    

    这将被构建为:

    [][]--[][][][]--[][]_ _ _[][]--[][]   [][]--[][][][]--[][]_ _ _[][]--[][]
    |---A----||---A----|     |---A----|---|---A----||---A----|     |---A----|
    |---------------A*B---------------|   |---------------A*B---------------|
    |---------------------------------A*B*C---------------------------------|
    

    所以如果你有一个 p[i][j][k],它实际上是 (p+i+Bj+BCk)

    【讨论】:

    • 是的,但是您的插图中的 A 和 C 颠倒了。此外,p+i+Bj+BCk 应该是 p+BCi+Cj+k。此外,需要注意的是,将 v 添加到 p 现在会得到 (p+v)+BCi+Cj+k,这允许您将 v“分布”在 i、j 和 k 上(请记住 i
    • 真的吗?我一直认为 [] 运算符是左->右处理的。显示我所知道的:P
    【解决方案3】:
    p = a[A-1]
    

    相同
    p = &a[A-1][0]
    

    所以

    p++
    

    结果

    p == &a[A-1][1]
    

    然后做

    p+=B
    

    会导致

    p == &a[A-1][1+B] == &a[A][1] // outside allocated memory
    

    【讨论】:

      【解决方案4】:

      只是为了进一步讨论(虽然我实际上无法在没有足够代表的情况下直接回复 cbailey 的帖子......)

      在栈和堆上声明多维数组有很大的区别。

      正如 abelenky 所说,在堆栈上声明一个多维数组总是会导致连续的内存。我相信 C 标准实际上在某处声明了这一点,但即使没有,地球上的每个编译器都会确保它是连续的。 这意味着在一天结束时,您还不如使用一维数组,因为无论如何编译器都会转换为该数组。

      就使用多维数组时的安全性而言,无论它们是分配在堆上还是堆栈上,您都不想像原始海报那样迭代它们。

      【讨论】:

      • w.r.t. 没有区别。堆栈或堆。区别(关于连续分配)在于 T[][] 与 T**。这与堆栈与堆不同,因为我的 T** 可以在堆栈上并指向堆栈(指向也指向堆栈的指针),并且我可以轻松地在堆上分配 T[][]。事实上,C 对堆栈和堆一无所知。顺便说一句,根据标准,多维数组确实是完全连续的(请参阅我对 cbailey 帖子的最后评论)。
      【解决方案5】:

      初始化后,a 存储了 AB 个整数,p 指向第 Bi 个整数(从 0 开始)。 后面的操作使它指向第 B*(i+1)+1 个。

      【讨论】:

      • 其中一个 i 应该是 1。
      【解决方案6】:

      这是一个元答案,主要针对 Justicle 和原始海报。

      数组退化为指针,但它们不是一回事。仅仅因为如果 a 是指向 int 的指针与指向数组的数组的数组,则获取 a[3][7][1] 的语法是相同的-int 不代表实际操作是一样的。

      您可以创建一个 any 类型的数组(大小明确)。数组解引用语法和指针语法是一样的,所以

      a[i] == *(a+i) == i[a]
      

      不管 a 是什么数组类型。

      本帖所有问题的答案都可以由此推导出来。

      int a[3][2][17];      //a is an array of length 17.
      int (*b)[3][2] = a[5]; //b is a pointer to the fifth element of a
      int (*c)[3] = b[1];    //c points to the first element of b.
      b += 1; // b now points to the sixth element of a. (c is unchanged)
      c += sizeof(*b); // c points to the first element of b again.
      

      请注意,如果 a 不连续,这些都不起作用。如果它不起作用,那么数组数组的工作方式将不同于其他任何数组。

      【讨论】:

        【解决方案7】:

        如果您以内存形式绘制 a[A][B] 矩阵,也就是一个向量,并以 p 指向 a[i] 的开头,然后应用这些操作,那么答案非常简单。

        【讨论】:

          【解决方案8】:

          要回答这个问题,您首先需要了解多维数组在 C 中是如何存储在内存中的。

          int a[A][B];
          

          如果不考虑如何优化它在内存中的位置,第一个索引 (A) 实际上将是一个指向第二个索引 (B) 的指针数组。 虽然内存可能是连续的,但无法保证

          因此:

          int a[A][B];
          int **b;
          

          上面ab的区别在于,a的内存是在进入作用域时分配的。

          考虑到这一点,回答您的问题:

          int* p = a[i]; // p = a[i][0]
          p++; // p = a[i][1]
          p+=B; // p = a[i][1+B]
          

          使用现代编译器,很可能已经分配了一个连续的内存块,相当于:

          p = a[i+1][1];
          

          但是不能保证内存是连续的,所以一个可能的情况是你现在有一个无效的指针。

          【讨论】:

          • 错误。 a[A][B] 是连续内存。使用调试器、内存查看器或一些简单的 printf 语句很容易验证这一点。
          • 是的,它通常是连续的,因为它是一个简单的优化,但不能保证。因此,假设您可以索引一个指针并让它正确索引到下一个指针是非常危险的。最好分配您自己的单个连续内存块并相应地对其进行索引。
          • 有趣的点——标准是否保证多维数组的连续分配?谁有链接?
          • 我试图找到它,因为我也觉得它是连续的。但是,我在 C 和 C++ 的标准中都找不到这样的保证。
          • 您不仅将 A 和 B 翻转,它们是 NOT 指针。如果您声明 int a[A][B] 则不涉及指针。它是 B 个 A-int 数组的数组。没有比 int b[A] 更多的指针。
          猜你喜欢
          • 2014-05-13
          • 2023-01-08
          • 2011-02-01
          • 2021-10-29
          • 1970-01-01
          • 2022-01-05
          • 2017-08-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多