Confusion with array of pointers - c++

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.

Related

C++ Reallocating pointer to array in dynamic memory in a different function

I have just done a module on pointers and dynamic memory in C++ and am attempting to complete a personal assignment so that I can practice the concepts. The program manages an array of strings that are names. The goal that I set for myself is that the list is stored in the heap (to practice using "new"), and the list is dynamically sized as new names are entered.
Disclaimer: I realize that this is easily accomplished using vectors, and after struggling with this for hours I re-wrote my original code to use a vector for the list with no problems. However I want to learn where my understanding of how pointers work is broken.
The problem that I have with the program is this: I initialize the name array to have zero elements and have a function to add names that handles the dynamic sizing. When first called it seems to re-size the array correctly and add a new name to the the new array. Within the function to add a name, I can print the contents of the new array. I can also re-assign the old array pointer to the address of the new array on the heap. However when I call the print function from main after adding a name to the list, the list does not contain a name. By my understanding, since I'm using pointers I should be updating values directly, so after the add name function terminates, the values should persist. Also, if I attempt to add a second name the program crashes. What am I doing wrong with the handling of memory?
I've searched quite a bit and the closest that I can find for a resolution was this post:
How to make an array with a dynamic size? General usage of dynamic arrays (maybe pointers too)?
I modified my code based on what I understand from that but it still doesn't work properly.
#include <stdio.h>
#include <vector>
#include <iostream>
using namespace std;
void add_name_to_list(string * my_list, size_t * list_size);
string get_name();
void print_names(const string *const my_list, const size_t *const list_size);
int main()
{
string *name_list_ptr {nullptr};
name_list_ptr = new string [0];
size_t name_list_size{0};
size_t *name_list_size_ptr {&name_list_size};
print_names(name_list_ptr, name_list_size_ptr);
add_name_to_list(name_list_ptr, name_list_size_ptr);
print_names(name_list_ptr, name_list_size_ptr);
return 0;
}
void add_name_to_list (string * my_list, size_t *list_size)
{
string new_name{get_name()};
string *new_string_ptr{nullptr};
new_string_ptr = new string [*list_size+1];
// copy existing list into new list
cout << "List size is " << *list_size << " so *list size == 0 is " << (*list_size == 0) << endl;
if(*list_size == 0)
{
new_string_ptr[0] = new_name;
*list_size = *list_size +1;
cout << new_string_ptr[0] << " has been added to position " << *list_size << endl;
}
else
{
print_names(my_list, list_size);
for(size_t i{0}; i < *list_size; i++)
{
cout << "At position " << i << " original list is " << my_list[i] << endl;
new_string_ptr[i] = my_list[i];
cout << "The name " << new_string_ptr[i] << " has been added to position " << i << " of the new list" << endl;
}
new_string_ptr[*list_size - 1] = new_name;
*list_size = *list_size + 1;
}
print_names(new_string_ptr, list_size);
string *temp_ptr{nullptr};
temp_ptr = new string [*list_size-1];
cout << "temp ptr is " << temp_ptr << " and my list is " << my_list << endl;
temp_ptr = my_list;
cout << "temp ptr is " << temp_ptr << " and my list is " << my_list << endl;
my_list = new_string_ptr;
delete [] temp_ptr;
new_string_ptr = nullptr;
print_names(my_list, list_size);
}
string get_name()
{
cin.sync();
cin.clear();
string new_name{};
cout << "\nEnter the full name: ";
getline(cin, new_name);
cin.sync();
cin.clear();
if(new_name.size() <= 1)
return "0";
else
return new_name;
}
void print_names(const string *const my_list, const size_t *const list_size)
{
if(*list_size == 0)
cout << "The list is empty" << endl;
else
for(size_t j{0}; j < *list_size; j++)
cout << j << ". " << my_list[j] << endl;
}
One variation that I've tried based on what I learned from searching is:
cout << "temp ptr is " << temp_ptr << " and my list is " << my_list << endl;
//my_list = new_string_ptr;
//delete [] temp_ptr;
//new_string_ptr = nullptr;
delete [] my_list;
my_list = new string[*list_size];
my_list = new_string_ptr;
print_names(my_list, list_size);
Unfortunately the results are the same.
Without checking the logic of the implementation, your list doesn't update because you are assigning my_list = new_string_ptr; but your function received void add_name_to_list (string * my_list, size_t *list_size).
As you are newcomer to C++ world, let me explain clearly:
list_size is a pointer to a size_t, so if you modify the pointed memory, the change will persist, but if you modify the pointer itself, it will not.
list_size = new size_t; // This change doesn't persist
list_size++; // This change doesn't persist
*list_size++; // This change persists and the value of pointed memory was increased.
With my_list is happening exactly the same, you are trying to modify the pointer itself, not the pointed memory.
So, you should use:
void add_name_to_list (string * &my_list, size_t *list_size)
Or maybe you are more confortable with
void add_name_to_list (string ** my_list, size_t *list_size)
[...]
*my_list = new_string_ptr;
Hope this helps

Lists of lists losing data after pointer arithmetics

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.

Strange output when attempting to print from an array of pointers c++

I'm 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];
adding the user to the hobbies array:
int Graph::addUserToHobby(std::string hobby1, std::string id){
// 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;
h->hobby = hobby1;
hobbies[key] = h;
}
my goal is to create an array of pointers with the hobbylist type, when attempting to print the contents of that array I end up with a very strange random symbol output:
GLIBC_2.2.5GLIBCXX_3.4.13GLIBCXX_3.4.14CXXABI_1.3GLIBCXX_3.4� P&y
I attempt to print it as so:
void Graph::displayHobbies(){
cout << "========================================\n";
cout << "DISPLAYING HOBBY INTERESTS =============" << endl;
for(auto const& value: hobbies)
{
cout << value->hobby << ":" << endl;
}
}
I was wondering if I am printing incorrectly or if I am adding the hobby to the hobbies array incorrectly.
Changed Code:
hobbylist *h = new hobbylist;
h->hobby = hobby1;
if(hobbies[key] ==NULL){
h->list.push_back(user);
hobbies[key] = h;
}
else if (hobbies[key]!=NULL){
h= hobbies[key];
h->list.push_back(user);
}
Changed code is above and I am getting a seg fault at the last line in the else statement 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?
You have at least two bugs.
hobbylist *h = new hobbylist;
h->hobby = hobby1;
hobbies[key] = h;
key is your hash key. If hobbies[key] already has a pointer, this is going to leak memory.
for(auto const& value: hobbies)
{
cout << value->hobby << ":" << endl;
}
This assumes that every slot in the hobbies hash array contains a pointer. This is unlikely. If a particular value in hobbies has never been initialized (none of the previously inserted hobbies mapped to that hash key), the pointer will be NULL, and value->hobby will attempt to dereference a NULL pointer, resulting in undefined behavior. That's your likely crash.

linked list not working properly, head updated instead

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.

VS'08 C++ Access Violcation When Initialising Pointer Previously had no issues

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.