-4

What is the correct way to pass pointers to an array from one C++ program to another linked C++ program?

I have a C++ program and it calls a function named SaveGatheredVec() in another C++ program that is included using the header file. SaveGatheredVec() shall return a pointer to an array that I can print from the function I called. But when I do something like below, the pointer is not getting the correct address of the array and just prints Segmentation Fault.

AS THE CODE IS LITTLE MESSY AND A LOT OF THINGS ARE GOING ON, just looking at NodesVisited[] and pointer p is what I need help with. I even tried declaring a global variable in the cpp program from where I call SaveGatheredVec and pass the array to the function, but it still gives the same error.

    #include<iostream>
    #inlcude "AnotherC++Program.h"
    ...
    main(){
     BFS();
    }

    void BFS(PSpMat<ElementType>::MPI_DCCols D, PSpMat<ElementType>::MPI_DCCols B, int ACol, string output){
        int *p=0;      
        PSpMat<ElementType>::MPI_DCCols C = Mult_AnXBn_DoubleBuff<PTDOUBLEDOUBLE, ElementType, PSpMat<ElementType>::DCCols>(D,B);
            int64_t cnnz = C.getnnz();
            ostringstream tinfo;
            p=C.SaveGatheredVec(output);

            for(int i=0; i<cnnz; i++)
              cout << "\n-----" << *(p+i);// on return it says Segmentation Fault

      }  

SaveGatheredVec() is defined in another C++ program linked by a header as below:

     #include<iostream>
        ...

       template <class IT, class NT, class DER>
template <class HANDLER>
int * SpParMat< IT,NT,DER >::SaveGatheredVec( string filename, HANDLER handler, bool transpose) const
{
    int proccols = commGrid->GetGridCols();
    int procrows = commGrid->GetGridRows();
    IT totalm = getnrow();
    IT totaln = getncol();
    //IT totnnz = getnnz();
    IT totnnz = 1;    
    static int NodesVisited[1]; //for example purpose, this is made just of size 1
    int increament=0;
    int flinelen = 0;
    ofstream out;
    if(commGrid->GetRank() == 0)
    { 
        std::string s;
        std::stringstream strm;
        strm << "%%MatrixMarket matrix coordinate real general" << endl;
        strm << totalm << " " << totaln << " " << totnnz << endl;
        s = strm.str();
        out.open(filename.c_str(),ios_base::trunc);
        flinelen = s.length();
        out.write(s.c_str(), flinelen);
        out.close();
    }
    int colrank = commGrid->GetRankInProcCol(); 
    int colneighs = commGrid->GetGridRows();
...

for(int j = 0; j < 2; ++j) 
            {
                IT rowcnt = 0;
                sort(csr[j].begin(), csr[j].end());
                int mysize = csr[j].size();
                MPI_Gather(&mysize, 1, MPI_INT, gsizes, 1, MPI_INT, 0, commGrid->GetRowWorld());
                if(commGrid->GetRankInProcRow() == 0)    
                {
                    rowcnt = std::accumulate(gsizes, gsizes+proccols, static_cast<IT>(0));
                    std::partial_sum(gsizes, gsizes+proccols-1, dpls+1);
                    ents = new pair<IT,NT>[rowcnt];  
                }

                MPI_Gatherv(SpHelper::p2a(csr[j]), mysize, datatype, ents, gsizes, dpls, datatype, 0, commGrid->GetRowWorld());

                if(commGrid->GetRankInProcRow() == 0)    
                {
                    for(int k=0; k< rowcnt; ++k)
                    {

                        if (!transpose){
//NodesVisited is assigned below
                            NodesVisited[increament]= j + roffset + 1; increament++;
                            out << j + roffset + 1 << "\t" << ents[k].first + 1 << "\t"; 

                            handler.save(out, ents[k].second, j + roffset, ents[k].first);} 
                        else
                            { 
                            out << ents[k].first + 1 << "\t" << j + roffset + 1 << "\t";
                         handler.save(out, ents[k].second, j + roffset, ents[k].first); 
                        }
                        out << endl;
                    }
                    delete [] ents;
                }
            }
            if(commGrid->GetRankInProcRow() == 0)
            {
                DeleteAll(gsizes, dpls);
                out.close();
            }
        } 
        MPI_Barrier(commGrid->GetWorld());       
    }
    for(int j=0; j<totnnz;j++)
        cout << "\nHere" << NodesVisited[j]; //values are printed correctly here

