I'm very confused about the following code:
class Tree {
protected:
struct Node {
Node* leftSibling;
Node* rightSibling;
int value;
};
private:
Node* root;
int value;
.....
public:
void addElement(int number) {
if (root == NULL) {
printf("This is the value of the pointer %lld\n",(long long)root);
printf("This is the value of the int %d\n",value);
...
return;
}
printf("NOT NULL\n");
}
};
int main() {
Tree curTree;
srand(time(0));
for(int i = 0;i < 40; ++i) {
curTree.addElement(rand() % 1000);
}
}
The curTree variable is local to the main function so I expected it to not have its members initialized to 0, but they are both initialized.
No, it has unspecified contents. Those contents might be random memory garbage, or they could just happen to be 0, depending on whatever data was left in their memory location beforehand.
It might just happen that due to the way the code was compiled, the particular stack location containing root always has 0 (say, because an earlier local variable occupying that same stack location always ended up as 0). But you cannot rely on this behavior -- you must properly initialize anything before reading it back, otherwise you enter the land of Undefined Behavior.
The actual default value a pointer is implicitly initialized to will depend on the compiler you use.
The Visual C compiler (v2012) will initialize it automatically to __nullptr which is equal to NULL. Have a look at the MSDN doc (see the last example).
I would try to check your compiler manual if you want more information.
You don't initialize root anywhere, proper place to initialize it would be the constructor.
Related
Trying to implement the add function in dynamic list, recursively.
The code is self-explanatory:
struct list {
int value;
list* next = NULL; // is this valid?
};
list head;
void add(list* cur, int value) {
if (cur->next) {
add(cur->next, value);
return;
}
cur->next = (list*)(malloc(sizeof(list)));
cur->next->value = value;
cur->next->next = NULL; // withouth this line, the program errors out after two calls to the function add
}
int main() {
for (int i = 0; i < 50; i++)
add(&head, i);
}
After seeing the debugger, I realized that calling malloc wasn't initiating "next" with NULL as specified in the defininition of the list struct.
As noted in comments, malloc does not initialize anything. It simply grabs a chunk of memory big enough for a list struct. Now, that might mean that struct has next set to NULL, or it might not.
That is why you're having to explicitly initialize it to NULL as that prevents undefined behavior when accessing that member.
If you use new to handle dynamic memory allocation, then the next member is initialized to NULL.
cur->next = new list;
Including this use of malloc, your code is very C-ish, and there are numerous improvements C++ will allow you to make.
in Class.h
Struct Node
{
int ID;
int position;
}
In class Class.cpp I am initializing vector of structs which leads to core dump error
Class::Class(const branch& branches):mybranches(branches)
{
for (const auto & branch:mybranches)
{
Node* node
node->ID= branch->ID
node->position= branch->position
mynodesvector.push_back(std::move(node));
}
}
However initializing it like this leads to no error
Class::Class(const branch& branches):mybranches(branches)
{
for (const auto & branch:mybranches)
{
Node node
node.ID= branch->ID
node.position= branch->position
mynodesvector.push_back(&node);
}
}
I want to know what is the reason for the core dump error with initializing it as pointer to struct.
You do not create/allocate an object to which node* shall point; so dereferencing node leads to undefined behaviour;
Node* node;
node->ID= branch->ID; // UB here...
However, allocating an object like
Node* node = new Node();
node->ID= branch->ID;
...
should work.
In your second example, you define a Node-object (and not just a pointer to it). So at least accessing its members is save.
Node node; // defines a Node-object.
node.ID= branch->ID; //save
node.position= branch->position; // save
Note, however, that you push_back a pointer to an object with block scope; when you dereference this pointer later, the actual object will be out of scope and you get undefined behaviour then.
mynodesvector.push_back(&node);
I'd suggest to have a look at std::shared_ptr<Node>.
In addition to the answer of #Stefan Lechner:
The version which throws no direct error has a bug which is likely to blow up whenever you try to modify the values in the mynodesvector:
you initialize a struct on the stack and then push its address into a vector. Once an iteration of the for loop has terminated, the Node instance is destructed, but you still have the pointer to it in the vector.
for (const auto & branch:mybranches)
{
{
Node node
node.ID= branch->ID
node.position= branch->position
mynodesvector.push_back(&node);
}
// here, Node is dead, but the pointer to it lives on.
}
In order to find bugs like that that escape your code control I recommend enabling compiler warnings and using appropriate sanitizers.
I am new to C++. I expected two pointers that don't point to anything to be detected as null pointers. However this works only with one of them. The physical addresses of those pointers are somewhat different - 0xe00000001 vs 0x0 (this one is properly detected as null pointer).
I've written the following snippet of code:
#include <iostream>
using namespace std;
struct TNode {
TNode* Parent; // Pointer to the parent node
TNode* Left; // Pointer to the left child node
TNode* Right; // Pointer to the right child node
int Key; // Some data
};
int main() {
TNode parent;
parent.Key = 2;
TNode first;
first.Key = 1;
first.Parent = &parent;
parent.Left = &first;
cout << first.Left << endl; // get 0xe00000001 here
cout << first.Right <<endl; // get 0x0
if (first.Right == nullptr) {
cout <<"rnull"<<endl; // rnull
}
if (first.Left == nullptr) {
cout <<"lnull"<<endl; // nothing
}
return 0;
}
What is going on here? Basically, I want to find a way to check whether first.Left points to nothing.
In your example, first.Left and first.Right are uninitialized, not null. This means that they basically contain whatever garbage was on the stack at the time they were allocated. Accessing the actual value (by printing the pointer, for example) is actually undefined behavior, but with most compilers on low optimization settings it'll just print that garbage.
Solution 1: give default values to member variables
If you want them to be null, you can modify TNode so that their initial value is guaranteed to be null:
struct TNode {
TNode* Parent = nullptr;
TNode* Left = nullptr;
TNode* Right = nullptr;
int Key = 0;
};
int main() {
TNode n; //Everything initialized to null or 0
}
This will guarantee that they're null.
Solution 2: Define TNode() to initialize members
Alternatively, you could also explicitly define the constructor so that it makes everything null
struct TNode {
TNode* Parent, Left, Right;
// Everything gets default-initialized to null
TNode() : Parent(), Left(), Right() {}
};
int main() {
Tnode n; // Everything initialized to nullptr or 0
}
Solution 3: default-initialize at the point of use
Even if you don't explicitly define a constructor, everything gets initialized to 0 (or null, if it's a pointer) when you explicitly initialize it by putting {} when declaring the variable.
struct TNode {
TNode* Parent, Left, Right;
int Key;
};
int main() {
TNode iAmUninitialized; // This one is uninitialized
Tnode iAmInitialized{}; //This one has all it's members initialized to 0
}
First of all, in C and C++ there is no such thing as a pointer that points to nothing. Regardless of the value in the pointer, it points at something. Even NULL is a pointer to address "0" but we use that, by convention to represent a NULL. The problem with a pointer that is uninitialized is that it can point to anything and that anything is likely an illegal address which will cause an exception or it points to something else in the application and, if the data is modified, will cause an undesired side-effect.
In your case the 2nd pointer is 0x00 and that is NULL. The 1st pointer, however, is 0x01, and that is NOT NULL.
I started C++ a few hours ago and have been trying to do a simple LinkedList implementation in it to get myself familiar with it, however, I'm stumped as to why this method hasNext() keeps returning true.
#include <iostream>
#include <string>
using namespace std;
struct LinkedNode {
public:
int data;
LinkedNode(int d = 0) {
data = d;
}
void setNext(LinkedNode * linked_node) {
next = linked_node;
}
LinkedNode * getNext() {
return next;
}
bool hasNext() {
return (next != nullptr);
}
private:
LinkedNode * next;
};
int main() {
LinkedNode * linked_list = new LinkedNode(2);
(*linked_list).setNext(new LinkedNode(10));
if (linked_list->getNext()->hasNext()) {
cout << "true";
}
else {
cout << "false";
}
}
This outputs "true", but when I try to access the data since it is supposedly "true" I get the Segmentation fault error, (going to guess it's being raised since I'm trying to get a value that doesn't exist), from linked_list->getNext()->getNext()->data; Can somebody explain why?
The constructor of LinkedNode does not initialise the next member.
That means it is uninitialised. It is not set to zero by default. In fact, accessing its value (before initialising it, or assigning a value to it) gives undefined behaviour.
Set next to be nullptr within the constructor.
You are not initializing next. By default allocating memory just changes a data structure storing information about what memory block is allocated. It does not change the content of this memory block. So you can consider the next pointer be of random data. And since random data is different than null pointer hasNext returns true but when you access the data it is very likely that the random data is interpreted as a pointer into some memory that either does not exist or your application does not has the right to access too. Therefore the result in segmentation / page fault.
To verify this truth just do not initialize data as well, create some nodes and read the data (or even the next pointer). This way you see the randomness which is basically just left overs of content the memory block once hold before it was freed.
PS: Memory blocks are freed and dynamically spliced and combined based on algorithms you can learn. Check out malloc and some other implementations and see the Wikipedia about memory allocation.
You must initialize the value of next to nullptr. By default, the value is undefined (garbage).
Check out member initializer lists:
LinkedNode(int d = 0)
: data( d )
, next( nullptr )
{
}
Or simply assign the values directly in the constructor body:
LinkedNode(int d = 0)
{
data = d;
next = nullptr;
}
When I push a pointer of struct into a std::queue, and then poping the value, the value that I'm getting back would change to zero. I've simplified the actual code to illustrate the problem below. The head pointer in the real code is a class variable and contains other values. If I push head onto the queue, all other values that I get also become uninitialized.
What could be the issue here?
Note: PipePixel *head; is an instance variable declared in the class header file.
Add Head Function:
void LinkedGraph::addHeadPixel(int index) {
PipePixel pixel = {NULL, 433, std::vector<PipePixel*>()};
pixel.index = index;
if (head==NULL) {
pixelMap[index] = &pixel;
head = &pixel;
} else {
printf("Already added head pixel! Px:%d\n", pixelMap[index]->index);
}
}
Print Function: <-- Where problem occurs
std::queue<PipePixel*> printQueue;
printQueue.push(head);
printf("headIndex:%d\n", head->index); // headIndex:433
while (!printQueue.empty()) {
PipePixel *child = printQueue.front();
printf("childIndex:%d\n", child->index); //childIndex:0
printQueue.pop();
if (child == NULL) {
printf("child is null"); // no output
continue;
}
}
PipePixel Struct:
struct PipePixel {
PipePixel *parent;
int index; //pixel index
std::vector<PipePixel*> children;
};
The problem here is that the variable pixel is local inside the LinkedGraph::addHeadPixel function. Once the function returns that object is destructed and the variable ceases to exist. If you have stored a pointer to a local variable, that pointer no longer points to a valid object, and dereferencing the pointer leads to undefined behavior.
My recommendation is to not use pointers at all, but let the compiler handle he object copying. For such small and simple objects its possible performance impact is negligible.