-1

My program keeps getting me bad alloc error when I use a normal function that contains a member function.

The program is about taking some specific inputs from the command line and printing the elements of an array of pointers. This has to be done with array of pointers.

To begin with, I created a class that needs to have 2 strings. One for the name and one for the room. Then I created another class with a size and a pointer to my first class in order to create an array.

My main is at the end, and above main are the 2 normal functions. What is wrong with this code? When I type the commands for the first time of the loop it works until I enter a command that connects to a normal function. Probably something is wrong there but I can't seem to find it.

#include <iostream>
#include <string>
using namespace std;

class Address
{
    private:
        string name;
        string room;
    public:
        Address(){};
        Address(string, string);
        string get_name();
        string get_room();
        void change_room(string);
};

Address::Address (string n, string r)
{
    name = n;
    room = r;
}


string Address::get_name()
{
    return name;
}

string Address::get_room()
{
    return room;
}

void Address::change_room(string change)
{
    room = change;
}


//end of Address class


class Address_Book 
{
    private:
        int size;
        Address* addresses;
    public:
        Address_Book();
        ~Address_Book(){ delete[] addresses;}
        void add(Address);
        void move(string, string);
        int get_size();
        Address location(int);
        int find(string);
        void clear();
        void remove_address(string);
        int exists(string);
        void sort();
};


Address_Book::Address_Book()
{
    int s = 0;
    size = s;
    addresses = new Address[s];
}

void Address_Book::add(Address add)
{
    Address* temp = new Address [size + 1];
    for (int i = 0; i < size; i++)
    {
        temp[i] = addresses[i];
    }
    temp[size] = add;
    delete[] addresses;
    addresses = temp;
    size ++;

}

void Address_Book::move(string name, string newroom)
{
    for (int i = 0; i < size ; i++)
    {
        if (addresses[i].get_name() == name )
        {
            addresses[i].change_room(newroom);
        }
    }
}

void Address_Book::remove_address(string name)
{
    Address* temp = new Address [size - 1];

    for (int i = 0; i < size; i++)
    {
        if (addresses[i].get_name() != name)
        {
            temp[i] = addresses[i];
        }
        else if (addresses[i].get_name() == name)
        {
            for (int j = i + 1; j < size; j++)
            {
                temp[i] = addresses[j];
                i++;
            }
            break;
        }
    }
    delete[] addresses;
    addresses = temp;
    size--;
}


int Address_Book::get_size()
{
    return size;
}


Address Address_Book::location(int index)
{
    return addresses[index];
}


void Address_Book::sort()
{
    Address temp;
    for (int i = 0; i < size; i++)
    {
        for(int j = 0; j < size - 1; j++)
        {
            if (addresses[j].get_room() > addresses[j + 1].get_room())
            {
                temp = addresses[j];
                addresses[j] = addresses[j + 1];
                addresses[j + 1] = temp;
            }
        }
    }
    for (int i = 0; i < size; i++)
    {
        if (addresses[i].get_room() == addresses[i + 1].get_room())
        {
            if (addresses[i].get_name() > addresses[i + 1].get_name())
            {
                temp = addresses[i];
                addresses[i] = addresses[i + 1];
                addresses[i + 1] = temp;
            }
        }
    }
}

void Address_Book::clear()
{
    Address * temp = new Address[0];
    delete[] addresses;
    addresses = temp;
    size = 0;
}


int Address_Book::find(string name)
{
    for (int i = 0; i < size; i++)
    {
        if (addresses[i].get_name() == name)
        {
            return i;
        }
    }
    return -1;
}



//end of Address_Book class



void find(string name, Address_Book addbook)
{
    int index = addbook.find(name);
    cout << index << endl;

    if (index > -1)
    {
        cout << addbook.location(index).get_name() << " is in room " << 
        addbook.location(index).get_room() << endl;
    }
    else
    {
        throw runtime_error("entry does not exist.");
    }
}


void remove_add(string name, Address_Book book)
{
    int exist = book.find(name);

    if (exist > -1)
    {
        book.remove_address(name);
    }
    else
    {
        throw runtime_error("entry does not existt.");
    }

}