return NodesVisited;
}

If someone can help with an example or some ideas how should I retrieve the values of an array from a function defined in another C++, it would be of great help as I have to use the function defined in another C++ function. Thanks.

user2720919
  • 27
  • 1
  • 9
  • 1
    So you have a program that sets aside some memory, and uses it, and another program should also access that same memory? I think that's a no-no. What you need to do is pass copies of the value, then use those values to calculate new values and pass those values back. – Tas Jul 31 '17 at 02:45
  • 3
    Something tells me you don't actually have two *programs*. What are you calling a program, .cpp file? – HolyBlackCat Jul 31 '17 at 02:46
  • each process has its own virtual address space. You can't pass a pointer to another process because the address has no meaning in that space – phuclv Jul 31 '17 at 02:48
  • 2
    Recommended reading: [How does the compilation/linking process work?](https://stackoverflow.com/questions/6264249/how-does-the-compilation-linking-process-work) – user4581301 Jul 31 '17 at 03:19

2 Answers2

3

What exactly do you mean by "different program"? Do you mean a different .cpp file? In that case that would be a different translation unit, and it doesn't really have any effect as to pointers - that is, you probably have a bug elsewhere.

If you meant a different programs as in a different process, then that isn't possible in user-mode. Each process has its own virtual address space, specifically designed and implemented in hardware and OS so that processes cannot access each other's memory.

Note: This is possible in kernel-mode drivers, where all drivers share the same virtual address space.

You should post more of your code, as it is very difficult to see what you are actually doing in fun, and what data structure your return pointer is pointing to. However, I would venture a guess that you are creating a local array - that is, in the stack - and returning a pointer to that. Stack variables get destroyed once they fall out of scope, which would explain why your pointer becomes invalid once the function returns.

Update: In your SaveGatheredVec function, in the line static int NodesVisited[1];, static makes all the difference. Without it, NodesVisited would be in the stack and a pointer to it would be invalidated once the stack unwinds on function return. See The stack and the heap and this SO question.

However, because you used static it lives until the end of the program, and there isn't anything immediately obvious. Try printing the value of NodesVisited, the pointer, and of p in BFS, and check that they are the same. Also, check that totnnz in SaveGatheredVec and cnnz in BFS have the same value - they should both be 1 in your example. If cnnz is larger then you'll read out of bounds and cause the seg fault.

NodesVisited[increament]= j + roffset + 1; increament++;

increament[sic: increment] should never go above 0 in your example.

Ramon
  • 1,169
  • 11
  • 25
  • By different program, I do mean a different .cpp file. If it does not have any effect to pointers, then how to get the values computed by the other program? – user2720919 Jul 31 '17 at 03:16
  • 1
    @user2720919 It's not "the other program", it's just part of the same program. It's (mostly) the same as having `fun` in your main file. As to passing values computed by `fun` to other functions, it depends on how you store that data - it could be in the heap, in a global variable, you could pass it by value. If you edit your question and post the entire body of `fun` it would be easier to help you. – Ramon Jul 31 '17 at 03:27
  • Thanks....I did a quick small version of this and it is working actually fine. Somehow HANDLER was causing some issue. I am not sure why is that though but passing arrays is perfect! – user2720919 Aug 01 '17 at 23:03
  • Good to hear. Cheers! – Ramon Aug 01 '17 at 23:25
0

As @Ramon says you should put more code about fun() function. To use properly the int* pointer you first of all have to initialize it, and then create a space of memory where it points to, to copy the elements of the array you want in it.

Math Lover
  • 148
  • 10