1

in the following code reverse function rerturns an empty string. no compilation errors.

what can cause the problem here?

#include <iostream>
#include <bits/basic_string.h>
using namespace std;

string reverse(string str) { 
    string r;

    for (int i=str.length()-1; i>=0; i--) {
        r[str.length() - 1 - i] = str[i];  
    }

    return r;
} 

int main() {
    string str = "ABCDefgh";

    cout<<"Reverse string is : "<<reverse(str)<<endl;

    return 0;
}

Edit: r[str.length() - i] = str[i];
r[str.length() - 1 - i] = str[i];

11
  • 3
    you need to allocate space for r, its length is 0. Commented May 1, 2019 at 17:42
  • 2
    Why <bits/basic_string.h> instead of <string>? Commented May 1, 2019 at 17:44
  • "no compilation errors ... r[str.length() - i] = str[i];" is undefined behavior. Commented May 1, 2019 at 17:46
  • It works fine after allocating length. Do I always need to declare length for a string? Will string behave differently in c++ than it behaves in php or javascript? Commented May 1, 2019 at 17:53
  • 1
    I'm going a bit further than Quimby. Don't include anything from the bits folder. Everything in bits is implementation-specific and intended to be included from a higher-level header. The implementation details can change without warning and are not the same, likely they don't even exist, across all C++ implementations. Without being included by the higher-level header, the headers in bits may malfunction because some set-up that's assumed to have been performed by the higher-level header may not have been performed. Commented May 1, 2019 at 18:01

1 Answer 1

9

Your function is invoking UNDEFINED BEHAVIOR, as you are not allocating any memory for the r string before using its [] operator to assign characters to r. std::string::operator[] does not perform any bounds checking, so you are actually trashing surrounding memory. Also, you are not indexing into r correctly, too (your indexing is off by 1).

Had you used the std::string::at() method instead of the operator[], it would have raised a runtime exception complaining about you accessing characters out of bounds.

You need to make a copy of the input str first, and then you can reverse the characters of that copy, eg:

std::string reverse(std::string str) { 
    std::string r = str; // <-- COPY HERE

    for (int i = str.length()-1, j = 0; i >= 0; --i, ++j) {
        r[j] = str[i];  
    }

    return r;
} 

Alternatively, you can use the std::string::resize() method to pre-allocate the r string, then use of operator[] will be valid:

std::string reverse(std::string str) { 
    std::string r;
    r.resize(str.length()); // <-- ALLOCATE HERE

    for (int i = str.length()-1, j = 0; i >= 0; --i, ++j) {
        r[j] = str[i];  
    }

    return r;
} 

Or, you can use the std::string::push_back() method instead (optionally with the std::string::reserve() method to avoid re-allocations while pushing):

std::string reverse(std::string str) { 
    std::string r;
    r.reserve(str.length()); // <-- OPTIONAL

    for (int i = str.length()-1; i >= 0; --i) {
        r.push_back(str[i]);  
    }

    return r;
} 

Or, have a look at replacing your manual loop with the std::reverse_copy() algorithm instead:

#include <algorithm>

std::string reverse(std::string str) { 
    std::string r;
    r.resize(str.length());
    std::reverse_copy(str.begin(), str.end(), r.begin());
    return r;
} 
#include <algorithm>
#include <iterator>

std::string reverse(std::string str) { 
    std::string r;
    r.reserve(str.length()); // <-- OPTIONAL
    std::reverse_copy(str.begin(), str.end(), std::back_inserter(r));
    return r;
} 

However, that being said, since the input str is being passed by value, it is ALREADY a copy of whatever string you pass to your function, so you don't actually need the local r string at all. You can reverse the characters of the input str in-place, just be use to take into account that the source and destination strings are the same string, so adjust your loop accordingly:

std::string reverse(std::string str) { 
    int count = str.length() / 2;
    for (int i = 0, j = str.length()-1; i < count; ++i, --j) {
        char ch = str[i];
        str[i] = str[j];
        str[j] = ch;

        // alternatively:
        // std::swap(str[i], str[j]);
    }

    return str;
} 

Or, have a look at the std::reverse() algorithm instead:

#include <algorithm>

std::string reverse(std::string str) { 
    std::reverse(str.begin(), str.end());
    return str;
} 

Or, you can use the std::string constructor that takes 2 iterators as input, as std::string has reverse iterators available:

std::string reverse(std::string str) { 
    return std::string(str.rbegin(), str.rend());
} 

Sign up to request clarification or add additional context in comments.

2 Comments

Well this is pass by value, so you don't even need to make a copy - you already have one.
You do not even need std::reverse() just one liner return std::string( str.rbegin(), str.rend() ); will do

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.