【问题标题】:C++: Is the same passing an array than a pointer to array? [duplicate]C++:传递一个数组和一个指向数组的指针一样吗? [复制]
【发布时间】:2013-07-27 05:29:39
【问题描述】:

起初我猜 k1 的值不会在主空间中。但是后来我意识到一个数组是一个指针,那么有什么区别吗?我认为这是相同的,但也许任何人都可以找到其他一些技术差异。也许更快地传递指针?

#include <iostream>

using namespace std;

void g(double [],int );
void f(double* [],int );

int main()
{

    int n = 10;
    double *k1, *k2;

    k1 = new double[n];
    k2 = new double[n];

    g(k1,n);
    f(&k2,n);

    for(int i = 0;i <n;i++)
    {
        cout << k1[i]<< " ";
        cout << k2[i] << endl;
    }

    delete [] k1;
    delete [] k2;

    return 0;
}


void g(double h[],int n)
{
     for(int i = 0;i <n;i++)
        h[i]=i;
}

void f(double* h[],int n)
{
     for(int i = 0;i <n;i++)
        (*h)[i]=i;
}

【问题讨论】:

  • 数组不同于指针,但声明为数组的函数参数实际上是指针。
  • @Nikos:他传递的地址是double*,而不是double*
  • 实际上它既不需要指向 double 的指针,也不需要指向指向 double 的指针。它需要一个指向不同数组的指针。
  • @BenVoigt 哎呀,确实。
  • @DaleWilson 函数参数中的[] 符号只是指针的语法糖。它不是一个数组。这两个参数都是指向int 的指针:int* aint a[]

标签: c++ pointers


【解决方案1】:

首先,数组不是指针。这是一个包含 10 个双精度数的数组:

double a[10];

这是一个指向双精度的指针:

double *p;

这是一个指向 10 个双精度数组的指针:

double (*pa)[10];

这是一个指向双精度的指针数组:

double *pa[10];

数组和指针只有在声明为函数参数时才相同。但是数组可以转换(衰减)为指向数组第一个元素的指针:

double a[10];
double *p = a;
double *q = &a[0]; //same as p

在您的示例代码中:

double *x = new double[10];

您正在创建一个包含 10 个双精度数的动态数组,并获取指向该数组第一个元素的指针。您还可以创建一个新数组并获得一个指向数组的指针:

double (*x)[10] = new double (*)[10];

但是这种奇怪的语法很少有用。

关于函数,这是一个采用双精度数组的函数:

void g1(double h[], int n);

这是一个函数,它带有一个指向 10 个双精度数组的指针:

void g2(double (*h)[10]);

在指向数组的情况下,您需要指定数组的大小,因为您无法创建指向未知大小数组的指针。

这就是为什么数组实际上是作为指针传递给函数的。但是指向数组的第一个成员的指针,而不是指向数组本身的指针。所以第一个函数实际上和这个函数是一样的:

void g1(double *h, int n);

由于您只将指针传递给数组的第一个成员(指向 double 的指针),因此您还需要在附加参数中指定数组的大小。优点是您可以传递任意大小的数组。甚至是数组的拼接:

double x[20];
g1(x + 10, 5); //pass x[10..15]

关于哪个更快,它们都是一样的,它们实际上是指向同一个内存地址的指针。请注意,数组仅在它们是结构的一部分时才通过副本传递,并且结构是按值传递的。

我的建议是:如果您使用 C 坚持惯用的 C,则在必要时使用指向数组第一个成员的指针,并尽可能避免使用指向数组的语法。如果您使用 C++,请使用容器、迭代器和范围。

【讨论】:

    【解决方案2】:
    void f(double* h[],int n)
    

    不接受指向数组的指针。你已经声明它接受一个指针数组。

    它起作用的唯一原因是声明为数组的函数参数被默默地转换为指针,因此它相当于:

    void f(double** h,int n)
    

    这毕竟是你想要的。

    这个(被 g++ 拒绝)代码将使用指向数组的指针:

    void f(double (*h)[],int n)
    

    【讨论】:

    • 该声明没有任何违法之处。
    • @Carl:不是吗? g++ 给出“错误:参数‘h’包括指向未知绑定‘double []’数组的指针”
    • 嗯 - 铿锵声默默地接受了它。编译器扩展?让我试试 GCC。
    • GCC 像你说的那样向我抱怨;我想知道为什么铿锵会拿那个...
    • @Carl:应该允许这样做是有道理的,因为您可以形成指向不完整类型的指针。你不能用它做指针运算(包括下标),但这是一个完全不同的问题。
    【解决方案3】:

    有了这个声明:

    void f(double* [],int );
    

    您是说,作为第一个参数,您正在获取指向double 的指针数组。

    当您使用(*h) 取消引用该参数(被视为指向指针的指针)时,您实际上获得了数组第一个位置的地址。

    【讨论】:

      【解决方案4】:

      即使你按值传递指针,它指向的内存仍然可以被函数更改。

      【讨论】:

        【解决方案5】:
        void g(double h[],int n);
        

        从技术上讲,您在该函数中传递了一个指针。

        void f(double* h[],int n);
        

        然而,在这一个中,你传递了一个指向数组的指针,它解析为一个指向指针的指针,因为它是一个函数参数*。

        *感谢本·沃伊特

        【讨论】:

        • 不,这是一个指针数组。有点。它原来是一个指向双精度指针的指针,因为这是传递数组的方式,所以事情工作但非常偶然。
        • 冒着被激怒的风险,大多数时候,数组“本质上”是一个指针。无论如何,对于典型用户。
        • 二进制值与指向 double 的指针的指针相同,但编译器生成的使用该值的代码会有所不同(并且非常错误,除非您真的知道为什么想要一个指向数组的指针。
        • @Joseph:不,不是。数组对象隐式转换为指针,但数组不是指针。在sizeof 或模板类型推断等情况下,将不会使用该转换。 (并添加混淆,函数参数声明中的数组语法实际上给你一个指针,而不是一个数组)。
        • @Joseph:对于函数参数是的,因为函数参数不能是数组(请参阅 Nikos 对问题的“语法糖”评论)。对于实际的数组对象,就指针算术和下标工作而言,它们就像指针。但它们与上下文中的指针不同,后者会进行类型推断(decltypesizeof 和模板)。
        【解决方案6】:

        许多程序员都有一个关于编译器如何工作的心智模型,其中包括“数组只是一个指针”。这个模型不正确。

         typedef int[10] Array;
         typedef Array * PointerToArray;
         typedef int * Pointer;
        
         Array a = {0,1,2,3,4,5,6,7,8,9};
         PointerToArray pa;
         Pointer pint = a;   // the compiler casts this automatically to a different type.
        

        此时 pint 和 pa 具有相同的二进制值,但 pa[1] 和 a[1] 不引用内存中的相同位置。了解原因很重要。

        【讨论】:

        • pa 没有任何值,它未初始化...
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-28
        • 2022-01-12
        • 2016-04-04
        • 2017-08-23
        相关资源
        最近更新 更多