【问题标题】:What is the advantage of a pointer to the base address of an array instead of pointer to the first element? [closed]指向数组基地址的指针而不是指向第一个元素的指针有什么好处? [关闭]
【发布时间】:2020-06-09 09:33:14
【问题描述】:

下面的代码 sn-p 显示了一个指向数组基址的指针和一个指向元素的指针;

第一种情况:

/* Pointer to an array of 10 integers */
int arr[10]
int (*ptr)[10];
ptr = & arr; //points to the base address of an array of 10 integers
for (i = 0; i < 10; i++) //prints the values
    printf("%d\n", *(*ptr + i)); 

第二种情况:

/* Pointer to an array element*/
int arr[10];
int *ptr;
ptr = arr;  //Points to the first element of an array
for (i = 0; i < 10; i++) //prints the values
{
    printf("%d\n", *ptr);
    ptr ++;
}

我了解两种情况下访问值的区别。但是我不明白使用第一种情况有什么好处,即指向 10 个整数数组的指针,即使第二种情况看起来很简单。

【问题讨论】:

  • 没有优势。它们是相同的。您断言的差异不存在。
  • @pmg 在这种情况下,它是指指约翰史密斯或约翰史密斯的房子的人。如果你知道在哪里可以找到他,你就知道在哪里可以找到他。如果你已经知道他住在哪里,你根本不需要指点,只要走到他的门前敲门,不用问路:)
  • 在这种情况下没有区别,但是当您尝试将数组传递给函数和retain sizeof information时可能会看到一个。
  • 做一个或另一个没有优势。一切都取决于你要做什么。
  • 这个最近的问题可能会澄清一些事情:stackoverflow.com/questions/62209942/…。甚至可能被骗。

标签: c++ c arrays pointers


【解决方案1】:

在您的特定示例中

int arr[10]
int (*ptr)[10];
ptr = & arr; //points to the base address of an array of 10 integers
for (i = 0; i < 10; i++) //prints the values
    printf("%d\n", *(*ptr + i));  //NOTE: same as `ptr[0][i]`

没有优势,或者至少没有优势被利用。

*(*ptr+i)int (*ptr)[10]; 将/应该生成与 *(ptr+i) 将与 int ptr[10]; 一起使用(注意:一些/许多人可能会发现 ptr[0][i]ptr[i] 分别是这些表达式的更易读的渲染)

例子:

int get_nth(int (*X)[10], int N) { return *(*X+N); }
int get_nth_(int *X, int N) { return *(X+N); }

x86_64 输出(gcc -O3 或 clang -O3):

get_nth:                                # @get_nth
        movsxd  rax, esi
        lea     rax, [rdi + 4*rax]
        ret
get_nth_:                               # @get_nth_
        movsxd  rax, esi
        lea     rax, [rdi + 4*rax]
        ret

https://gcc.godbolt.org/z/up7HXc

如果int (*ptr)[10] 派生自多维数组 如

int multidim[5][10]; //array 10 or array 5 of int
int (*ptr)[10]=&multidim[1];

您可以使用第一个索引以10*sizeof(int) 的增量跳转指针,此外还可以使用第二个索引以sizeof(int) 的增量跳转(与普通的int* 一样)。

在一个独立的示例中(即,10-int 块不是多维数组的一部分),int(*)[10] 的唯一“优势”可能是它保留了sizeof 信息(即使跨函数调用边界),并且您可以想象将其用于显式边界检查。

边界检查示例:

#include <stdio.h>

#define CHECKED_SUBSCRIPT(PtrArray, Index) (*(PtrArray))[BOUNDCHECK(Index,ARRCNT(*(PtrArray)))] /*{{{*/
    #include <assert.h>
    static inline size_t BOUNDCHECK(size_t Index, size_t Bound)
    {
        assert(Index <  Bound);
        return Index;
    }
        //sizeof(A) or void (=>error) if A isn't an array
        #define ARRSZ(A) (+ sizeof(A) + 0* /*{{{*/\
                     _Generic((__typeof(&(A)[0])*)0, __typeof(__typeof(A)*):(void)0,default:0) ) /*}}}*/
    #define ARRCNT(A) (ARRSZ(A)/sizeof((A)[0])) /*}}}*/
int main()
{
    int arr[10]={0,2,4,6,8,10,12,14,16,18};
    int (*ptr)[10] = &arr;
    for (int i = 0; i < 20; i++){
        printf("%d\n", CHECKED_SUBSCRIPT(ptr,i));
    }
}

输出:

0
2
4
6
8
10
12
14
16
18
a.out: boundschecking.c:7: BOUNDCHECK: Assertion `Index < Bound' failed.

【讨论】:

    【解决方案2】:

    没有优势。访问数组arr元素的指针类型不同。

    在第一种情况下,ptr 的类型为 int (*)[10] - 指向 10 个数组的指针 int

    在第二种情况下,ptr 的类型为 int * - 指向 int 的指针。


    ptr = arr; - arr 衰减为指向arr 的第一个元素的指针(类型为int*)。

    ptr = &amp;arr; - &amp;arr 是指向 int(类型为 int (*)[10])的 10 个元素的数组的指针。


    旁注:

    如果您在第一个示例中递增ptr,则指针将指向数组arr 之后的内存位置。至少在 C 中取消引用该指针会调用未定义的行为:

    当一个整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果和原始数组元素的下标之差等于整数表达式。换句话说,如果表达式P 指向数组对象的第i 元素,则表达式(P) + N(等效于N + (P))和(P) - N(其中N 的值是@987654345 @) 分别指向数组对象的i + n-th 和i − n-th 元素,前提是它们存在。

    此外,如果表达式P 指向数组对象的最后一个元素,则表达式(P) + 1 指向数组对象的最后一个元素,如果表达式Q 指向数组对象的最后一个元素对于数组对象,表达式(Q) - 1 指向数组对象的最后一个元素。如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则计算不应产生溢出;否则,行为未定义。 如果结果指向数组对象的最后一个元素,则不应将其用作被评估的一元 * 运算符的操作数

    来源:C18,6.5.6/8

    对于 C++:Dereferencing one past the end pointer to array type

    在第二个示例中递增ptr 时,只需让ptr 指向数组arr 的以下char 元素。

    【讨论】:

    • 拒绝投票是一回事,但删除投票是有人滥用他们的特权。这确实回答了这个问题。
    • 两者都是指向int 的指针。期间。
    • @MarquisofLorne 不,他们不是。
    • @MarquisofLorne 不不不。一个是指向数组类型的指针,另一个是指向int 的指针。
    • @RobertSsupportsMonicaCellio 也许你也应该说当我们尝试将指针递增1时会发生什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-28
    • 2016-08-11
    • 2017-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多