Sutter Bestwick
Sutter Bestwick

Reputation: 1

Setters Causeing Segfault

I'm sort of new to the computer coding world so I'm not exactly sure how to read the GDP, but I get Seg Fault: 11 when it tried to run my setters inside of my program. Could anyone explain why these setters are causing issues (both in lamens terms and tech terms if possible)? The setters are coded as follows:

class MapEntry{
private:
    int mIDVal;
    char* mKeyName;

public:
    MapEntry(char *key, int val) {
        mKeyName = key;
        mIDVal = val;
    }
    int getVal(){
        return mIDVal;
    }
    char* getKey(){
        return mKeyName;
    }
    void setVal(int val){
        this->mIDVal = val;
    }
    void setKey(char* key){
        this->mKeyName = key;
    }
};

I'm trying to create a simple database that has a char string as the key and a student ID of sorts as the val. Here is the rest of the code.

Map::Map() {
database = new MapEntry*[DATABASE_SIZE];
for (int i = 0; i < DATABASE_SIZE; i++){
    database[i]->setVal(0);
    database[i]->setKey("");
    }
}

/* Adds (inserts) val with the associated key.
 * Returns if successful or not.  (It is not successful if we are out of
 * memory, or if the key already exists.)
 */
bool Map::add(const char *key, int val) {
    char lettersForKey[50];
    strcpy(lettersForKey, key); //because const ref and all that jazz

// when adding, I need to make sure the key does not already exist
    for (int i = 0; i < DATABASE_SIZE; i++)
        if (database[i]->getVal() == 0) {
            database[i]->setVal(val);
            database[i]->setKey(lettersForKey);
        }
    return false;
}

void Map::print() {
    for (int i = 0; i < DATABASE_SIZE; i++)
        if (database[i] != NULL) {
            std::cout << database[i]->getKey() << " " << database[i]->getVal() << "\n";
        }
}

Upvotes: 0

Views: 813

Answers (2)

john
john

Reputation: 87997

The errors are because you haven't created any MapEntry objects.

This line creates an array of MapEntry pointers, but the pointers have not been initialised.

database = new MapEntry*[DATABASE_SIZE];

You need to create the MapEntry objects as well, perhaps like this

for (int i = 0; i < DATABASE_SIZE; i++){
    database[i] = new MapEntry();
    database[i]->setVal(0);
    database[i]->setKey("");
    }
}

Of course you could avoid all the trouble by avoiding pointers, you do know that they are bad?

class Map
{
    std::vector<MapEntry> database;
};

Map::Map() : database(DATABASE_SIZE)
{
    for (int i = 0; i < DATABASE_SIZE; i++)
    {
        database[i].setVal(0);
        database[i].setKey("");
    }
}

No pointers, no problems. You should replace the char* mKeyName pointer in MapEntry with std::string mKeyName too.

Upvotes: 5

Some programmer dude
Some programmer dude

Reputation: 409364

With

database[i]->setKey(lettersForKey);

you make the mKeyName member point to the first element of an array that is local inside the Map::add function. As soon as the Map::add function exits that array goes out of scope (and basically cease to exist), and will leave you with an invalid pointer. Dereferencing that pointer will lead to undefined behavior.

If you want to handle strings, use std::string instead.

Upvotes: 1

Related Questions