2010-07-06 85 views
2

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

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; 
} 

这可以工作,据我所知。它对我来说并不安全,但我更喜欢它将2D数组传递给函数。相反,一个指针可以为我完成这项工作。

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

此外,问题有点偏题。我为什么可以这样写:

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

但为什么我不能写

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

甚至用**帕尔?

回答

4

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

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

arr现在是3个3个数组的数组的数组。

int *pArr = *arr; 

*arr使用数组ARR中表达,所以它衰减到指针ARR的第一个元素 - 即指针的3个整数阵列(包含数组{1,2,0})。取消引用该指针(使用*)将为您提供3个整数的数组。现在你在表达式中使用表示数组,并且它衰减到指向int的指针,该int指向pArr。

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

pArr[0]给出了pArr指向的整数(数字1)。 &pArr[0]在该整数处产生指针(其实际上等于pArr)。使用[1]对指针进行索引给出对数字1之后的下一个整数的引用,该数字是数字2.将该引用指定为3.以下是catch:指向数组元素的指针只能用于访问同一阵列的其他元素。在数组{1,2,0}的元素,你已经改变了你的指针指向{1,3,0},这很好,但

func(&pArr); 

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

ptr[0][1] = 5; 

现在你已经采取了ptr[0],其计算结果为指向的对象,这是你原来的指针帕尔。此行相当于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说错误:从'int'无效转换为'int'*。 同样地,也可以不写此:

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

出于同样的原因:* ARR是3个整数{1,2,... 0},** ARR是整数1,以及整数不能被分配在阵列到一个指针。

6

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

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

ptr[0][1] = 5;在你的功能正在被译成*((*(ptr + 0)) + 1) = 5;,这显然不是你想要给什么arr不是指针数组。

编辑:在回应评论:

ptr[0][1] does overwrite the information in cell [0][1] of the array

是的,你真的很幸运在这里 - 这里的原因。当你将数组传递给你的函数时,你通过了(&pArr[0])[1],这是一个指向数组第一个元素的指针。当你做了*((*(ptr + 0)) + 1) = 5;,ptr+0变为空操作,离开*(*ptr + 1) = 5;,根据你的输入数据(它看作arr作为单维数组),它确实有明确的行为。如果你试图改变下标的第一个维度,那么它会炸毁。

+0

感谢您的信息,但我不完全理解你的意思。 ptr [0] [1]确实覆盖了数组的单元[0] [1]中的信息,那么这不是我想要的? 然后,如果数组仅仅是一个9个单元的块,那么我真的可以使用一个指向数组的元素0..7的指针,而不是这样做吗?所以我基本上过分复杂的整个事情? – IAE 2010-07-06 12:30:48

+0

@SoulBeaver:是的。 'arr'衰变成一个'int *',而不是'int **'。我在回答中回复了您评论的第一部分。 – 2010-07-06 12:42:14

+2

我已经低估了这个答案,因为答案和回答者关于衰变的评论都是错误的。 'arr'不是一个指向内存的指针,但它本身就是一个内存块(如果它是一个指针,它不需要衰减)。它衰变为'int(*)[3]',而不是'int *'。对于这个问题,我想说整个'(&pArr [0])[1]'和'pArr [1]'是一样的。我怀疑他想编写'(&pArr)[0] [1]'来模拟在函数中完成的访问。但是他的整个代码对我来说没有意义。我怀疑他很困惑。请更正答案,我会收回我的downvote,队友。 – 2010-07-06 13:05:09

-1

我发现C++中的多维数组总是有点混乱,并且往往会避免它们。有几种解决方案比较容易理解,例如Boost.MultiArray或Boost.UBlas库中的类,或矢量矢量,这取决于您的需求。