Sab
Sab

Reputation: 533

Segmentation fault from accessing 2d array passed to a function

I am using Code:Block.

Compiled the following code(no errors) and while running got segmentation fault.

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

I tried using different methods of passing the array:

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

I got no error, code ran successfully.

For the first code instead of using a[i][j], I tried with *(*(a+i)+j), got segmentation fault.

Then I debugged the first code at the point of segmentation fault and absorbed the following:

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

I believe that a hold the first address of the 2d array. but for p **a there is a different address shown in the error message.

Then I ran the first code in http://ideone.com/ and encountered run time error. Where am I making mistake? and why the debugger showing different address?.

Upvotes: 2

Views: 2128

Answers (5)

nullgraph
nullgraph

Reputation: 307

The following works for me:

Allocation and assignment:

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

Now you can use it like this:

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

Upvotes: 1

kotlomoy
kotlomoy

Reputation: 1430

In your first example

void print(int size, int **a)

expects second argument of type pointer to pointer to int. But here

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

you pass a variable of type array of 4 arrays of 4 ints. When you pass an array to function, array decays to pointer to its first element. So actually function print gets argument of type int *[4] - pointer to array of 4 ints which is not what print expects. That's an error. You hide this error from compiler telling him that a has type int **. It doesn't. Hence the segmentation fault.

In your second example

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

expects an argument of type array of arrays of 4 ints. It decays to int *[4] which is exactly the type of a when it decays while passed to print function. No error here.

Upvotes: 3

InvisibleWolf
InvisibleWolf

Reputation: 1017

Problem you are facing is because of Data type of both is different. int arr[][] is different from int ** arr. Lets see from 1-d array when you declare int arr[], arr it is same as int *arr. When you try to access it arr[i] internally what compiler does *(arr+i). But when you declare int arr[][size] data type of arr is int (*arr)[size] which is different from int **arr. That's why you get error. see this Link

Upvotes: 1

Andrii
Andrii

Reputation: 1906

Replace cout<<a[i][j]<<" "; with cout<<a[i*size+j]<<" ";

Upvotes: 1

heinrichj
heinrichj

Reputation: 552

If you index an int**, in your case a[0] for example, the resulting type is int*. If you index that again, as in a[0][0], it will interpret the first element (being the integer 1) (or first two elements on 64-bit) as a pointer to int (int*) and attempt to dereference it, which is obviously incorrect and will usually lead to a segmentation fault.

Your C-style cast (int**) is translated to a reinterpret_cast. Which is why I don't like C-style casts as it's not always obvious what they do.

In short: with your cast to (int**) you're telling the compiler that it's an array of pointers to int, which it isn't: it's an array of int[4]'s.

Edit: my comment about 64-bit only holds for platforms where sizeof(int) is always 4. I believe on linux sizeof(int) == sizeof(int*).

Upvotes: 2

Related Questions