I have started learning c++ (coming from java background) and barely reached pointers and got stuck. When I debug this program it says, program received segmentation fault (SIGSEGV signal) at line
*previous = head;
in the following code.
#include <iostream>
using namespace std;
struct Node
{
int data;
Node *link;
};
int main()
{
cout << "Starting main program \n";
Node head;
head.data = 0;
head.link = NULL;
cout << "After declaring head and initializing values \n";
//Declaring a pointer variable which points to an entity of type struct.
Node *previous;
*previous=head;
cout << "After declaring previous pointer \n";
bool done = false;
int i = 1;
cout << "First while loop\n";
while(!done)
{
cout << i << ": Iteration";
Node temp;
temp.data=i;
temp.link=NULL;
if(i > 2)
{
done = true;
continue;
}
*previous->link=temp;
++i;
*previous = temp;
}
done = false;
cout << "Declaring temp pointer before printing \n";
Node *temp;
*temp = head;
cout << "Second while loop\n";
while (!done)
{
cout << i << ": Iteration";
if(temp == NULL)
{
done = true;
continue;
}
cout << temp->data << "->";
*temp = *temp->link;
}
cout << "NULL";
}
Why is the pointer initialization incorrect ?
First problem:
Node *previous;
*previous=head;
First line declares that previous will hold the address of a Node. It is not initialized, so whatever value happens to be on the stack will be picked up as the bit pattern it holds.
Unfortunately, the 2nd line then dereferences the pointer (which points to garbage) and attempts to copy head into random memory (hence your crash).
In this case you probably want previous to point to head, which is taking head's address and assigning it:
Node* previous = &head; // initialize at the point of declaration
However, you must also be very wary of pointers to variables declared on the stack, because the addresses will soon become invalid when the function returns or the scope exits.
(Usually data structures with pointers are using values allocated on the heap, so the objects outlive the function that declares them.)
Which brings us to the second problem:
while(!done)
{
cout << i << ": Iteration";
Node temp;
Already there's a problem. temp is declared inside the loop on the stack. Each loop iteration, the variable will automatically be destroyed. Therefore it cannot participate in your linked list without corrupting it.
You want your list nodes to be created with new, and when you update previous's next pointer, you want to assign an address TO it, not copy an object THROUGH it.
Something like this:
while(!done)
{
cout << i << ": Iteration";
Node * temp = new Node();
temp->data = i;
temp->link = nullptr; // better than NULL
if(i > 2)
{
break;
}
previous->link = temp;
++i;
previous = temp;
}
The head object should probably also be heap allocated. Of course, now you have to deal with cleaning up the memory by calling delete on all the nodes.
There were some bugs in the code but major ones were :-
you were not allocating memory for the new nodes that you were adding during runtime
you were creating instances of structure but instead you were required to create an pointer pointing to the structure ( instances will be created during runtime ( using new operator )
I have added the comments to the code explaining what exactly are the changes that I have done.
Here is the fix :-
#include <iostream>
using namespace std;
struct Node
{
int data;
Node *link;
};
int main()
{
cout << "Starting main program \n";
// Allocating memory for the new instance of Node and making "head" pointing to it
Node *head = new Node;
head->data = 0;
head->link = NULL;
cout << "After declaring head and initializing values \n";
//Declaring a pointer variable which points to an entity of type struct.
Node *previous;
// As head and previous both are pointers thus can be assigned as it is
previous = head;
cout << "After declaring previous pointer \n";
bool done = false;
int i = 1;
cout << "First while loop\n";
while(!done)
{
cout << i << ": Iteration";
// Allocating memory for the new instance of Node and making temp pointing to it
Node *temp = new Node;
// As temp is a pointer thus using member access ("- >") operator to access the members
temp->data=i;
temp->link=NULL;
if(i > 2)
{
done = true;
continue;
}
previous->link = temp;
++i;
previous = temp;
}
done = false;
cout << "Declaring temp pointer before printing \n";
Node *temp;
temp = head;
cout << "Second while loop\n";
while (!done)
{
cout << i << ": Iteration";
if(temp == NULL)
{
done = true;
continue;
}
cout << temp->data << "->";
temp = temp->link;
}
cout << "NULL";
}
Related
I'm implementing a stack using GList (doubly) but when I assign my stack with the last element using g_list_last(*stack*) the program doesn't print my stack at all
Pointing to the first element using g_list_first(*stack*) works and I can traverse with stack->next pointer
Here's my test program:
#include <iostream>
#include <cstdlib>
#include <glib.h>
using namespace std;
int main()
{
cout << "Enter the no of random data to push: ";
int number = 0;
cin >> number;
GList *stack = nullptr;
for (int i = 0; i < number; i++) {
int data = random() % 10;
stack = g_list_append(stack, GINT_TO_POINTER(data));
cout << "Push: " << data << endl;
}
cout << "Printing the stack forward:\n";
stack = g_list_first(stack);
while (stack != nullptr) {
cout << GPOINTER_TO_INT(stack->data);
cout << "->";
stack = stack->next;
}
cout << "nullptr" << endl;
cout << "Printing the stack backward:\n";
stack = g_list_last(stack);
while (stack != NULL) {
cout << GPOINTER_TO_INT(stack->data);
cout << "->";
stack = stack->prev;
}
cout << "nullptr" << endl;
return 0;
}
Do I have to manually assign the prev link while appending?
First of all, I would not recommend using GLib in a C++ code base; GLib is a C library, full of idiomatic C code and functionality. I'd suggest using the C++ standard library, instead.
GList is a doubly linked list where each element is composed by three pointers:
typedef struct _GList GList;
struct _GList
{
void *data; // untyped pointer data
GList *prev; // pointer to the previous element in the list
GList *next; // pointer to the next element in the list
}
For convenience, all the GList functions accept a NULL as a valid list; in the case of g_list_append(), passing a NULL list as the first argument means that it will allocate a new GList element for the data you're passing and place it at the start of the list.
In your code you're taking the head of the list after populating it, and calling g_list_first(), which is a no-op on the head of the list; then you proceed to consume it by iterating over it, until you hit the end of the list, where you assign nullptr to the stack variable. Since nullptr/NULL is a valid empty GList, you're now calling g_list_last() on a valid, but empty list, which will return NULL, and thus prevent you from iterating backwards. Additionally, you're now leaking the memory allocated to the list.
The solution is to never iterate a GList with the same variable that holds the head of the list:
cout << "Printing the stack forward:\n";
GList *iter = g_list_first(stack);
while (iter != nullptr) {
cout << GPOINTER_TO_INT(iter->data);
cout << "->";
iter = iter->next;
}
cout << "nullptr" << endl;
The code above will consume the iter variable, instead of the stack. Which means that the code below:
cout << "Printing the stack backward:\n";
iter = g_list_last(stack);
while (iter != NULL) {
cout << GPOINTER_TO_INT(iter->data);
cout << "->";
iter = iter->prev;
}
cout << "nullptr" << endl;
will work appropriately, and walk the stack backwards, as the stack variable still points to the head of the list, and you're now consuming a temporary iterator.
Remember to call g_list_free() on the list to release any resources allocated for it—and g_list_free_full() in case you're allocating the contents of the data pointer as well.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I'm working on creating a doubly linked list. I seem to be having issues with the pushBack function (supposed to add a node to the end of the list). Somehow it just replaces the first node and points to itself as both the previous and next node. When I go to print the list, it just goes on forever because the next node isn't NULL (because as I said, it's pointing to itself for some reason). Posted below is the entire program. I think I might be having an issue with scope or possible am using the pointers incorrectly.
#include <iostream>
class Node {
public:
Node();
Node(int *val, Node *nx = NULL, Node *prev = NULL) {
value = val; next = nx; previous = prev;
}
void setPrev(Node* prev) { previous = prev; }
void setNext(Node* nx) { next = nx; }
void setVal(int* x) { value = x; }
Node* getPrev() { return previous; }
Node* getNext() { return next; }
int* getVal() { return value; }
private:
int* value;
Node *next;
Node *previous;
};
class LinkedList {
public:
LinkedList() : front(NULL), back(NULL) {}
bool empty() { return front == NULL; }
void pushBack(Node *nd) {
if (back == NULL) {
front = nd;
back = nd;
}
else {
back->setNext(nd);
nd->setPrev(back);
back = nd;
}
std::cout << "Front: " << *front->getVal() << std::endl;
std::cout << "Back: " << *back->getVal() << std::endl;
}
Node* topFront() { return front; }
void printFront() {
int *x = front->getVal();
std::cout << *x << std::endl;
}
void print() {
if (empty()) {
std::cout << "List is empty" << std::endl;
}
else {
std::cout << "Print list" << std::endl;
Node *x = front;
int count = 1;
// First just print the first element, then the rest
int *y = front->getVal();
std::cout << count << ": ";
std::cout << *y << std::endl;
x = x->getNext();
while (x != NULL) {
std::cout << count << ": ";
int *z = x->getVal(); std::cout << *z << std::endl;
x = x->getNext();
}
}
}
private:
Node* front;
Node* back;
};
int main() {
LinkedList ll;
char input;
char const *menu = {"Options:\n\n" \
"0. Quit\n" \
"1. Print linked-list\n" \
"2. pushBack -- add to the end of the LinkedList\n"};
while (input != '0') {
std::cout << menu << std::endl;
std::cout << ":";
std::cin >> input;
if (input == '1') {
ll.print();
}
else if (input == '2') {
std::cout << "Value: ";
static int init;
std::cin >> init;
static Node x(&init);
ll.pushBack(&x);
}
}
return 0;
}
Below is the input that I used. I printed some values to try to debug the program. You'll notice, I just tried putting the nodes with values 1, 2, 3 and 4 into the list
Options:
0. Quit
1. Print linked-list
2. pushBack -- add to the end of the LinkedList
:2
Value: 1
Front: 1
Back: 1
Node Prev: 0
Node Next: 0
Options:
0. Quit
1. Print linked-list
2. pushBack -- add to the end of the LinkedList
:2
Value: 2
Front: 2
Back: 2
Node Prev: 0x602300
Node Next: 0x602300
Options:
0. Quit
1. Print linked-list
2. pushBack -- add to the end of the LinkedList
:2
Value: 3
Front: 3
Back: 3
Node Prev: 0x602300
Node Next: 0x602300
Options:
0. Quit
1. Print linked-list
2. pushBack -- add to the end of the LinkedList
:2
Value: 4
Front: 4
Back: 4
Node Prev: 0x602300
Node Next: 0x602300
Options:
0. Quit
1. Print linked-list
2. pushBack -- add to the end of the LinkedList
:0
There are lots of good tips here, but none so far will solve the fundamental problem: you need to allocate the Node instances on the heap instead of the stack.
To make this easier, I'm going to suggest you store the ints by value instead of a pointer. Change all the places you use int* to just plain 'int'.
Then change the code to push a node on the back to this:
else if (input == '2') {
std::cout << "Value: ";
int init;
std::cin >> init;
Node *x = new Node(init);
ll.pushBack(x);
}
I've tested this with your code and it worked for me.
When you do something like this:
else if (input == '2') {
std::cout << "Value: ";
int init;
std::cin >> init;
Node x(init);
ll.pushBack(&x);
}
You're allocating a Node on the stack, which means as soon as you exit the "else" block the Node 'x' is destroyed and the pointer you added to your list is no longer valid. You need to allocate Node on the heap with the new operator. That will keep the Node alive and in memory until you delete it later.
Speaking of delete -- once you get this part working, you'll want to write a destructor that iterates over all the nodes in your list and deletes them. But for now, I'd focus on getting your other operations correct.
As you are using a static variable in below code all your node will have first value you entered.
static int init;
std::cin >> init;
static Node x(&init);
Correct it like below and try again
int *init = new int;
std::cin >> *init;
Node *x = New Node(init);
Your pushBack method look good for me. Just make above change and try.
Question: I keep receiving exc_bad_access (process code 11) error. Is this due to a bad algorithm or simply a coding error? Can anyone help me fix it?
My class assignment is to create a binary search tree whose nodes can store a name, a balance, and a key. Nodes are to be organized and searched for using the key. This tree should support insertion, inorder traversal, and searching based on a key (I haven't built this function yet). I've also included several other functions to facilitate building these. If it matters, I'm using CLion on OSX High Sierra. Additionally, I get the error on the first prompt to enter node information, the error does not seem to be related to the input itself.
//Genghis Khan
#include <iostream>
#include <vector>
using namespace std;
class node
{
public:
int key;
string name;
double balance;
node *leftptr;
node *rightptr;
friend class tree;
};
class tree
{
public:
node *root, *temp, *v;
//Constructor
tree()
{
root = NULL;
temp = root;
}
bool empty()
{
return(root == NULL);
}
bool isleaf(node *x)
{
return((x->leftptr == NULL) && (x->rightptr == NULL));
}
void inorder(node *temp)
{
if(~isleaf(temp))
{
inorder(temp->leftptr);
cout << "Name: " << temp->name << " " << "Balance: " <<
temp->balance << " " << "Key: " << temp->key;
inorder(temp->rightptr);
}
}
node* createnode()
{
v = new node;
cout << "Enter name (string): " << endl;
getline(cin, v->name);
cout << "Enter key (integer): " << endl;
cin >> v->key;
cout << "Enter balance (double): " << endl;
cin >> v->balance;
return(v);
}
void set()
{
temp = root;
}
void insert(node *v)
{
while(~isleaf(temp))
{
if((v->key < temp->key))
{
temp = temp->leftptr;
insert(v);
}
else if(v->key > temp->key)
{
temp = temp->rightptr;
insert(v);
}
}
temp->key = v->key;
temp->balance = v->balance;
temp->name = v->name;
}
};
int main()
{
int n;
cout << "Enter number of people: ";
cin >> n;
//Creating instance of tree, inserting all data into tree
tree b;
for(int i = 0; i < n; i++)
{
b.set();
node *a = b.createnode();
b.insert(a);
}
//inorder part
b.set();
b.inorder(b.temp);
}
The functions are (pseudocode):
1. function isleaf(x): return(x's left pointer and x's right pointer are both NULL)
2. function set(): set temp to root //temp will be reset every time an insertion, traversal, or search occurs
3. function createnode():
v is a new node
get all the fields for v
return v
4. function insert(v)
while(not isleaf(temp)):
-if(v's key < temp's key)
temp = temp's left pointer (to the lower value child node)
insert(node *v)
-if(v's key > temp's key)
temp = temp's right pointer (to the higher value child node)
insert(node *v)
end while
duplicate v's data to temp, now that temp is a leaf
5. function inorder(temp):
if(not isleaf(temp):
inorder(temp's left pointer)
output all info in temp node
inorder(temp's right pointer)
Main Algorithm
for the number of nodes to be entered:
1. set
2. node *a = createnode
3. insert(a)
Update
The error seems to be coming from the 'if((v->key < temp->key))' line.
EXC_BAD_ACCESS just means that you are trying to access an invalid memory. By a quick brief, your function isleaf doesn't check whether x is null.
May have other errors, you can debug and find it by yourself.
I have a problem with the following linked list code, but i'm not sure what it is. Could someone point me in the right direction? I'm using this code in some larger code where i update records, but it never reaches the "creating new record" section. It is as if the main code is updating the head pointer instead thus always resulting in a favourable comparison.
Thanks in advance. I've been racking my brains out trying to figure out what the problem is.
struct l_list *find_name(const char *name)
{
struct l_list *tmp=0;
if(records==0) { // First record
head=new l_list;
head->name=name;
head->next=0;
tail=head;
records++;
return head;
}
else {
tmp=head;
while(tmp!=0)
{
if(!std::strcmp(tmp->name,name))
{
cout << "Returning existing record with value: " << tmp->number << " name:" << tmp->name << endl;
return tmp;
}
tmp=tmp->next;
}
// No first and no existing records
cout << "Creating new record" << endl;
tail->next=new l_list;
tail=tail->next;
tail->name=name;
tail->next=0;
records++;
return tail;
}
I'm calling this from main with:
struct records *tmp=find_name("Max");
then :
tmp=find_name("Eva");
Once i get the struct i update it like so:
tmp->number=1;
Or even updating the name:
tmp->name="Peter";
So by passing a string to the function it will either create a new record and return it or give an existing record and return that. Problems might not be apparent in the output, but when you put it in a for(;;) loop in main it will
mess up.
The struct is as follows:
struct records {
const char *name;
struct records *next;
}
The relevant program code is:
struct record {
const char *name;
struct record *next;
};
struct record *head;
struct record *tail;
struct record *find_name(const char *name)
{
struct record *tmp=0;
if(record_count==0) { // First record
cout << "Creating first record" << endl;
head=new record;
head->name=name;
head->next=0;
tail=head;
record_count++;
return head;
} else {
tmp=head;
while(tmp!=0) {
if(!std::strcmp(tmp->name,name)) {
cout << "Returning existing record with value: " << "name: " << name << "tmp->name: " << tmp->name << endl;
return tmp;}
tmp=tmp->next;
}
// No first and no existing records
cout << "Creating new record" << endl;
tail->next=new record;
tail=tail->next;
tail->name=name;
tail->next=0;
record_count++;
return tail;
}
}
int main(int argc, const char *argv[])
{
struct record *tmp=0;
if(something is true) {
//Return or create a new user
tmp=find_name("Peter");
} else {
tmp=find_name("Unknown"); // Hold 1 unknown person in database
}
}
I know it's not compilable as-is but i had to extract it from a larger part.
Since you have not told us what the records structure is, there is no way for anyone to give a correct answer. You have made it even more impossible by not giving an example of code that will cause your function to behave incorrectly.
If the name element is a char * pointer then you could easily get this behaviour. For example:
The calling code puts a name into a buffer, and calls find_name.
find_name stores the address of the buffer into the name element of a records object. name therefore points to whatever the buffer happens to contain, now and in the future.
The calling code puts a new name into the same buffer. This automatically means that the name element now points to that new name, since it is pointing to the buffer.
The calling code calls find_name again.
find_name compares the contents of the buffer to the string pointed to by the name element of the first records object. Since the name element contains the address of the buffer passed by the caller (from step 2), this means that it is comparing the buffer to itself. So the result is always "equal".
But it may be that name is not a pointer at all, in which case this entire answer is irrelevant.
First of all do not use the following code formatting
if(record_count==0) { // First record
cout << "Creating first record" << endl;
//...
} else {
tmp=head;
//...
It is difficult to read such a code. It is just a bad style of programming.
The function itself can look the following way
struct l_list * find_name( const char *name )
{
struct l_list *tmp = head;
wjile ( tmp != nullptr && std::strcmp( tmp->name, name ) != 0 ) tmp = tmp->next;
if ( tmp == nullptr )
{
cout << "Creating new record" << endl;
tmp = new l_list;
tmp->name = name;
tmp->next = nullptr;
if ( tail == nullptr )
{
head = tail = tmp;
}
else
{
tail = tail->next = tmp;
}
records++;
}
return tmp;
}
Take into account that the nodes can contain pointers to strings either with the static storage duration as for example string literals or allocated in the heap.
I'm writing a code to index the skills available to a user in a game, constructed as a linked list. I've throughly tested the function that populates the list and it seems to be working correctly (so the head pointer for the list shouldn't be null). When I attempt to traverse the list to set values in the skill, before any of the code which writes to memory within the list gets to execute the program is crashing when I initialise the temp pointer within the search function of the list to the head pointer.
What makes this additionally weird to me is that it worked fine (and I had tested this fairly thuroughly) until I added in a list to store a list of available items, and may just be missing an odd interaction between the two when I populate them.
The specific error is that the pointer is supposedly accessing memory index 0x000000c to write to, but I don't see how the code at that point is dealing with a null pointer at all (since after 10 runs of the program the OS shouldn't be allocating that block of memory to the temp pointer every time and nothing else should be null.
I'm probably just ramblind at this point so here's the code:
The function that causes the error according to the debugger:
void Mechanics::setSkillValue(int index, int value)
{
Skill *temp = FirstSkill; // << The error is happening on this line //
while((temp != NULL)&&(temp->index != index))
{
temp = temp->next;
}
if (temp == NULL)
{
cout << "%";
}
else temp->setValue(value);
// cout << temp->returnValue(); //This was a test check, not needed for anything
}
The Function that's supposed to populate the skill and item lists.
void Mechanics::Populate()
{
ifstream skillstream("Skills.txt");
if(skillstream.is_open())
{
while(skillstream.good())
{
Skill *newskill;
int indexval;
string skillindex;
string skillname;
string skilldescription;
cout << "TP4" << endl; //TEST POINT
getline(skillstream, skillindex);
cout << skillindex;
getline(skillstream, skillname);
cout << skillname;
getline(skillstream, skilldescription);
cout << skilldescription; cout << endl;
indexval = atoi(skillindex.c_str());
newskill = new Skill(skillname, skilldescription,indexval);
//cout << "TP5" << endl; //TEST POINT
if(newskill == NULL) cout << "NULL!!!";
addSkill(newskill);
}
}
ifstream itemstream("Items.txt");
if(itemstream.is_open())
{
while(itemstream.good())
{
Item *newitem;
int indexval;
string skillindex;
string skillname;
string skilldescription;
string abilitydescription;
string valueSTR;
string typeSTR;
int value;
int type;
int numeric[5];
// cout << "TP4" << endl; //TEST POINT
getline(itemstream, skillindex);
// cout << skillindex;
getline(itemstream, skillname);
// cout << skillname;
getline(itemstream, skilldescription);
// cout << skilldescription;
getline(itemstream, abilitydescription);
getline(itemstream, valueSTR);
value = atoi(valueSTR.c_str());
getline(itemstream,typeSTR);
type = atoi(typeSTR.c_str());
for (int i=0; i < 5; i++)
{
string numericSTR;
getline(itemstream,numericSTR);
numeric[i]=atoi(numericSTR.c_str());
}
indexval = atoi(skillindex.c_str());
newitem = new Item(indexval, skilldescription, skillname, abilitydescription, value, type, numeric);
//cout << "TP5" << endl; //TEST POINT
// if(newskill == NULL) cout << "NULL!!!";
addItem(newitem);
}
}
The function that's supposed to actually add a skill to the skill list:
void Mechanics::addSkill(Skill *nskill)
{
Skill *temp = FirstSkill;
if(FirstSkill == NULL)
{
FirstSkill = nskill;
//cout << "TP1" << endl; //TEST POINT
//FirstSkill->printname();
}
else
{
while((temp->next != NULL))
{
temp = temp-> next;
//cout << "TP2" << endl; //TEST POINT
//temp->printname(); cout << endl;
}
if (FirstSkill != NULL)
{
temp->next = nskill;
nskill->next = NULL;
}
}
}
The code that I have is somewhat extensive so I'm only going to include the blocks which are potentially interacting with the function that's throwing up the error.
Thanks in advance for reading through this, and any assistance you're able to offfer, I've been banging my head against this for about 6 hours now and I've lost the perspective to actually track this one down.