I been programming a set of lists holing pointer to lists, and wanna create an convenient interface to brows them and save selected data from file to lists. The idea is that there is one "API list" with unique id, and whenever I find an unique id, I shall create a new API list. For now I'm stack on saving data to one "API list's" related lists.
The structure looks simply like this:
enum day { mon, tue, wed, thu, fri, sat, sun };
static const string enumValues[] = { "mon", "tue", "wed", "thu", "fri", "sat", "sun" };
struct _ListSub {
string h;
day d;
string gr;
string sub;
_ListSub *next = nullptr;
};
struct ListAPI {
string id;
ListAPI *next = nullptr;
_ListSub *head = nullptr;
};
And my function to read and save values from the file to the lists look like this:
ListAPI *createLists(string arg) {
ifstream f_in;
ListAPI *listGrip;
f_in.open(arg);
if (!f_in.is_open()) {
cout << "\"" << arg << "\": file does not exist!" << endl;
exit(EXIT_FAILURE);
}
listGrip = new ListAPI;
listGrip->head = new _ListSub;
while (true) {
// dummy data
string h;
string week = "";
string gr;
string id;
string sub;
if (!(f_in >> h >> week >> gr >> id >> sub)) {
break;
}
cout << "ID check: " << checkListID(id, listGrip) << endl;
listGrip->id = id;
listGrip->head->h = h;
listGrip->head->d = (day)enumerateDay(week);
listGrip->head->gr = gr;
listGrip->head->sub = sub;
listGrip->head ++;
listGrip->head = new _ListSub;
}
f_in.close();
return listGrip;
}
Any ways, the data is correct, it worked fine, so long didn't add this part (moving head pointer of _listSub and creating new instance of this object):
listGrip->head ++;
listGrip->head = new _ListSub;
All data that I'm getting out of this is id witch I save to listGrip (my list API), however all the data from the nested list list is gone.
Can someone tell me what I'm doing wrong here with pointers?
MAIN:
int main( int argc, char **argv ) {
/* Directly parse options in order to avoid accepting abbrevations. */
string ARGUMENT;
validate_arguments;
cout << "File path: " << ARGUMENT << endl;
ListAPI *listGrip;
listGrip = createLists( ARGUMENT );
//listGrip->head;
cout << "List has been created." << endl;
cout << "ID: " << listGrip->id << endl;
cout << "Subject: " << listGrip->head->sub << endl;
cout << "Time: " << listGrip->head->h << endl;
cout << "Day: " << getTextFromEnum((short)listGrip->head->d) << endl;
delete listGrip;
return EXIT_SUCCESS;
}
listGrip->head ++;
Makes no sense. head points to a single _ListSub. When you increment it, it will point to some random memory after the _ListSub you've allocated. This random memory is not yours and could lead to memory corruption or if you are lucky to a SegFault.
What you probably want is to insert at head:
auto new_head = new _ListSub;
new_head->next = listGrip->head;
listGrip->head = new_head;
Or even better use the Standard library. There's a std::list in there already, it's well tested and it works.
Linked-List is an abstract structure connecting loosely placed nodes. As nodes are not placed next to each other we can not preform pointer arithmetics to get to the next node. In stead we can create an insert function witch is going to redirect pointers for us.
Redirecting nodes:
Classical Linked-List contain the next pointer in it's structure, pointing to the next node of the same type. For convince we can add previous pointer and a size variable to keep track of list size.
void insertSub(string h, day d, string gr, string sub) {
auto newNode = new _ListSub;
//initialize
newNode->h = h;
newNode->d = d;
newNode->gr = gr;
newNode->sub = sub;
// point new node to the currently previous and next node
newNode->next = node->next;
newNode->prev = node;
// point currently next and previous node to the new node
node->next->prev = newNode;
node->next = newNode;
// increment size
++ node->size;
}
This works for my structure, but probably you wanna use constructor for object initialization.
Related
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";
}
My program is a list of cities, it's good but when I call to popFront(), I don't know why but it doesn't work, then I call any function and the program is over.
City* popFront(Nodo*& header, Nodo*& trailer) {
City* libras;
if (inicio) {
strcpy(libras->Name,inicio->dato.Name );
libras->Num = header->dato.Num;
Nodo* aux = header;
header= header->next;
header->previous= NULL;
delete aux;
if (!header) trailer = NULL;
}
return libras;
}
void read(Nodo*& head) {
Nodo* aux = head;
int pos = 1;
while (pos <= node_count) {
cout << "pos" << pos << endl;
cout << "Name> " << aux->dato.Name << endl;
cout << "NUm> " << aux->dato.Num << endl;
aux = aux->next;
pos++;
}
if (node_count == 0)cout << "Empty list" << endl;
}
Well, I'm not sure this is the only problem, but this right here is wrong:
City* libras;
You need to allocate it before you use it, like this:
City* libras = new City;
Otherwise, something like strcpy(libras->Name,inicio->dato.Name ); will fall and crash hard. That's because it's UB (Undefined Behavior) to access a pointer to memory that is unallocated.
Of course, you will need to delete it when you're done with it, but you seem to know and understand that already based on your other code:
delete libras; // Or wherever the returned pointer gets stored
This may be a dumb question but I'm getting pretty desperate at this point.
I am attempting to create an array of pointers:
struct vertex
{
std::string id;
std::string name;
int networkID;
std::vector<adjVertex> friends;
bool visited;
};
struct hobbylist
{
std::string hobby;
std::vector<vertex*> list;
};
hobbylist * hobbies[HASHMAP_SIZE];
int Graph::addUserToHobby(std::string hobby1, std::string id){
//cout << "Adding to hobby: " << hobby1 << " user: " << id << endl;
vertex *user = findVertex(id);
int collisions = 0;
// initial key is based on the first 2 characters of the hobby name
int key = (hobby1[0] + hobby1[1]) % HASHMAP_SIZE;
//cout << " initial hashmap key " << key << endl;
hobbylist *h = new hobbylist;
if(hobbies[key] == NULL){
h->hobby = hobby1;
h->list.push_back(user);
hobbies[key] = h;}
else if (hobbies[key]!=NULL){
hobbies[key]->list.push_back(user);
collisions++;}
return collisions;
}
I am getting a seg fault at the last line in the else statement in the addUserToHobby function when running the function the first time and I am confused why the function would go to the else statement when the array should be empty and therefore hobbies[key] should be null the first time the function is run? Upon further inspection the function will always enter the else statement, so the array values are never null?
Each location is the array is not set to null by default, it's just whatever trash was in there before you allocated it.
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.