I’m working on a beginner(!) exercise.
I am comfortable passing basic variables and also using &variable parameters so I can make changes to the variable that are not destroyed when returning. But am still learning pointers. I am working on the basic Mutant Bunny exercise (linked list practice).
In it I create a linked list by declaring Class Bunny. I set it up as you expect with a data section and a ‘next’ pointer for set up the linkage.
struct Bunny {
string name;
int age;
// more variables here
Bunny* next;
};
Everything works great when I call function to do things like create Bunnies using the function:
Bunny* add_node ( Bunny* in_root ){}
This sets up the node and returns it just like I want. I can also do things like call a function to modify the Bunny class like aging the bunnies.
void advanceAge ( Bunny* in_root ){}
I pass in the head and then I can modify the bunnies in the called function and it stays modified even when it goes back to main. For example I can use:
in_root->age ++;
in the called function and when I return to ‘main’ it is still changed. Basically I can use -> in any called function and it makes the change permanently. I think because the pointer is dereferenced(?) by the -> but still getting my head around it...
So far so good.
The problem comes up when I want call a function to delete the list. (Nuclear option… no more bunnies)
I can delete all the nodes in the called function… but it does not change the Bunny in ‘main’. For example… this does not permanently remove the node.
void DeathCheck(Bunny* in_root){
Bunny* prev_ptr;
prev_ptr = in_root;
if (prev_ptr == NULL){
cout << "No list to check age." << endl; return;
} else {
prev_ptr = NULL; // <- what could I code to have this stick? return;}
// rest of DeathCheck
I’m curious if there is a way to set the node to NULL in the called function and have it stick?
Since you're passing in_root by value, there's no way for it to modify the caller's variable. You could pass it by reference.
void DeathCheck(Bunny* &in_root) {
Bunny *prev_ptr = in_root;
...
in_root = nullptr;
return;
}
Currently, in DeathCheck(Bunny* in_root), there is no way that in_root can be changed, only the object it is pointing to can be changed. (See pass by reference and value with pointers). Based on this, you need to change the parameter to pass-by reference, eg by changing the signature of your function to this:
DeathCheck(Bunny* &in_root)
{
//...
}
This passes the Bunny by reference, meaning that it can now be reassigned to without a copy.
Related
Can somebody please explain the segfault here:
class foo
{
private:
some_class *test_;
void init_some_class(some_class*);
void use_class();
}
foo::foo()
{
//test_ = new some_class(variables, variables); //THIS WOULD WORK
}
void foo::init_some_class(some_class *tmp)
{
tmp = new some_class(variables,variables);
}
void foo::use_class()
{
test_->class_function() //THIS SEGfaults
}
I would call the funtion via init_some_class(test_); If I use new in the constructor then the test_->class_function() works fine. It only seems to segfault when I use new outside of the class constructor and try and pass the pointer through the function
When you write in init_some class() :
tmp = new some_class(variables,variables);
you are in fact storing the new pointer in the parameter that is passed by value. But this parameter is local to the function and lost as soon as the function returns.
So if you call somewhere init_some class(test_) the value of test_ is transferred to tmp, but the changed tmp remains local to the function. You therefore get a segfault beause test_ remains uninitialized.
Possible solutions:
A simple solution to the described use case could be to pass the parameter by reference:
void foo::init_some_class(some_class *& tmp) // note the &
{
tmp = new some_class(variables,variables);
}
With this definition, when calling init_some class(test_), the original test_ pointer gets modified.
Another solution could be to have the init_some_class() change directly the test_ member. You'd then no longer need a parameter.
im using my own linked list made with stuct. The struct has 2 ints and 1 pointer to another struct, next.
I'm using the LL (linked list) but in one of the functions a certain pointer won't change.
AddChain( &MakeChain(..values..), added )
this is how i call the function, i send her a new chain to link to the big one, and if there is no big one aka it's NULL so it will replace it. In this call added is a NULL ptr to a chain struct.
void AddChain(PolyChain* pol, PolyChain* main) // adds the new piece to the chain
{
PolyChain *current = main, *back = NULL;
if (main == NULL)
{
pol->next = NULL;
main = pol;
return;
}
... \\ there is continuation of the function but it wont get so far without main one
}
Now, as you can see if the main chain is a NULL I make to to reference to the same thing as the new chain I got. I'm running in the debugger and pol HAS a value and after the line:
main = pol;
main realy changes to point to what pol is pointing to. BUT after the return in AddChain, added which is the main in AddChain is still a NULL. It didn't get the value back from the function, it didn't change the pointer of added as like it was by value and not by reference, but it was by reference.
What's causing this problem?
EDIT: MakeChain returns a PolyChain and AddChain gets PolyChain*, this is why i used &.
This happens because you pass your pointer PolyChain* main by value. A simple way of visualizing "passing by value" is to think about it as "passing by copy": a copy of the pointer is made specifically for the call of AddChain. That is why any change to the pointer inside AddChain remains local to AddChain.
You could fix this problem in three different ways:
Take PolyChain*& main by reference - this is the simplest solution. because nothing else needs to change.
Take PolyChain** main by pointer - in this case AddChain needs to dererefence main, i.e. use *main instead of main, and take a pointer when passing main to AddChain
Return PolyChain* with the new value of main - in this case the caller must make an assignment of the result back to the pointer passed for main.
void AddChain(PolyChain* pol, PolyChain* main)
...
main = pol;
return;
In that code, main is a local copy of whatever pointer was passed in, so assigning to main has no effect on the pointer outside the function.
You didn't give enough information for me to deduce your intent, so it is likely (but not clear) that you could fix the problem by passing the pointer by reference:
void AddChain(PolyChain* pol, PolyChain*& main)
You are changing a copy of the pointer, since you are passing the pointer by value. If you want to change the pointer that comes from the calling scope you will have to pass a pointer to the pointer or a reference to the pointer:
void AddChain(PolyChain*& pol, PolyChain*& main) {...}
You must use pointer to pointer to modify pointer value inside the function
void AddChain(PolyChain* pol, PolyChain** main)
than in your code:
void AddChain(PolyChain* pol, PolyChain** main) // adds the new piece to the chain
{
PolyChain *current = *main, *back = NULL;
if (main == NULL)
{
pol->next = NULL;
*main = pol;
return;
}
... \\ there is continuation of the function but it wont get so far without main one
}
to pass value to the function just call
AddChain(pol, &main);
where pol and main are regular pointers to PolyChain type.
or with simple values:
PolyChain* pMain = &main;
AddChain(&pol, &pMain);
NOTE: This practics are extremaly error prone so you must be extra careful for managing pointers at this manner.
I am writing a template BST class and notice that I need to declare the "insert" parameters like this:
void BST<TYPE>::insert(TYPE iData, int line, node *&n)
instead of:
void BST<TYPE>::insert(TYPE iData, int line, node *n)
The only difference being the "&" for passing the node pointer. The full code for the function is:
template <class TYPE>
void BST<TYPE>::insert(TYPE iData, int line, node *&n){
if(n == NULL){
n = new node(iData, line, NULL, NULL, NULL);
}
else if(iData < n->data){
insert(iData, line, n->leftChild);
}
else if(iData > n->data){
insert(iData, line, n->rightChild);
}
else if(iData == n->data){
while(n->head != NULL){ //traverse to end of list
n = n->head;
}
n->head = new node(iData, line, NULL, NULL, NULL); //add p to end of list
}
}
The tree holds duplicates, which is why there is an else if(iData == n->data).
My thought was that if we pass a pointer to a child, then eventually when NULL is found, when we create a new node, it will be at the address in memory pointed to by either the leftChild or rightChild pointer. Instead, it seems that if we don't add the & operator, the new node is created but is not "connected" to the tree.
I'm wondering if someone could explain the syntax here. Also, I apologize for any breaches of ettiquette; this is my first post on SO. This BST is for a homework assignment, but the question I've asked is not. It's just something I'm curious about.
Thanks.
When you have a function parameter int& i, any changes to i inside the function, also change the variable passed to the function. When the parameter is int i, a copy is made inside the function, and any changes to the parameter do not affect the variable passed to the function.
There's no reason the same logic cannot be applied to pointer parameters. When you have node *n, a copy of the pointer is made, and if the pointer inside the function is made to point to something else, the pointer that was passed to the function from outside is not changed. When the parameter is node *&n, if the parameter is made to point to something else inside the function, the pointer variable outside the function which was passed in, is also changed to point to the same thing.
I didn't look too much at the function, but I assume the logic requires this function to update the pointer outside the function call too.
I have created an object of a certain class. The class is "Node" and it has an attribute of CString strName. The value of this variable can be retrieved with a method of Node: CString Node::GetName(), which just returns the name of the variable.
In the following method I instantiate this:
Node* UpperClass::GetObject(CString value) {
Node retObject;
retObject.strName = value;
Trace(retObject.strName); // Prints argument to trace file - this prints the value of strName fine
return &retObject;
}
Then I run this method in a second class:
Node* LowerClass::Get() {
Node *pReturn = instanceOfUpperClass.GetObject();
Trace(pReturn->GetName()); // This trace just prints blank...
return *(&pReturn);
}
As you can see by the code comments, it seems to lose the value when it is passed to the second method. I've attempted to research this but am having some real trouble getting to grips with why.. can anyone help?
As an aside, if one is wondering about the return value of the second method, I am intending to past the resultant pointer to a third function where I utilise it for processing (messy, I know, but I inherited the code and have no choice); just in case that has any bearing on the answer.
Thanks in advance!
int this method:
Node* UpperClass::GetObject(CString value) {
Node retObject;
retObject.strName = value;
Trace(retObject.strName); // Prints argument to trace file - this prints the value of strName fine
return &retObject; // <-- Undefined Baaviour
}
you are returning pointer to local object, which is destroyed once this method ends. You should create retObject dynamically, and return pointer to it, or better put this pointer into shared_ptr<>.
The Node retObject is a local variable when you go out of scope of the function GetObject any use of the object is undefined. And in this case you return a pointer to that object.
I'm currently coding on a project and I have a function that looks like this:
Room::addItem(Item*&); //not written by me
I have some trouble understanding what to send as parameter.. the "*&" mess it up for me.
I've tried the following:
foo.addItem(loadItem()); //Returns an Item-object
/*and*/
foo.addItem(loadItem()); //Returns an Item-pointer
edit: It would be nice if you explain what the "*&" means. I want to understand it next time I run in to it ;)
The addItem function accepts argument of type Item* and the pointer is passed by reference. It means that the function addItem can modify the pointer internally. This may also imply that the object is being reallocated or modified inside this function.
Example:
void pointerByValue(int* ptr)
{
ptr = new int[10];
}
void pointerByReference(int*& ptr)
{
ptr = new int[10];
}
void main()
{
int* p = NULL; //A NULL pointer
pointerByValue(p); //p is still NULL
pointerByReference(p); //memory has now been allocated to p
}
Pointer By Reference are only valid in C++.
It looks to me like your function is expecting a reference to a pointer. For example, MSDN has some sample code with similar syntax.
// Add2: Add a node to the binary tree.
// Uses reference to pointer
int Add2( BTree*& Root, char *szToAdd ) {
if ( Root == 0 ) {
...
There are various reasons why you might want to do that, but your favorite search engine should be able to help you there. One blog entry to point you in the right direction is here.
The parameter type is a reference to a pointer to an Item, and
what you need to pass to it is a pointer to an Item (i.e.
Item*), which must, in addition, be an lvalue (because presumably,
Room::addItem is going to modify the pointer).
you need to pass pointer to function
Item item = loadItem()
foo.addItem(&item);
& means that function will use reference and will be able to change it value