CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 6 of 6
  1. #1
    Join Date
    Sep 2006
    Posts
    13

    Correct way to pass a pointer to a structure

    Hi

    This problem is driving me crazy


    #include "stdafx.h"
    #include "fstream.h"

    struct myStruct {
    int a;
    int b;
    } *myStruct_;

    void tryToInitialiseArray(myStruct *ms);

    int main(int argc, char* argv[])
    {

    myStruct_ = NULL;

    tryToInitialiseArray(myStruct_);

    cout << myStruct_[0].a << endl;

    printf("Hello World!\n");
    return 0;
    }

    void tryToInitialiseArray(myStruct *ms) {
    ms = new myStruct[3];
    ms[0].a = 1;
    ms[0].b = 11;
    ms[1].a = 2;
    ms[1].b = 22;
    ms[2].a = 3;
    ms[3].b = 33;
    }


    This small program exhibits the problem that I am having.

    I have a pointer to a struct, which I want to initilise (new) in a function.

    It compiles okay - and runs, but crashes at the 'cout'. Running in Debug you can see that after the call to tryToInitialiseArray, myStruct_ is still NULL.

    I guess this is because the myStruct_ is being passed by copy (not as a pointer or reference) - but I don't understand why.

    Can anybody help?

    (I have also tried it without the 'struct" in the function definition, with the same results.

    Thx

  2. #2
    Join Date
    Sep 2004
    Location
    Holland (land of the dope)
    Posts
    4,123

    Re: Correct way to pass a pointer to a structure

    myStruct_ is the definition.

    Code:
    myStruct_ myStructPtr = NULL;
    
    tryToInitialiseArray (&myStructPtr);
    In this case you are passing a pointer to a pointer.

  3. #3
    Join Date
    May 2006
    Location
    beyond the pillars of hercules
    Posts
    295

    Re: Correct way to pass a pointer to a structure

    Code:
    void tryToInitialiseArray(myStruct *ms) 
    {
    ms = new myStruct[3];
    ms[0].a = 1;
    ms[0].b = 11;
    ms[1].a = 2;
    ms[1].b = 22;
    ms[2].a = 3;
    ms[3].b = 33;
    
    std::cout << ms[0].a << std::endl;
    
    }

  4. #4
    Join Date
    Nov 2006
    Posts
    1,611

    Re: Correct way to pass a pointer to a structure

    So far the underlying problem has been missed.

    Though Skizmo's reply hints to the issue.


    consider these two lines

    myStruct_ = NULL;

    tryToInitialiseArray(myStruct_);



    and this declaration

    void tryToInitialiseArray(myStruct *ms);


    When this function is called, a COPY of the pointer myStruct_ will be pushed on the stack.

    The function will allocated a new myStruct on that copy.

    When the function returns, the caller will still be looking at the "original", not the copy, which will still be null (as initialized)

    The allocated struct is lost to a memory leak.


    There are several solutions depending on how "C" you need to remain.

    You can use the C++ reference, re-declare the function to be:

    void tryToInitialiseArray(myStruct *& ms);


    Now, it acts upon a reference to a pointer. This is related to the C version of the same idea, a pointer to a pointer:

    void tryToInitialiseArray(myStruct ** ms);

    Either offers a solution.

    In the "C" version, pointer to a pointer, a copy of the the address of the pointer is pushed onto the stack for the call.

    The function itself will have to be modified

    Code:
    void tryToInitialiseArray(myStruct **ms) 
    {
     *ms = new myStruct[3];
    (*ms)[0].a = 1;
    ...
    }
    To comply with this method.

    Now, however, the copy of the address doesn't obscure the underlying pointer which the caller is attempted to have allocated for it.


    Using the reference to a pointer approach, the same "pointer to a pointer" is passed, but the compiler offers the added convenience of leaving the original form of the function intact, as the reference is "automatically de-referenced" when it is used (that' the nature of a reference).

    In either case, this makes the function act upon the caller's pointer, not a copy of that pointer.


    Let me underscore the point which gets students' heads spinning out of control.

    A copy of an address is not a pointer, it's a pointer TO a pointer.

    A copy of a pointer is just that, a copy.


    consider...

    void func( int );


    a = 5;

    func( a );


    What happens here? A copy of a is pushed on the stack. Whatever func does to a inside, the caller's "original" for a is unchanged.

    void func( int & );

    func( a );

    Now what happens? A copy of the ADDRESS of a is pushed on the stack. Inside func, this address is a pointer to an integer (the original integer in the caller's code), and is automatically de-referenced when it is used. Now, all changes made inside func are witnessed in a after func executes, because the function was directed to work upon the integer at that address.

    void func( int *);

    func( &a );

    This is similar to the reference above, but it will not be de-referenced automatically - inside func the integer pointer is exposed raw, so it will have to be dereferenced as it is used, but no matter, what it will be doing is acting upon a copy of the address of a, just as the reference version did, and so the caller's a will be modified by func.

    void func( object * );

    object *b;

    func( b );

    This is where students get off track. This looks like the example func( int *), so the changes to b ought to be seen in the caller, right? True, it is. But that's a change to the object b.....

    What tryToInitialiseArray was attempting to do was to allocate memory. In that case, the caller is expected to see the changes made to the pointer b, not just to the object to which it points. If instead you had....


    myStruct_ = new myStruct[3];

    Then....

    func( myStruct_ );

    would work if and only if the function were something like...


    Code:
    void tryToInitialiseArray(myStruct *ms) 
    {
     ms[0].a = 1; 
     ms[0].b = 11; 
     ms[1].a = 2;
     ms[1].b = 22;
     ms[2].a = 3;
     ms[3].b = 33;
    }
    Note that this function is not allocating memory. That's done in the calling code.

    We are expecting to modify the structure, not the pointer. In this configuration, the allocated myStruct_ is a pointer to an instance. The call to tryToInitialiseArray is pushing a copy of that pointer. The function is acting upon the copy, modifying the structure.

    When the function returns, the calling code is looking and using it's original myStruct_. The function never attempted to change it (it didn't need to), and it makes no difference if access modified the instance through the original pointer or a copy of it - the memory location is the same.

    It's important to visualize the difference between a function modifying what a pointer points TO, or a modification to the pointer ITSELF.

    For the latter, you have to push a copy of the ADDRESS of that pointer - or, put another way, the ADDRESS of the ADDRESS of the instance.

    For the former, you only need a copy of the pointer, a copy of the address of the instance.
    Last edited by JVene; July 26th, 2009 at 10:53 AM.
    If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).

  5. #5
    Join Date
    Sep 2006
    Posts
    13

    Re: Correct way to pass a pointer to a structure

    Wow - thank you.

    I would never have got to this.

    I have gone with declaring the function as

    void tryToInitialiseArray(struct myStruct *&ms);

    and it works a treat.

    ... and I thought that this would be a case of me doing somethig stupid but, as I say, I would not have resolved this, so thank you again.

  6. #6
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: Correct way to pass a pointer to a structure

    It's the same basic principal at work here:
    Code:
    void increment(int i)
    {
        i++;
    }
    
    int main()
    {
        int val = 0;
        increment(val);
        cout << val;
    }
    Naturally, val is not incremented because the function is working on a copy rather than the original, and 0 is printed. Some people get confused when they start dealing with pointers since they can modify the target of the pointer, but the same principal applies to the pointer itself.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured