I am using this simple function to create a new node
node* Tree::createNewNode(int score, const char* word)
{
// Create a new node with the information available
node* n = new node;
n->left=NULL;
n->right = NULL;
n->parent = NULL;
n->score = score;
strcpy(n->word,word);
return n;
}
node is a structure:
struct node
{
int score; // the score or label of the node
char *word; // the word stored in the node
node *left; // the pointer to left child of the node
node *right; // the pointer to right child of the node
node *parent; // the pointer to parent node
};
And I am calling the createNewNode function from another function
temp = t->createNewNode(score,"");
The function runs properly for only one time and then it crashes while executing:
node* n = new node;
You need to allocate memory to the word field. You are trying to copy data into word with out allocating space for it.
change char *word to char word[100];
char *word; // this is a pointer to string, aka this is not a string
char word[100]; // this is a string
n->word is uninitialized. when you are using strcpy you are copying word content in an unknown address.
This result on unknown behavior (The first call look like it work and the second made the program crash). You need to allocate the memory space to hold word string inside the structure.
Your error is due to word not being allocated memory.
You could fix this using legacy C functionality like in the other answers, or you could actually write idomatic C++.
All of the initialization done in the createNewNode function should be done in the node constructor. You should use std::string instead of char* to avoid memory allocation failures like you currently have. You should also protect the members of your node class, instead providing mutators to attach/detach them from the tree so you don't need to do it manually.
Your program crashes in the following line,
strcpy(n->word,word);
because, n->word in struct node
char *word; // the word stored in the node
was not allocated any memory.
Use char array instead of char pointer or change the function definition like this:
node* createNewNode(int score, const char* word, int wordLen)
{ ^^^^
// Create a new node with the information available
node* n = new node;
n->left=NULL;
n->right = NULL;
n->parent = NULL;
n->score = score;
n->word = (char *) malloc(wordLen);
strcpy(n->word,word);
return n;
}
strcpy(n->word, word) copies the input string into n->word which has not been initialized. For that experession to work correcly n->word must point to an allocated buffer.
strdup function allocates that buffer for you and copies the input string into that buffer, e.g.:
n->word = strdup(word);
Related
I have a struct like these:
struct Node {
void *data;
Node *l, *r;
}
And I should use function:
void push(Queue *q, void *data, int priority) {
Node *n = new Node;
n->data = data;
// place node in queue
}
I'm trying to read strings in loop, but after that I got queue where all values in nodes are similar.
void read_input(Queue *q) {
string s;
int p;
cin >> s >> p;
// problem is here
push(q, (void *) s.c_str(), p);
}
void main() {
Queue *q = create();
for (int i = 0; i < 5; i++) {
read_input(q);
}
}
How can I fix that? Why string s always has the same address?
Like Trantor said, you using s.c_str() which is a private pointer of string s; and is valid only inside read_input function.
Every call to read_input will use this pointer that is destroyed every time you reach read_input end (out of scope).
You see the same pointer, probably because its on the stack. Its a coincidence.
To fix your issue, you need to create a copy of the characters and store them in node->data. However you will also need to think where to delete it. E.g. OnNodeDestroy event or similar.
The problem is, you are saving (temporary) pointers to the private internals of temporary objects of class std::string in your queue push call. They become invalid after leaving read_input, and may be even reused internally, so the pointer seems not to change.
Instead you should work with copies, allocate your own memory for the strings.
When you have created a string object compiler will allocate the memory from stack and all the time that string object will pointing to that particular memory location (static memory allocation in this case) only. In your structure void *data pointer will also always pointing to that same memory location. Hence the last value entered into string object will reflect in all the node in your stack. To fix this you have to dynamically allocate memory each time so that the data pointer should pointing to different memory location and you will get different value.
void read_input(Queue *q) {
//string s;
char *s = (char *)malloc(50);
int p;
cin >> s >> p;
push(q, (void *) s, p);
}
Normally, I would just input head = new Node in main, which would set everything up, but the stipulation is that I do not have permission to mess with global variables. This is an assignment where I only have access to main, and due to other backend features, I have to leave the global variables intact so I can't overwrite it with head = new Node.
The point is just to add characters to a linked list. I just hardcoded inserting one just as an example, but I still can't avoid the error.
Is there a correct way to add them?
struct Node{
char key;
Node *next;
};
Node *head = NULL;
int main(){
char x = 'a';
cout<<x<<endl;
head->key=x;
}
assignment:
Find all nodes in a BST that are between a given range of values. Then build a linked list of the values and the list should be in ascending order.
NOTE: the head of the linked list is declared globally in the back end and its initial value is NULL. Just add the nodes to the linked list using head. The printing of the linked list will also be done in the backend. Helper functions can be used.
void RangeSearch(TreeNode *node, char m, char n);
Head is just a pointer, pointing to NULL. There is no real object / memory allocated for Node. You have first to allocate memory for it.
In your assignment, you can and should (as far as i understand it) add nodes to linked list, so you will have to allocate new nodes .
struct Node {
char key;
Node *next;
};
Node *head = NULL;
int main() {
char x = 'a';
head = new Node();
cout << x << endl;
head->key = x;
delete head;
return 0;
}
I'm implementing a simple trie data structure in c++ using struct and pointers. When I pass a string to add in trie, it gives segmentation fault in the addString() function.
struct node {
char ch;
node *link[26];
node() : link(){}
};
node head;
void addString(node *n, string s) {
if (!s.length()) return;
if (!n -> link[(int)s[0] - 97]) {
node m;
m.ch = s[0];
n -> link[(int)s[0] - 97] = &m;
}
addString(n -> link[(int)s[0] - 97], s.substr(1));
}
int main(){
addString(&head, "red");
return 0;
}
I tried debug statements and even printed and matched the address values of newly created node and the one passed recursively, they were same.
PS I'm using head node as epsilon state.
You are using addresses of objects allocated on stack. node m; is on stack. It will be deleted as soon as you leave an if block in which it is declared. And you assign it's address to a node n -> link[(int)s[0] - 97] = &m; which lives longer than that.
n -> link[(int)s[0] - 97] = &m;
You're storing the address of m while it is destroyed at the end of its scope.
You should redesign your project with a proper memory management.
There are two problems that could explain segmentation fault:
the first is that you add a pointer to a local object m into your array of links. As soon as you return from the function the pointer will be dangling and you'll have UB. Allocate m properly: node *m = new node; Better: use unique_ptr instead of raw pointers.
you assume that the string contains only lower case letters between 'a' and 'z'. If the string would contain anything else, you'll go out of bounds and might cause memory corruption and UB. You should have at least an assert()
Here a small fix to address both issues, based on your current structure and approach:
struct node {
...
node(char c=0) : link(), ch(c) {}
~node() { for (int i=0;i<26; i++) delete link[i]; }
};
...
void addString(node *n, string s) {
if (!s.length()) return;
size_t c = tolower(s[0]);
if (c<'a' || c>'z') return; // char not ok-> do like end of string
if (!n -> link[c-'a']) {
n -> link[c-'a'] = new node(c);
}
addString(n -> link[c-'a'], s.substr(1));
}
Note that when you use pointers in a struct, you have to be extra-careful about the rule of 3. It will not hurt here, though, as you do'nt copy nodes yet.
Online demo
I'm trying to traverse on a binary tree to find someone's ID by using his/her ID number. When I debug this function it works well, but on the other hand, when I directly run, it terminates itself.. Can someone figure it out please?
struct person{
char ID[15];
char name[30] ;
char surname[30];
person *left;
person *right;
};
struct tree{
person *root;
void bfsSearch();
void BFS(person*,char*);
};
void tree::BFS(person *root,char *search)
//BFS traversal on a binary tree
{
char *temp;
std::deque<person *> q;
q.push_back(root);
temp=strncpy(temp,q.front()->ID,8);
while (q.size() != 0)
{
person *next = q.front();
if (strcmp(search,temp)==0)
{
cout<<"Result: "<<q.front()->ID<<endl;
break;
}
q.pop_front();
if (next->left)
q.push_back(next->sol);
if (next->right)
q.push_back(next->sag);
temp=strncpy(temp,q.front()->ID,8);
}
}
void tree::bfsSearch()
{
person *scan;
char *data,*temp;
data=new char[15];
scan=root;
cout<<"Enter the Person`s ID to search: ";cin>>data;
BFS(root,data);
}
char *temp;
temp=strncpy(temp,q.front()->ID,8);
You are copying data into an uninitialized pointer, which is undefined behavior. You need to declare temp as an array, or allocate it dynamically. Since you are only copying up to 8 bytes, using char temp[9]; should be enough. Note though that strncpy will leave the string unterminated if the input was too long, so you'd need to add temp[8]=0; to be safe.
There is also no point in assigning the result of strncpy back to temp, since it just returns its first argument.
It's much better to do things the C++ way: Use std::string and avoid all this messing around with char pointers and null-terminators.
I'm attempting to craft my own basic singly linked list in C++ as a learning exercise, and I'm encountering some difficulty in the memory management department. As it stands I have...
A 'Node' class:
class Node
{
public:
char *value;
Node *next;
Node();
~Node();
};
Node::Node()
{
}
Node::~Node()
{
delete[] value;
}
And then my list (I've omitted certain method calls for brevity):
class LinkedList
{
private:
Node *head;
public:
LinkedList();
~LinkedList();
void Add(char **x);
};
LinkedList::LinkedList()
{
head = 0;
}
LinkedList::~LinkedList()
{
Node *temp;
Node *current = head;
while(current)
{
temp = current;
current = current->next;
delete temp;
}
}
void LinkedList::Add(char **x)
{
Node *nodeToAdd = new Node();
nodeToAdd->value = *x;
nodeToAdd->next = NULL;
Node *current = head;
if(!head)
{
head = nodeToAdd;
return;
}
while(current->next)
{
current = current->next;
}
current->next = nodeToAdd;
}
I'm attempting to use this code as follows (again I've omitted things for brevity):
int main()
{
LinkedList *list = new LinkedList();
char *alpha = "alpha";
char *beta = "beta";
char *charlie = "charlie";
char *delta = "delta";
char *echo = "echo";
list->Add(&alpha);
list->Add(&beta);
list->Add(&charlie);
list->Add(&delta);
list->Add(&echo);
delete list;
}
The last call in main to delete the list produces an error:
Debug Assertion Failed! Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
What am I doing wrong here?
The data pointed to by the various Node::value aren't dynamically allocated, so you shouldn't delete them. Applying the concept of "ownership", nodes should either make their own copies of data, which they own and can delete, or nodes don't own data, so they shouldn't be responsible for deleting it.
You can also implement multiple ownership using reference counting, like Objective-C does (see Objective-C Memory Management Rules for more info) but you have to be careful to avoid ownership cycles. You often find some type of reference counting in third-party smart pointers, such as Boost's smart_ptr library. Since you're doing this for the learning experience, it may make more sense to roll your own than use a library. Of course, you could also use a library for now, letting you focus on whatever you're trying to learn.
One day a student came to Moon and said: “I understand how to make a better garbage collector. We must keep a reference count of the pointers to each cons.”
Moon patiently told the student the following story:
“One day a student came to Moon and said: ‘I understand how to make a better garbage collector...
you are trying to release the memory which is not allocated on heap.
char *alpha = "alpha"; --- not allocated on heap
calling delete[]in Node destructor would lead to heap corruption.
Some points:
1) initialize pointers properly in the constructor:
Node::Node():value(NULL),next(NULL)
{
}
2) Take a ownership of value.
Allocate the memory on heap and copy
the contents
You shouldn't release a pointer use delete[]/delete if it's not created by new operator. There are some actions under the hood for the delete[] operation, like releasing/reclaiming marked memory from a managed pool. Since your pointer doesn't belong to these stuff, there will be a problem. IMHO, the underlying delete[] code is the _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) stuff.
The problem is that you're assuming that you can delete the data inside node, but you're passing in pointers to string literals instead, which you can't delete.
If you're assuming that the Node object controls the lifetime of the data inside it, your Node constructor or the Add function in LinkedList will have to make a copy of the data that it is being passed.
In your destructor, you are trying to array delete (delete [ ]) a static string. You have change your Add function to reserve the string and copy it first. See the code below.
However, if I were you and fairly new to memory management, I'd really use something like CString instead of a raw "char *" as it's much easier to deal with.
void LinkedList::Add(const char *x)
{
Node *nodeToAdd = new Node();
int len=strlen(x);
nodeToAdd->value = new char [len+1]; // room for string + terminating 0
strcpy(nodeToAdd->value,x);
nodeToAdd->next = NULL;
Node *current = head;
if(!head)
{
head = nodeToAdd;
return;
}
while(current->next)
{
current = current->next;
}
current->next = nodeToAdd;
}
value and next in Node class doesn't have memory allocated. You should allocate memory in Node's constructor.