c++bad-alloc

C++ throwing error "terminate called after throwing an instance of 'std::bad_alloc'"


I'm trying to run the following code, which should get user input, place it in a string, copy that string over to an array of chars, extract the first character to another array of chars, and finally get the rest of it after a space to an array of ints. But, it throws an error and I can't tell why:

terminate called after throwing an instance of std::bad_alloc

#include <iostream>
#include <string>
#include <cstring>

using namespace std;

int main()
{
    char ID[15];
    int score[15];
    float avg[3];
    int i;

    cout<< "Hello there!:\n";

    string name;

    for (i = 0; i <= 15; i++) {

        cout<< "Please enter a ID:";
        cin >> name;

        char* temp = new char[name.size()+1];

        name.copy(temp, name.size() + 1);

        ID[i] = temp[0];

        temp = new char[name.size()-2];

        name = name.substr(2,name.length());
        name.copy(temp, name.size() + 1);

        score[i] = atoi(temp);
    }
    cout << endl;

    cout << "Name" << "      " << "Average" << endl;

    for (i = 0; i <= 15; i++) {
        cout << ID[i] << "           "<< score[i] << endl;
    }

    return 0;
}

Solution

  • Think real hard about what this piece of code is doing:

    temp = new char[name.size()-2];
    name = name.substr(2,name.length());
    name.copy(temp, name.size() + 1);
    

    If name.size() is less than 2 characters, the new[] is invalid. But even if name.size() were greater than 2, say 5, then you would allocate temp as only 3 characters without room for the null-terminator, but then you would copy 3 characters and the null-terminator into temp. So you are likely to corrupt memory.

    That said, there are other problems with the rest of your code, too:

    Try this instead:

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main()
    {
        char ID[15];
        int score[15];
        string name;
    
        cout << "Hello there!:\n";
    
        for (int i = 0; i < 15; ++i) {
    
            cout << "Please enter a ID:";
            getline(cin, name);
    
            ID[i] = name[0];
    
            name = name.substr(2,name.size());
    
            score[i] = atoi(name.c_str()); // <-- prefer std::stoi() instead...
        }
        cout << endl;
    
        cout << "Name" << "      " << "Average" << endl;
    
        for (int i = 0; i < 15; ++i) {
            cout << ID[i] << "           " << score[i] << endl;
        }
    
        return 0;
    }
    

    However, it would be simpler to write this without the use of std::string at all, let operator>> read directly into your arrays handling the spaces between them for you, eg:

    #include <iostream>
    using namespace std;
    
    int main()
    {
        char ID[15];
        int score[15];
    
        cout << "Hello there!:\n";
    
        for (int i = 0; i < 15; ++i) {
    
            cout << "Please enter a ID:";
            cin >> ID[i];
            cin >> score[i];
        }
        cout << endl;
    
        cout << "Name" << "      " << "Average" << endl;
    
        for (int i = 0; i < 15; ++i) {
            cout << ID[i] << "           " << score[i] << endl;
        }
    
        return 0;
    }