• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 231
  • Last Modified:

Parameter Pointer Initialization problem

typedef stuct tagTest{
int x1;
int x2;
}Test;

class C1
{
void fn();
fn1(Test *);
};

//implementation

void C1::fn()
{
Test* pTest;
fn1(pTest);
pTest->x1 = 1; //I am getting an
               //assertion here??
}

void C1::fn1(Test* pTest)
{
pTest = new Test;
pTest->x1 = 0;
pTest->x2 = 0;
}

In 'fn1' pTest is getting initialized.
But once the function returns, the pTest
pointer seems to be damaged.

Can somebody help me, what is the problem with this code?

0
Thirstyplusplus
Asked:
Thirstyplusplus
  • 7
  • 4
  • 4
  • +4
1 Solution
 
rgoughCommented:
When you pass a variable into a function a copy of the variable is made on the stack and passed in, not the variable itself.  If you want to alter the value of a passed in parameter you must pass in a pointer to the variable, in this case fn1(Test**).  You would then call it like this:

void C1::fn()
{
    Test* pTest;
    fn1(&pTest);
}

A better method would be:

void C1::fn()
{
   Test* pTest = fn1();
   pTest->x1 = 1;
}

Test* C1::fn1()
{
   Test* pTest = new Test;
   pTest->x1 = 0;
   pTest->x2 = 0;
   return pTest;
}
0
 
inprasCommented:
Hi Thirstyplusplus
Check this U were using parameter passing but not returning the value U know other fundas I believe
#include "stdio.h"

typedef struct tagTest{
int x1;
int x2;
}Test;

class C1
{
public:
void fn();
Test *fn1(Test *);
};

//implementation

void C1::fn()
{
Test* pTest;
pTest = fn1(pTest);
pTest->x1 = 1; //I am getting an
               //assertion here??
}

Test *C1::fn1(Test* pTest)
{
pTest = new Test;
pTest->x1 = 0;
pTest->x2 = 0;
return pTest;
}
void main()
{
      C1 tryC;
      tryC.fn();
}

Regards
0
 
iarlaCommented:
The simplist waqy to solve you problem is allocate Test in fn

e.g.

void C1::fn()
{
  Test* pTest;
  pTest = new Test;
  fn1();
  pTest->x1 = 1;
}

void C1::fn1(Test* pTest)
{
pTest->x1 = 0;
pTest->x2 = 0;
}
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
jasonclarkeCommented:
or if you really want Test in the parameter list, just change the declaration of fn1 to look like:

void C1::fn1(Test*& pTest)

BTW, you do realise you don't need the C style struct definition, just:

struct Test { ... };

would have been fine.
0
 
ThirstyplusplusAuthor Commented:
Hi All,
If I return the pointer then it is working fine. But I need to use the return value to check some other status.
I also do not want to allocate storage in the calling function. Therefore only
way out is passing the pointer variable as an argument.

jasonclarke / rgough,

I tried both of ur suggestions but getting compiler error. Can u please show the syntax for declaration and implementation for fn1(????).

rgough,

What I understand is when a pointer variable is passed as an argument to the function, we are dealing with the address of the variable which may be stored in the stack.
In this case,
Test* pTest;
fn1(pTest); //pass address of pTest

Why a pointer to a pointer is required?

Also if I allocate the storage in the calling function i.e. fn(), then my code works fine.

What I need is a function to allocate storage for a Pointer Variable that is created outside the function.

Thanks for ur help.



0
 
inprasCommented:
Hi thirstyplusplus
U haven't mentioned about my solution is it working and meets UR requirement?
Regards
0
 
ThirstyplusplusAuthor Commented:
Hi inpras,

Ur solution works but doesn't meet my
requirement 'cause I do not want to return the pointer. I intent to use the return value for some status checking.

Since I am passing the address of the pointer variable, I believe it should be possible  to allocate storage directly to that variable. I think I am missing the correct syntax. Please bear with me.

thanks and regards.

0
 
