0

When the below code is run, I get garbage output. I have debugged it enough to figure out the error comes when I try to access hobbies[i]->hobby. Any help would be appreciated. I have been trying to figure out what is going on for hours.

int Graph::addUserToHobby(std::string hobby, std::string id){
  int key = ((int)hobby[0] + (int)hobby[1])%HASHMAP_SIZE;
  int collisions = 0;
  while(hobbies[key] != NULL && hobbies[key]->hobby.compare(hobby) != 0 ){
    key++;
    collisions++;
    if(key >= HASHMAP_SIZE){
      key = 0;
    }
  }

  if(hobbies[key] == NULL){
    hobbylist hob;
    hob.hobby = hobby;
    hob.list.push_back(findVertex(id));
    hobbies[key] = &hob;
  }
  else{
    hobbies[key]->list.push_back(findVertex(id));
  }
  return collisions;

}

void Graph::displayHobbies(){

  for(int i=0; i<HASHMAP_SIZE; i++){
    if(hobbies[i] != NULL){
      cout << hobbies[i]->hobby << ": ";
      for(unsigned int j=0; j<hobbies[i]->list.size()-1; j++){
        cout << hobbies[i]->list[j]->name << ", ";
      }
      cout <<  hobbies[i]->list[hobbies[i]->list.size()-1]->name << endl;
    }
  }
}
gsamaras
  • 66,800
  • 33
  • 152
  • 256

3 Answers3

9

Focus your attention in that part of the code:

if(hobbies[key] == NULL) {
  hobbylist hob;
  ...        
  hobbies[key] = &hob;
}

When hob gets out of scope (at the end of that if-statement's body), hobbies[key] will reference something that doesn't exist any more.

Later on in your program, as you correctly noticed, when you do cout << hobbies[i]->hobby;, you will request for hobby on something that has gone out of scope, which invokes Undefined Behavior (UB).


Some possible solutions:

  1. Use an std::map, instead of the array of pointers you use now. The container will automatically take care of the memory management for you. (Recommended)
  2. Use smart pointers (e.g. std::unique_ptr), instead of raw pointers. Read more in What is a smart pointer and when should I use one?
  3. Dynamically allocate hob, so that its lifetime is extended (that means that when that if-statement's body terminates, hob's lifetime won't terminate). This approach requires you to be responsible for the memory management (you have to de-allocate every piece of memory that you dynamically allocated before (call delete as many times as you called new)).
gsamaras
  • 66,800
  • 33
  • 152
  • 256
2

In this part:

if(hobbies[key] == NULL){
  hobbylist hob;
  /* ... */
  hobbies[key] = &hob;
}

hob is allocated on the stack and deleted after the if block. So the pointer you have in hobbies[key] is dangling. You can catch these sort of errors with valgrind.

perreal
  • 85,397
  • 16
  • 134
  • 168
2

Your issue is that you are populating your hobbies value with pointers to objects allocated on the stack.

These objects will have subsequently been destroyed. Perhaps you were meaning to allocate them on the heap with new?

hobbylist* hob = new hobbylist;
...
hobbies[key] = hob 
donkopotamus
  • 18,536
  • 2
  • 36
  • 52