0

I am new to C++ and I recently learned pointers and references through u-demy lectures. After lectures, I am solving a problem to reverse a string using a separate function. I came up with a code but for some reason, I can access an individual char using [] notation (like reverse[0] is equal to !) but when I print the whole string I get an empty string? What is causing this issue?

Thank you for your time in advance!

Here I have pasted my code:

#include <iostream>
// using namespace std;

std::string reverse_string(const std::string &str) {
    std::string reversed;

    size_t size {str.length()};
    for(int i{}; i < size/2; i++) {
        reversed[i] = str[(size-1)-i];
        reversed[(size-1)-i] = str[i];
    }
    
    return reversed;
}

int main() {
    // Write C++ code here
    std::string input = "Hello, World!";
    std::string reversed = reverse_string(input);
    std::cout << reversed << std::endl;  //I get nothing, BUT
    std::cout << reversed[0] << std::endl //here I do get a '!'
    return 0;
}
Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51
Jerry
  • 15
  • 2
  • Does this answer your question? [why string variable "sum" is not storing any data and program is not giving any output](https://stackoverflow.com/questions/41892750/why-string-variable-sum-is-not-storing-any-data-and-program-is-not-giving-any) – JaMiT Jun 01 '23 at 14:01
  • 1
    Why not to use `std::reverse` or `std::string reversed{input.rbegin(), input.rend()};`? – Dmitry Sazonov Jun 01 '23 at 14:08
  • Why make the code more complex than it needs to be? Usually you're trying to keep the locations of memory accessed as close together as possible, and reading/writing from/to both ends of the string isn't exactly great in that regard. Iterating to `size/2` has the added drawback, that your code won't handle odd-length strings correctly: just consider the string `"1"`: the length is `1`, so `size/2` is `0` and even if you resize the output string to the appropriate size, the char `'1'` won't be copied to the result. – fabian Jun 01 '23 at 17:59
  • ... Iterating from one end to the other you avoid this issue: `std::string result; result.reserve(str.size()); for (auto pos = str.end(), begin = str.begin(); pos != begin; ) { --pos; result.push_back(*pos); }` – fabian Jun 01 '23 at 18:02

2 Answers2

5

The original issue is that no space is ever reserved for std::string reversed in function reverse_string(). This creates and returns an empty std::string.

The operator[] performs no bounds checking. That's your first instance of undefined behavior.

Think of the number in brackets as a memory offset. If you don't switch them on, there are no checks to see if the offset is still within the chunk of memory owned by your string.

What we see in main() is a secondary problem. reverse is an empty string (because that's what reverse_string() always returns, see above). And reverse[0] (another out-of-bounds access and thus undefined behavior) is "!" because you incorrectly set it to this value.

To fix the problem, initialize reversed with a capacity of str.size() or simply as a copy of str.

To prevent such problems, turn on all compiler warnings and do a debug build.

Friedrich
  • 2,011
  • 2
  • 17
  • 19
1

I get the following error when running your code (after adding string header)

usr/src/debug/gcc/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/basic_string.h:1259: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::reference std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator[](size_type) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; reference = char&; size_type = long unsigned int]: Assertion '__pos <= size()' failed.
Aborted (core dumped)

Usually you'd get Segmentation fault, but here as you can see from the error message, Assertion '__pos <= size()' failed, some assertion failed. Thus, the program was aborted.

Invalid memory access is a common cause of Segmentation fault. It is undefined behavior.

Specifically in this case, the index is not within the range of the string object.

Replace the [] operator with .at(), which throws when the index is out of range. [] operator does not.

Debug the program either using a debugger (recommended) or manually to find out where this might be happening.

UmbQbify
  • 160
  • 10
  • *"Usually you'd get `Segmentation fault`"* -- Thanks to [SSO](https://stackoverflow.com/questions/10315041/meaning-of-acronym-sso-in-the-context-of-stdstring), it's actually unlikely you'd get a segmentation fault in this case. More likely, the first 24 characters would be written into the `std::string` object itself, which is valid memory. If you go beyond that, you're likely corrupting stack memory, which tends to cause problems later on, not at the time when the stack got corrupted, and the symptoms tend to be more varied than just being a segmentation fault. – JaMiT Jun 01 '23 at 14:23
  • @JaMiT Maybe that's why the program didn't actually crash on OP's system? – UmbQbify Jun 01 '23 at 14:27
  • I tried using .at() instead of [] along with the debugger. As soon as it enters the for loop and when it assigns reversed.at(i) = str.at((size-1)-i); it gives an out of range error. Why would this give an out of range error..? When the i = 0? – Jerry Jun 02 '23 at 01:22
  • See the other answer. I forgot to add that part @Jerry – UmbQbify Jun 02 '23 at 05:15