从访问2d数组传递给函数的分段错误

时间:2014-09-25 06:06:37

标签: c++ arrays pointers

我正在使用Code:Block。

编译以下代码(无错误)并在运行时出现分段错误。

void print(int size, int **a)
{
    for(int i=0;i<size;i++)
    {
        for(int j=0;j<size;j++)
        {
            cout<<a[i][j]<<" ";/**Segmentation fault here**/
        }
        cout<<endl;
    }
}

int main()
{
    int a[4][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
    int size = sizeof(a)/sizeof(a[0]);
    print(size,(int **)a);
    return 0;
} 

我尝试使用不同的传递数组的方法:

void print(int size, int a[][4])
{
    for(int i=0;i<size;i++)
    {
        for(int j=0;j<size;j++)
        {
            cout<<a[i][j]<<" ";
        }
        cout<<endl;
    }
}

int main()
{
    int a[4][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
    int size = sizeof(a)/sizeof(a[0]);
    print(size,a);
    return 0;
} 

我没有错误,代码成功运行。

对于第一个代码,而不是使用a[i][j],我尝试使用*(*(a+i)+j),得到了分段错误。

然后我在分段错误点调试了第一个代码并吸收了以下内容:

> p a
$1 = (int **) 0x22fd30
> p *a
$2 = (int *) 0x200000001
> p **a
Cannot access memory at address 0x200000001

我相信a拥有2d数组的第一个地址。但是对于p ** a,错误消息中显示了不同的地址。

然后我在http://ideone.com/中运行了第一个代码并遇到了运行时错误。我哪里弄错了?为什么调试器显示不同的地址?。

5 个答案:

答案 0 :(得分:1)

在你的第一个例子中

void print(int size, int **a)

期望类型为的第二个参数指向指向int 的指针。但是这里

int a[4][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
print(size,(int **)a);

传递一个变量类型 4个4个数组的数组。当您将数组传递给function时,数组会衰减到指向其第一个元素的指针。实际上,函数print得到类型为int *[4]的参数 - 指向4个整数的数组的指针,这不是print所期望的。这是一个错误。您从编译器隐藏此错误,告诉他a类型为int **。它没有。因此分割错误。

在你的第二个例子中

void print(int size, int a[][4])

需要一个类型 4个整数数组的参数。当它传递给int *[4]函数时,它会衰减到a,这恰好是print的类型。这里没有错误。

答案 1 :(得分:0)

如果索引int **,例如在[0]中,结果类型为int *。如果再次索引,如在[0] [0]中,它将解释第一个元素(是整数1)(或64位的前两个元素)作为指向int(int *)的指针并尝试取消引用它,这显然是不正确的,通常会导致分段错误。

你的C风格演员表(int **)被翻译成reinterpret_cast。这就是为什么我不喜欢C风格的演员表,因为他们所做的并不总是很明显。

简而言之:使用你的转换为(int **),你告诉编译器它是一个指向int的指针数组,它不是:它是一个int [4]&#39;的数组。

编辑:我对64位的评论仅适用于sizeof(int)始终为4的平台。我相信linux sizeof(int)== sizeof(int *)。

答案 2 :(得分:0)

cout<<a[i][j]<<" ";替换为cout<<a[i*size+j]<<" ";

答案 3 :(得分:0)

您遇到的问题是因为两者的数据类型不同。 int arr [] []与int ** arr不同。当你声明int arr []时让我们从1-d数组看,arr和int * arr一样。当你试图在内部访问arr [i]编译器做什么*(arr + i)。但是当你声明 int arr [] [size]时,arr的数据类型是int(* arr)[size] ,这与int ** arr不同。这就是你得到错误的原因。请参阅此Link

答案 4 :(得分:0)

以下适用于我:

分配和分配:

int** foo( int N, int M)
{
    int** arr;
    arr = (int **)malloc(sizeof(int *)*N);
    for(int i=0; i < N; i++) {
        arr[i] = (int *)malloc(sizeof(int)*M);
    }

    int x=0;
    for(int i=0;i<N;i++)
    {
        for(int j=0;j<M;j++)
        {
            arr[i][j]=x;
            x++;
        }
    }
    return arr;
}

现在您可以像这样使用它:

void print(int size, int a[][4])
{
    for(int i=0;i<size;i++)
    {
        for(int j=0;j<size;j++)
        {
            cout<<a[i][j]<<" ";
        }
        cout<<endl;
    }
}
int main()
{
    int N=2;
    int M=3;
    int** foo = bar(N,M);
    print(arr,N,M);
}