C++ - Unexpected output from std::string

Asked by At

I'm writing a function which returns a string. But something weird happened. The output of the result string was printed as an unexpected thing from the console.

It becomes Chinese or something else or EMPTY STRING depending on the machine (TESTED). But this only happens when the input string is super long. It works normally for strings with a smaller size.

Is there a better way to append char to a string? It's because I suspect the problem was caused by the way how I added chars to the end of a string.

From Console

enter image description here

From Debugger

enter image description here

main.cpp

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

bool checkPalindrome(string s)
{
    return (s == std::string(s.rbegin(), s.rend()));
}

string longestPalindrome(string s)
{
    if (s.size() > 1000 || s.empty())
        return "";

    string result = "";
    string sub = "";
    char* ptr = &sub[0];

    for (int i = 0; i < s.length(); ++i) {
        sub += s[i];
        while (true) {
            string temp = ptr;
            if (checkPalindrome(temp)) {
                ptr = &sub[0];
                if (temp.length() > result.length()) {
                    result = temp;
                    break;
                }
                break;
            }
            else {
                ptr++;
            }
            if (ptr == &sub[sub.length()-1]) {
                ptr = &sub[0];
                break;
            }
        }
    }
    std::cout << "end of function" << std::endl;
    return result;
}



int main()
{
    string output = longestPalindrome("babaddtattarrattatddetartrateedredividerb");
    std::cout << output << std::endl;

    return 0;
}

1 Answers

6
Fran├žois Andrieux On Best Solutions

The expression char* ptr = &sub[0]; gives you a pointer to a char. However, when you perform sub += s[i]; you may require the string's internal storage to grow to accommodate the new character. If you keep adding to it, eventually it will happen. This will invalidate ptr and render it unusable until it's reassigned.

When such a reallocation does happen a larger buffer is allocated, the previous value is moved from the shorter buffer to the larger buffer then the shorter buffer is destroyed to be replaced by the larger one. But ptr still points to where the previous shorter buffer's data used to be. It's now pointing to an element of a destroyed object. When you then do string temp = ptr; you risk initializing a string from an invalidated pointer which is undefined behavior.

One relatively simple solution woult be to stick with indices instead of pointers. Indices by their nature don't get invalidated as long as they are within the bounds of the string's size. Another possible solution might be to use reserve to pre-allocate a large enough capacity that it never has to reallocate.