【问题标题】:On Passing a 2D-Array into a function关于将二维数组传递给函数
【发布时间】:2011-03-12 07:03:05
【问题描述】:

这不是一个问题,“我如何将它传递给函数?”而是“这可以接受吗?”

void func( int **ptr );

int main( int argc, char* argv[] )
{
    int arr[][3] = {{1, 2,}, {3, 4}, {5, 6}};
    int *pArr = *arr;

    (&pArr[0])[1] = 3;

    func(&pArr);

    cin.get();
    return 0;
}

void func( int **ptr )
{
    cout << "In func()" << endl;
    ptr[0][1] = 5;
}

据我所知,这很有效。这对我来说并不安全,但我更喜欢它而不是将二维数组传递给函数。相反,一个为我工作的指针。

这对于必须阅读我的代码的人来说会不会很困惑?我应该改用其他方法吗?使用指向数组的指针是不是一个坏主意?

另外,问题有点离题。为什么我可以写:

int arr[] = { 1, 2, 3, 4, 5 };
int *pArr = *arr;

为什么我不能写

int arr[][3] = {{1, 2,}, {3, 4}, {5, 6}};
int *pArr = **arr;

甚至使用 **pArr?

【问题讨论】:

    标签: c++ pointers multidimensional-array


    【解决方案1】:

    您在这里感到困惑。 int arr[][3] = {{1, 2,}, {3, 4}, {5, 6}}; 不是指向长度为 3 的数组的指针。它是一个长度为 9 ints 的单个固态内存块,它衰减为单个 int*。编译器会为您执行 3*first+second 映射到这块内存。

    函数中的下标无效的原因是因为函数无法确定数组的维度。使用一维数组,您不需要此信息——您只需将索引添加到给定的基指针。但是,对于二维数组,您需要维度来计算最终索引。

    您函数中的ptr[0][1] = 5; 被转换为*((*(ptr + 0)) + 1) = 5;,这显然不是您想要的,因为arr 不是指针数组。

    编辑:回应评论:

    ptr[0][1] 确实会覆盖数组的单元格 [0][1] 中的信息

    是的,你在这里很幸运——这就是原因。当你将数组传递给你的函数时,你传递了(&amp;pArr[0])[1],它是一个指向数组第一个元素的指针。当您执行*((*(ptr + 0)) + 1) = 5; 时,ptr+0 变为无操作,留下*(*ptr + 1) = 5;,根据您的输入数据,它确实具有明确定义的行为(它将arr 视为一维数组)。但是,如果您尝试更改下标的第一个维度,它会爆炸。

    【讨论】:

    • 感谢您提供的信息,但我不太明白您的意思。 ptr[0][1] 确实覆盖了数组的单元格 [0][1] 中的信息,那么这不是我想要的吗?然后,如果数组只是一个由 9 个单元组成的块,那么我真的可以使用一个简单地指向数组元素 0..7 的指针而不是这样做吗?所以我基本上把整个事情复杂化了?
    • @SoulBeaver:是的。 arr 衰减为 int *,而不是 int **。我已在回答中回复了您评论的第一部分。
    • 我对这个答案投了反对票,因为答案和回答者关于衰变的评论都是错误的。 arr 不是指向内存的指针,但它本身就是一个内存块(如果它是一个指针,它就不需要衰减)。它衰减到int(*)[3],而不是int*。对于这个问题,我想说整个(&amp;pArr[0])[1]pArr[1] 是一样的。我怀疑他想写(&amp;pArr)[0][1] 来模拟函数中完成的访问。但是他的整个代码对我来说没有意义。我怀疑他很困惑。请更正答案,我会收回我的反对票,伙计。
    【解决方案2】:

    让我们仔细分析一下,因为数组到指针的转换有时会令人困惑。

    int arr[][3] = {{1, 2,}, {3, 4}, {5, 6}};
    

    arr 现在是一个由 3 个 3 个整数组成的数组。

    int *pArr = *arr;
    

    *arr 在表达式中使用数组 arr,因此它衰减为指向 arr 的第一个元素的指针——即指向 3 个整数数组的指针(包含 {1,2,0} 的数组)。取消引用该指针(使用*)为您提供3 个整数的数组。现在您在表达式中使用 that 数组,它衰减为指向 int 的指针,该指针分配给 pArr。

    (&pArr[0])[1] = 3;
    

    pArr[0] 给出 pArr 指向的整数(数字 1)。 &amp;pArr[0] 在该整数处创建一个指针(实际上等于 pArr)。用 [1] 对该指针进行索引给出了对数字 1 之后的下一个整数的引用,即数字 2。对于该引用,您分配了 3。这是问题所在:指向数组元素的指针只能用于访问同一数组的其他元素。您的指针指向数组 {1, 2, 0} 的一个元素,您已将其更改为 {1, 3, 0},这很好,但是

    func(&pArr);
    

    现在你正在创建一个指向 int 的指针(因为 pArr 是一个指向 int 的指针),并将它传递给你的函数。

    ptr[0][1] = 5;
    

    现在您已经使用了ptr[0],它计算出指向的对象,即您的原始指针 pArr。此行等效于pArr[1] = 5;,并且仍然有效(将您的 {1,2,0} 数组更改为 {1,5,0})。但是,ptr[1][... 将是无效的,因为 ptr 没有指向任何类型的数组的元素。它指向一个独立的指针。递增 ptr 将使其指向未初始化的内存和取消引用,这将是未定义的行为。

    对于其他问题:

    你不应该这样写:

     int arr[] = { 1, 2, 3, 4, 5 };
     int *pArr = *arr;
    

    数组arr 衰减为指向int 的指针(指向数字1),解引用给出整数,并且整数不能分配给指针pArr。 gcc 说 error: 从 'int' 到 'int' 的无效转换*。 同样,你不能这样写:

    int arr[][3] = {{1, 2,}, {3, 4}, {5, 6}};
    int *pArr = **arr;
    

    同理:*arr 是 3 个整数 {1, 2, 0} 的数组,**arr 是整数 1,整数不能赋值给指针。

    【讨论】:

      【解决方案3】:

      我发现 C++ 中的多维数组总是有点令人困惑,并且倾向于避免使用它们。有几种更容易理解的解决方案,例如 Boost.MultiArray 或 Boost.UBlas 库中的类,或向量的向量,具体取决于您的需要。

      【讨论】:

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