int main()
{
    Address_Book addbook;
    string action, in_name, in_room;
    do
    {
        try
        {
            cout << "> ";
            cin >> action;

            if (action == "add")
            {
                cin >> in_name >> in_room;
                Address newadd(in_name, in_room);
                addbook.add(newadd);
            }
            else if (action == "move")
            {
                cin >> in_name >> in_room;
                addbook.move(in_name, in_room);
            }
            else if (action == "remove")
            {
                cin >> in_name;
                remove_add(in_name, addbook);
            }
            else if (action == "find")
            {
                cin >> in_name;
               find(in_name, addbook);
            }
            else if (action == "list")
            {
                addbook.sort();

                for (int i = 0; i < addbook.get_size(); i++)
                {
                cout << addbook.location(i).get_name() << " is in room 
                " << addbook.location(i).get_room() << endl;
                }
            }
            else if (action == "clear")
            {
                addbook.clear();
            }
            else
            {
                throw runtime_error("input mismatch.");
            }
        }
        catch (runtime_error& e)
        {
            cerr << "error: " << e.what() << endl;
        }
    }while (action != "exit");

    return 0;
}
halfer
  • 19,824
  • 17
  • 99
  • 186
  • would be helpful to know what operating system, compiler, etc. you are using. An example for the input that's causing problems would be helpful. Also,Please let us know what is printed on the screen. – CplusPuzzle Oct 21 '17 at 16:27
  • I have to reinvent vector for this one. Its a must use. I need to understand how memory works. – Dr Victor V. Doom Oct 21 '17 at 16:29
  • The operating system is mac. When I enter 'add' followed by the name and a room they are going straight to the addresses array that i have created. and when I enter 'list' it prints the whole array. But when I want to remove or find it works only the first time. then it get me a bad alloc(). whats going on? – Dr Victor V. Doom Oct 21 '17 at 16:30
  • BTW, you should pass `std::string` variables by reference or constant reference, so the compiler doesn't make unnecessary copies. – Thomas Matthews Oct 21 '17 at 16:55
  • In your `Address_Book` class, use `std::vector
    addresses;` instead of a pointer. This will prevent your present issues from occurring.
    – Thomas Matthews Oct 21 '17 at 16:57
  • Here is one issue, allocating a zero length array in the constructor of `Address_Book`. – Thomas Matthews Oct 21 '17 at 16:58

2 Answers2

0

The exact commands that lead to your problem are not specified in your question, so I poked around a little bit until the code crashed with a segmentation fault.

Valgrind and Dr. Memory are awesome tools for finding root causes of such problems. In your case:

$ g++ -g 46865300.cpp
$ valgrind ./a.out
> add foo bar
> list
==102== Invalid read of size 8
==102==    at 0x4EF4EF8: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) (in /usr/lib64/libstdc++.so.6.0.19)
==102==    by 0x401354: Address::get_room() (46865300.cpp:33)
==102==    by 0x401C05: Address_Book::sort() (46865300.cpp:152)
==102==    by 0x4026A3: main (46865300.cpp:262)
==102==  Address 0x5a17410 is 8 bytes after a block of size 24 alloc'd
==102==    at 0x4C2A8A8: operator new[](unsigned long) (vg_replace_malloc.c:423)
==102==    by 0x4014BF: Address_Book::add(Address) (46865300.cpp:74)
==102==    by 0x40245C: main (46865300.cpp:243)

It says that the following code performs out-of-bounds access:

150     for (int i = 0; i < size; i++)
151     {
152         if (addresses[i].get_room() == addresses[i + 1].get_room())
153         {
154             if (addresses[i].get_name() > addresses[i + 1].get_name())

I guess the loop condition should use "size - 1" instead of "size".

mephi42
  • 475
  • 6
  • 18
  • This is not the problem. try entering: 'add' John F450, then add someone else e.g. 'add' Frank T430. Then type 'list'. Then type 'find' John (it should print the correct output) but when I type 'list' again or try to 'find' again it gives either bad alloc or double free or corruption – Dr Victor V. Doom Oct 21 '17 at 16:51
0

The function remove_add needs to get the address book object by reference or by pointer. The way it is now, it removes from a copy of the address book.

It should look like this:

void remove_add(string name, Address_Book& book)
{
    int exist = book.find(name);

    if (exist > -1)
    {
        book.remove_address(name);
    }
    else
    {
        throw runtime_error("entry does not existt.");
    }

}

Also, you should probably do something different in case size == 1 in the following function. e.g. set addresses to NULL, zero or nullptr if your compiler supports it.

void Address_Book::remove_address(string name)
{
    Address* temp = new Address[size - 1];

    for (int i = 0; i < size; i++)
    {
        if (addresses[i].get_name() != name)
        {
            temp[i] = addresses[i];
        }
        else if (addresses[i].get_name() == name)
        {
            for (int j = i + 1; j < size; j++)
            {
                temp[i] = addresses[j];
                i++;
            }
            break;
        }
    }
    delete[] addresses;
    addresses = temp;
    size--;
}

Have fun learning the language and good luck :)

CplusPuzzle
  • 298
  • 2
  • 9