0

I've encountered a situation where I gotta do some math in a function into a matrix (the dimensions of this are unknown at compile time so I gotta save it as a pointer) and then equate it to a pointer I pass as argument to the function.

The code throws a segmentation fault each time. I have a sample code here:

#include <iostream>
using namespace std;
void assign(int **a)
{
  int **A = new int* [3];
  int i, j;

  for(i = 0; i < 3; i++)
    A[i] = new int[3];

  for(i = 0; i < 3; i++)
    for(j = 0; j < 3; j++)
      A[i][j] = 100;

  a = A; /* equating the pointers */
}

int main()
{
  int **ptr;
  assign(ptr); /* Passing my pointer into the function */
  cout << ptr[0][0] << endl;
  return 0;
}

The code is in C++ and it is not an option for me to make the function have a return type other than void. And I don't want to save my matrix on a normal pointer by row/column major - I need to know why this doesn't work.

1
  • @Nidish Have you tried to write the 'assign' function that assigns value to a simple 'int' instead of an 'int**'? Write it in the same way and try to check whether the value before the assignment and after differ in any way - denniskubes.com/2012/08/20/is-c-pass-by-value-or-reference Commented Jan 23, 2016 at 15:23

2 Answers 2

5

Look carefully at your code:

void assign(int** a)
{
    // ...
}

int main()
{
    int** ptr;
    assign(ptr);
}

You're passing a by value - after calling assign(ptr), you will not modify ptr itself inside the function body, but merely a copy of ptr.

Take ptr by reference instead:

void assign(int**& a)
{
    // ...
}

Other possible solutions:

  1. Add another level of indirection.

    void assign(int*** a)
    {
        // ...
        *a = A;
    }
    
    int main()
    {
        int** ptr;
        assign(&ptr);
    }
    
  2. Return from assign.

    int** assign()
    {
        // ...
        return A;
    }
    
    int main()
    {
        int** ptr;
        ptr = assign();
    }
    
Sign up to request clarification or add additional context in comments.

3 Comments

+1. I think that returning A from assign() is the simplest and best way (no need to worry about passing by value/reference).
No point in passing a into assign at all any more. Your last example should be int** assign().
@LightnessRacesinOrbit: whoops, fixed. Thanks!
1

Think about what actually happens in your code in terms of memory. Here's an illustration, taking some imaginary memory addresses for now:

    in main():                                 in assign():
ptr at 0x0100, value: garbage_ptr
                                    call
                                   ----->
                                           a at 0x0200, value: garbage_ptr
                                           [after some computation]
                                           A at 0x0204, value: 0x0400
                                           [after the line: a = A;]
                                           a at 0x0200, value: 0x0400
ptr at 0x0100, value: garbage_ptr

You can see how nothing is ever written to 0x0100, the address of ptr. That's because a in assign() gets the value of ptr; it doesn't know where ptr is. ptr still points to the untouched (garbage) value that it did when its scope started at the beginning of main().

Suppose, now, that instead change the code to:

...
void assign(int ***a)
{
    ...
    *a = A;
}

int main()
{
    int **ptr;
    assign(&ptr);
    ....

The above illustration now becomes:

    in main():                         in assign():
ptr at 0x0100, value: garbage_ptr
&ptr rvalue, value: 0x0100
                                     call
                                   ----->
                                           a at 0x0200, value: 0x0100
                                           *a at 0x100, value: garbage_ptr
                                           [after some computation]
                                           A at 0x0204, value: 0x0400
                                           [after the line: *a = A;]
                                           a at 0x200, value: 0x0100
                                           *a at 0x100, value: 0x0400
                                   return
                                   <-----
ptr at 0x100, value: 0x0400

This way, the value at 0x0100 does get changed, which is what you wanted. (Actually, you should use a reference for this kind of thing in C++, but it's easier to show the error with pointers.)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.