-1

I have a program that reads 3 strings from a text file and outputs them as three columns. I am using MS Visual Studio 2022 for this. Upon running the program, the output I expected is shown, but so is an error message that states "Debug Error! Program:(file location) abort() has been called".

using namespace std;

int main() {

    string str1, str2, str3;
    ifstream inFile;

    inFile.open("strings.txt");

    getline(inFile, str1, '\n');
    getline(inFile, str2, '\n');
    getline(inFile, str3, '\n');

    if (str1.length() >= str2.length() && str1.length() >= str3.length()) {
        for (int i = 0; i <= str1.length(); i++) {
            cout << str1.at(i) << " " << str2.at(i) << " " << str3.at(i) << endl;
        }
    }

    if (str2.length() >= str1.length() && str2.length() >= str3.length()) {
        for (int i = 0; i <= str2.length(); i++) {
            cout << str1.at(i) << " " << str2.at(i) << " " << str3.at(i) << endl;
        }
    }

    if (str3.length() >= str1.length() && str3.length() >= str2.length()) {
        for (int i = 0; i <= str3.length(); i++) {
            cout << str1.at(i) << " " << str2.at(i) << " " << str3.at(i) << endl;
        }
    }

    system("pause");
    return 0;

}
drescherjm
  • 10,365
  • 5
  • 44
  • 64
Chase O
  • 11
  • When you hit the abort popup dialog press Retry then switch the "Stack Frame" on the debug toolbar to your code to see what part of your code was executing. – drescherjm Nov 09 '22 at 20:23
  • 2
    The `<=` for iterating over a string is wrong. Use `<` instead. – drescherjm Nov 09 '22 at 20:24
  • 2
    Note that the code isn't checking if the file was actually opened nor the return values of `getline` calls nor the actual size of those strings. Besides, it's attempting to access elements in all the strings up to the length of the *longer* string. Unless you are trying to throw an exception, you should iterate up to the *min* of those lengths. – Bob__ Nov 09 '22 at 20:25
  • https://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems – Jesper Juhl Nov 09 '22 at 20:31
  • Amazing that you got this code running without headers. – user4581301 Nov 09 '22 at 20:31
  • 3
    Do note that in C++11 onward, calling `string::operator[]` with a string's size/length is safe, it returns a reference to the string's required null terminator. But calling `string::at()` with the string's size/length will always throw a `std::out_of_range` exception. And this code is definitely going out of range of its strings when one string's length is `>` then another string's length – Remy Lebeau Nov 09 '22 at 20:32

1 Answers1

1

std::terminate() is called automatically when an exception is thrown but not caught. And the behavior of the default std::terminate_handler is to call std::abort().

If you wrapped your code in a try..catch block, you are likely to see that std::out_of_range is being thrown, because your for loops are not handling the string lengths correctly and are going out of bounds of the strings.

#include <stdexcept>

int main() {

    try {
        ...
    }
    catch (const std::exception &ex) {
        std::cerr << ex.what() << std::endl;
    }

    system("pause");
    return 0;
}

std::string::at() throws a std::out_of_range exception if it is called with a character index that is >= the string's size().

In this loop:

if (str1.length() >= str2.length() && str1.length() >= str3.length()) {
    for (int i = 0; i <= str1.length(); i++) {
        cout << str1.at(i) << " " << str2.at(i) << " " << str3.at(i) << endl;
    }
}

if str1.length() is greater than str2.length() or str3.length(), then either str2.at(i) or str3.at(i) will throw, respectively. And even if they don't (because all of the length()'s are equal), then str1.at(i) certainly will throw once i reaches str1.length(), since you are using <= when you should be using < instead.

Your loop needs to stop iterating when it reaches the minimum of the three string lengths, to avoid going out of bounds of any of the strings, eg:

if (str1.length() >= str2.length() && str1.length() >= str3.length()) {
    size_t min_len = min({str1.length(), str2.length(), str3.length()});
    for (size_t i = 0; i < min_len; ++i) {
        cout << str1.at(i) << " " << str2.at(i) << " " << str3.at(i) << endl;
    }
}

Your other two loops are making the same mistakes.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770