访问传递给函数的二维数组时出现分段错误

Segmentation fault from accessing 2d array passed to a function

本文关键字:分段 错误 二维数组 函数 访问      更新时间:2023-10-16

我正在使用代码:块。

编译了以下代码(没有错误),运行时出现分段错误。

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/并遇到运行时错误。我哪里搞错了?为什么调试器显示不同的地址?。

在您的第一个示例中

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 int的数组组成。当您将数组传递给函数时,数组会衰减为指向其第一个元素的指针。所以实际上函数print得到类型为int *[4]的参数-指向4个int数组的指针,这不是print所期望的。这是个错误。对于编译器告诉他a的类型为int **,您可以隐藏此错误。事实并非如此。因此出现了分段错误。

在你的第二个例子

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

需要一个类型为的参数,该数组包含4个整数的数组。当它在传递给print函数时衰减时,它衰减为int *[4],这正是a的类型。此处没有错误。

如果对一个int**进行索引,例如在您的情况下为[0],则结果类型为int*。如果你再次对其进行索引,就像在[0][0]中一样,它会将第一个元素(整数1)(或64位上的前两个元素)解释为指向int(int*)的指针,并试图取消对它的引用,这显然是不正确的,通常会导致分段错误。

您的C样式强制转换(int**)将被转换为interpret_cast。这就是为什么我不喜欢C风格的类型转换,因为它们的作用并不总是显而易见的

简言之:通过对(int**)的强制转换,你告诉编译器这是一个指向int的指针数组,但事实并非如此:它是一个int[4]的数组。

编辑:我对64位的评论只适用于sizeof(int)总是4的平台。我相信在linux上sizeof(int)==sizeof(int*)。

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

您面临的问题是因为两者的数据类型不同。int arr[]不同于int**arr。让我们从一维数组中看到,当您声明int arr[]时,arr与int*arr相同。当您试图在内部访问它时,arr[i]编译器会做什么*(arr+i)。但是当您声明int arr[][size]时,arr的数据类型是int(*arr)[size],这与int**arr不同。这就是你出错的原因。请参阅此链接

以下对我有效:

分配和分配:

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