c++ trouble with what parameter to send - c++

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

Related

pointer problems with function calls

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.

pointer won't go back to it's reference from a function after return (stays null) C++

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.

C++ Pointer object lost outside of function?

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.

Reading new, filled array gives segfault

I've been banging my head hard over this...I create a pointer in main(), which I pass on to another function. Inside that function, the pointer is used to create a new array (using the new operator), the array is filled, and the function ends.
If I then try to access elements in the new array in the caller, I get a segfault. Since the new operator was used, I expect the new array to be on the heap and thus not cleared by it going out of scope...I really don't get this. What am I overlooking? I also don't know precisely what to google for, so no luck there yet.
I can get it to work if I let the function return the pointer (instead of passing it), but I don't want to do that because eventually I'd like my function to create a few such newly created arrays. So what am I missing here?
Here is a minimal working example:
#include <iostream>
#include <stdio.h>
bool getData(double *myData)
{
myData = new double[2];
if (!myData)
return false;
myData[0] = +4.53;
myData[1] = -3.25;
return true;
}
int main()
{
double *myData = NULL;
if (!getData(myData))
fprintf(stderr, "Could not get data.\n");
std::cout << myData[0] << std::endl;
std::cout << myData[1] << std::endl;
delete [] myData;
}
Root Cause of the Crash:
When you pass a pointer to the function by value. An copy of the pointer gets passed to the function. Further You allocate memory to the copy of pointer passed through main, this pointer is not same as the one you access in main, it is an copy. The pointer myData in main was never allocated any memory, so eventually you are dereferencing a NULL pointer which results in a Undefined Behavior and an crash.
Suggested Solution 1:
Pass the pointer by Reference:
bool getData(double *&myData)
^
And you are good to go.This is the C++ way of doing it.
Another Solution:
You could also do:
bool getData(double **myData)
^
{
*myData = new double[2];
//so on
}
while calling it as:
getData(&myData);
^
A word of caution:
new does not return NULL in case of failure to allocate memory. It throws a std::bad_alloc exception. So you need to handle that exception or in case you want to check for null you should use the nothrow version of new.
The pointer argument to getData() is passed by value, not by reference. This means you're pushing the value (== the address the pointer points to) on the stack and call getData. Inside getData you overwrite this value with the return value from new[]. This value is no longer valid after returning from the function as it only existed on the stack.
Try to pass a reference or pointer to the pointer:
bool getData(double *&myData)
{
myData = new double[2];
if (!myData)
return false;
myData[0] = +4.53;
myData[1] = -3.25;
return true;
}
You have to pass a double** as myData, to initialize correctly your array. Currently, your getData function creates an array and stores its value in the copied parameter, so myData in main is not modified. Your must pass the pointer of myData and modify it with
bool getData(double** myData)
{
*pmyData = new double[2];
...
}
and call getData in main:
getData(&myData);
The myData given as parameter to getData function is passed on stack as a copy. When modifying that value in getData function you actually modify the value from the stack.
When you return to the main function everything is as it was before (except a memory leak).
The quickest solution would be to change the getData function like this:
bool getData(double *&myData)
and you're all set.
You pass the pointer into your function by value, not reference. Try this:
bool getData(double* &myData)
{
...
}
The difference is that myData is now a reference to the pointer in main, not a copy of it that gets destroyed when the function exits.

What is the problem with this piece of C++ queue implementation?

I'm trying to write a linked queue in C++, but I'm failing so far. I've created 2 files by now: my main.cpp and box.h. When trying to use my box, I receive the following message:
Description Resource Path Location Type
conversion from ‘Box*’ to
non-scalar type ‘Box’
requested main.cpp /QueueApplication line
14 C/C++ Problem
My code is as follows:
box.h
#ifndef BOX_H_
#define BOX_H_
template<class T>
class Box
{
public:
Box(T value)
{
this->value = value;
this->nextBox = NULL;
}
T getValue()
{
return this->value;
}
void setNext(Box<T> next)
{
this->nextBox = next;
}
private:
T value;
Box<T> nextBox;
};
#endif /* BOX_H_ */
main.cpp
#include<iostream>
#include "box.h"
using namespace std;
int main(int argc, char** argv)
{
Box<int> newBox = new Box<int>();
cout << "lol";
cin.get();
cin.ignore();
return 0;
}
Could you guys help me?
PS: before someone ask me why not to use stl ... I'm in a data structures class.
Removing unimportant stuff, we see you've declared a new class like this:
template<class T>
class Box
{
T value;
Box<T> nextBox;
};
How big is Box<T>?
Clearly
sizeof Box<T> >= sizeof(Box<T>::value) + sizeof(Box<T>::nextBox)
sizeof Box<T> >= sizeof(T) + sizeof(Box<T>)
0 >= sizeof (T)
uh-oh
The problem is with this line
Box<int> newBox = new Box<int>();
The new operator returns a pointer to a Box object created on the heap. The pointer will be of type Box<int>*. The left side of that expression declares a Box object. You can't directly assign a pointer-to-X to an X. You should probably just omit the new keyword unless you have a reason to want to manage the storage lifetime of the object manually. Incidentally, I'm betting you come from Java, where new is always required to create objects. Not so in C++.
Also I think it's awesome that your data structures class is introducing you to templates right off the bat.
I believe your nextBox should be a pointer.
Box<T> * nextBox;
Method setNext should deal with pointers too.
void setNext(Box<T> * next)
And newBox should be a pointer.
Box<int> * newBox = new Box<int>();
Since you come from a Java background, you are assuming that all of your objects are references. Syntax is a little different in C++.
There are multiple problems here.
First of all, in order to implement a linked list (or a queue that uses a linked list) in C++ you need to use pointers. In Java everything is a reference. C++, on the other hand, makes a clear distinction between objects and pointers to objects. (There are also references to objects, but they are irrelevant here).
Let's also forget the templates for a moment, because they are not part of the problem here.
class Box
{
int value;
Box nextBox; // wrong! should be a pointer
};
is wrong, because nextBox must be a pointer to the next element of the list/queue. The correct
way would be Box *nextBox;
By the same token setNext() should also take a pointer to Box as its argument. setNext(Box b) is an example of pass-by-value, i. e. this member function (method in Java lingo) gets its own copy of the entire Box object. This could lead to performance issues if the object is large, not to mention that any changes done to it by the function will be invisible to the caller. What you want instead here is pass-by-reference, which is accomplished by using a pointer.
The final point is that new in C++ always returns a pointer. You should have Box<int> *newBox = new Box<int>;
When you use new, you get a pointer to an object, not a plain object. Declare your variable as a pointer or just allocate your object on the stack instead.
I hope this makes sense to you, since if it doesn't, you should probably go back and read more about the basics of OOP in C++.
Guys. No raw pointers in C++ unless you really need them. Please. Especially for some poor soul who doesn't even know that operator new returns a pointer. Get a std::auto_ptr or a std::shared_ptr.