inprasCommented:
Hi Thirstyplusplus
as the C++ help says
The new keyword allocates memory for an object of type-name from the free store and returns a suitably typed, nonzero pointer to an object. So the new keyword which U are allocating in function will allocate a new memory address space which is not same as the pTest address of function fn()
any how what status value U want to test? U can return only that value and check it but U can't do what ever U were doing accessing the member of pTest pointer in  fn() function
Regards
0
 
ThirstyplusplusAuthor Commented:
Hi inpras,

Thanks for ur comment but it is still not clear.

In this case:
1. I am creating a pointer variable of type 'Test' in fn().

2.  I am passing the pointer 'pTest' of type 'Test' as argument to the function f1().

3. Inside f1() I am allocating storage for the pointer pTest. The new operator also returns a pointer of type 'Test'. Since both the pointers are of same type it should be possible to assign the same. After the assignment, the passed pointer 'pTest' should point to whatever storage area pointed by, the pointer returned by the new operator.

This is happening inside the called function fn1() but is lost upon exiting
the function. I don't understand why.

It is really baffling?????????



regards


   

0
 
inprasCommented:
Hi Thirstyplusplus

Let me illustrate

the values of observe the values pTest
in function fn()
after Test* pTest;
pTest will be 0x00000003
in call of fn1(pTest) pTest will be 0x00000003
now in fn1()
till pTest = new Test; pTest will be 0x00000003
but as the statement new executes pTest will be assigned a new memory space and hence the location therefore after the above statement pTest will be someother value say0x00420af0
when U return this val it will be assigned back to pTest which again in fn() function will be 0x00000003 (local to fn() function
Hope I cleared UR doubt

Regards
0
 
vsriCommented:
Hi

Try out this way...

#include <iostream.h>

struct Test
{
      int x1;
      int x2;
};

void Function2(Test** ptr)
{
      *ptr       = new Test;
      (*ptr)->x1 = 1;
      (*ptr)->x2 = 2;
}

void Function1()
{
      Test* ptr;
      Function2(&ptr);  
      ptr->x1 = 3;      // Now, You will not get assertion here.
      cout << "ptr->x1 = " << ptr->x1 << endl;
      cout << "ptr->x2 = " << ptr->x2 << endl;
      delete ptr;      
      //...      
}


void main()
{
      //...

      Function1();

      //...
}
0
 
vsriCommented:
Hi

Try out this way...

#include <iostream.h>

struct Test
{
      int x1;
      int x2;
};

void Function2(Test** ptr)
{
      *ptr       = new Test;
      (*ptr)->x1 = 1;
      (*ptr)->x2 = 2;
}

void Function1()
{
      Test* ptr;
      Function2(&ptr);  
      ptr->x1 = 3;      // Now, You will not get assertion here.
      cout << "ptr->x1 = " << ptr->x1 << endl;
      cout << "ptr->x2 = " << ptr->x2 << endl;
      delete ptr;      
      //...      
}


void main()
{
      //...

      Function1();

      //...
}
0
 
ThirstyplusplusAuthor Commented:
Hi inpras,

Thanks for the prompt reply. I beg to differ in two counts.

1. What u said would have been correct
 had the variable been passed by value. Here, the function argument pTEst is the address of a pointer variable. So by  c++ teachings, the address of the variable rather than the copy  that will be pushed to the stack. Hence, the original object can be accessed directly from the called function fn1().

2. Also there is noting to believe that the compiler makes some implied assignments when the called function returns. The actual storage is not local to the function, it is from the free heap. Only the pointer variables created locally goes out of scope when the function returns, not the heap area pointed by these variables. That need to be deleted explicitly.

In this case, the scope and lifetime of the pointer is within the caller function 'fn()'.

Thank you for ur patience.

regards.





0
 
rgoughCommented:
Hi Thirstyplusplus,

inpras,
Regarding your reply on 12/2/99 01:32 am PST
I hope you went to bed shortly after you wrote that; I've been programming C/C++ professionally for over 10 years and your explanation confused me!  ;-)

Thirsty,

I'm not sure if you're still confused on this issue or not but I will attempt a more verbose explanation.

In your original question you declare a pointer to a Test in fn() and then pass the pointer into fn1().  What happens is that a copy of the pointer is pushed onto the stack and it is that copy which is used by fn1().  You now have two pointers to the same uninitialized spot in memory.  When you then allocate a Test object with the new operator and assign its return to the copy of the pointer you change the value of the copy, not of the original pointer.  The copy now points to the new Test object but the original pointer is still uninitialized.  At the end of fn1() the copy pointer goes out of scope and there is no way for the value of the pointer (i.e. the location of the Test object) to be communicated back to the original pointer.  The allocated object is lost forever since the only pointer that pointed to it is gone.  This is called a memory leak.  This is bad.  This is very, very bad!!  What you could do is create the new Test object in fn1() and return its value to fn() to initialize the original pointer like this:

void C1::fn()
{
    Test* pTest;
    pTest = fn1();
    pTest->x1 = 1;
}

Test* C1::fn1()
{
    Test* pTest = new Test;
    pTest->x1 = 0;
    return pTest;
}

BTW it is not necessary to pass the original pointer into fn1() since it will be destroyed anyway, you can create it locally in fn().
By contrast if you had created the new Test object in fn() and passed a pointer to it to fn1() thusly:

void C1::fn()
{
    Test* pTest = new Test;
    fn1(pTest);
}

void C1::fn1(Test* pT)
{
    pT->x1 = 1;
}

you would then be able to manipulate the members of the Test object using the passed in pointer.  Note that in this example pTest in fn() and pT in fn1() are two different pointers that point to the same object in memory.  They have the same value.

Perhaps an analogy will help illustrate the point.  Suppose you and I are connected to the same local network.  I create a document on some shared drive and I want to show it to you and have you comment on it.  I attach a copy of the document to an e-mail and send it to you.  You open the document, edit the copy, close it and then delete the e-mail.  The changes are lost.  This is passing by value.  If, on the other hand, I send you an e-mail containing the location of the document on the network (its address) you can make changes to it and the changes will be saved.  This is passing by reference, or passing a pointer.  Now in your case I am telling you I want a document so I think of a place for it to be on the network and ask you to create it (I'm fn() and you're fn1()).  You create the document and whatever application you use puts it not where I wanted to put it but wherever it wants to put it which is fine, that's the way it's supposed to work.  The problem is that you never reply to my e-mail and tell me where the application put the document. If you return the location of the new document to me I can update my pointer to it and work on the document myself.

Hope this helps.
0
 
MaydipalleCommented:
Hi,
  You are passing parameter "byvalue" not "byreference".To pass byreference you have to do as follows.This will work perfectely.If you want analasis what you are doing please let me know.

typedef struct tagTest{
      int x1;
      int x2;
}Test;

class C1
{
public:
      void fn();
      void fn1(Test** );
};

void C1::fn()
{
      Test* pTest = 0;
        fn1(&pTest);
      pTest->x1 = 1;
      printf("%d\n",pTest->x1);
}

void C1::fn1(Test** pTest)
{
      *pTest = new Test;
      (*pTest)->x1 = 0;
      (*pTest)->x2 = 0;
}
0
 
vsriCommented:
Hi Thirstyplusplus,

Did you try out solution that I have proposed? Let me know your comment.

Reagrds,
vsri
0
 
ThirstyplusplusAuthor Commented:
rgough,vsri & Maydipalle gave almost identical solution.

Instead of passing the address of the pointer, I was passing the pointer variable itself.

I am not the right person to judicially evaluate the answers given by three experts towards the same problem.

Personally I feel that:

rgough gave lot of explanation but the code given was incomplete.

vsri gave clean code but no description.

Maydipalle also gave the clean code but the description was wrong.
"  You are passing parameter "byvalue" not "byreference".To pass byreference you have to do as follows."...

I think there is a difference between passing by reference and passing the address.

I may be wrong, I am not sure. So please suggest who deserve the points.

Thank u all and regards.
0
 
rgoughCommented:
Award the points to the answer that was most helpful to you in understanding the solution to your problem.

> rgough gave lot of explanation but the code given was incomplete.

How so?  The code given was meant to illustrate the explanation, not be a full compilable program.

> I think there is a difference between passing by reference and passing the address.
> I may be wrong,

Sorta yes and sorta no.  In C & C++ you can pass a parameter by value or by reference.  If you pass by value you pass the value of a variable or object into the function.  It is actually a copy of the value and modifying the passed in parameter does not modify the value of the original variable, only the copy.  If you pass a pointer to a variable or object into a function the function can use that pointer to modify the original object.  The pointer is a copy but it still points to the original.  The difference is in the way you use the parameter.  This is the only way to pass by reference in C.  C++ adds something called a "reference" denoted X& (a reference to X).  It is like a pointer in that you can pass it into a function and the function can then modify the original object but unlike a pointer you can't make it point to another object.  e.g.

void C1::foo()
{
    int X, Y;
    X = 2;
    Y = 3;
    int* pX = &X;      // pointer pX contains the address of X
    bar( pX, Y);        // pass in X as a pointer and Y as reference
}

void C1::bar( int *nPtr, int &nRef)
{
    int Z = 5;
    printf("%d", *nPtr);  // nPtr points to X
    nPtr = &Z;               // nPtr points to Z
    nRef = Z;                // nRef points to Y and makes Y = 5
}

Syntactically a reference is used the same as the object itself, that is you use the dot to access members of a class or structure not an arrow.  But it is used like a pointer in that it can be used to alter the value of an object created in a different scope.

I hope this helps. (And I haven't the foggiest idea why I am doing so much typing for 100 points. Probably because I had trouble with pointers when I started out. :-)
0
 
ThirstyplusplusAuthor Commented:
Hello rgough,
>>The pointer is a copy but it still >>points to the original.  

This is the point I failed to understand in my original code.

So instead of passing the copy of the variable I passed the address of the pointer variable i.e. pointer to a pointer and the problem was solved.

Do you think that this question worth more than 100 points?


0
 
rgoughCommented:
> Do you think that this question worth more than 100 points?

No, 100 points is fair.  Pointers and parameter passing are both concepts that are obvious once you get it, but understanding it in the first place is sometimes difficult.  I was used to BASIC when I learned C and it was a struggle for me too.  Get some experience with it and it will become second nature to you.

> So instead of passing the copy of the variable I passed the
> address of the pointer variable i.e. pointer to a pointer and
> the problem was solved.

I still think that the better approach would be to not pass the pointer at all and return a pointer from the function that creates the object as in my first comment, but hey, whatever works!

Cheers
0
 
jasonclarkeCommented:
A reference to the pointer variable would probably be better in this case beacause:

i) it makes it clear that the intention is to change what the pointer looks at (when you pass a parameter as a non-const reference, you expect its value to be changed).

ii) the object msut be a valid pointer object, passing 0 as the parameter will not be allowed.

iii) it simplifies the syntax of the parameter in use.

i.e. do it like this:

class C1
{
public:
void fn();
void fn1(Test*& );
};

void C1::fn()
{
   Test* pTest = 0;
   fn1(pTest);
   pTest->x1 = 1;
   printf("%d\n",pTest->x1);
}

void C1::fn1(Test*& pTest)
{
    pTest = new Test;
    pTest->x1 = 0;
    pTest->x2 = 0;
}

0
 
ThirstyplusplusAuthor Commented:
I am convinced that passing reference is a better approach in c++ context. I want to find out why pointer passing should not work.

Now I have another trouble in returning a structure by reference. I will ask this as a separate question.

Till then bye and thank u all.

regards




0

Featured Post

[Webinar] Kill tickets & tabs using PowerShell

Are you tired of cycling through the same browser tabs everyday to close the same repetitive tickets? In this webinar JumpCloud will show how you can leverage RESTful APIs to build your own PowerShell modules to kill tickets & tabs using the PowerShell command Invoke-RestMethod.

  • 7
  • 4
  • 4
  • +4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now