-6

I'm revisiting C++ after a few years of C#, Javascript, web development etc.

There is a thread where it is explained that the major difference between these is that the at() method does bounds checking and throws an exception if the index provided is out of bounds.

What is the difference between string::at and string::operator[]?

However, that does not seem to justify the following behavior I am experiencing, perhaps someone could help me out?

#include <iostream>
#include <string>

using namespace std;

void remodel(string & str){
    string * ps = new string(str);

    ps->at(0) = 'n';
    cout<<*ps<<endl;
    delete ps;
}

int main(){
    string str = "Hello world";
    remodel(str);
    cin.get();
    return 0;
}

Output

nello world

In the above code, I use the at() method to change the first character of the string, and am successfully able to do so. Printing the string confirms this.

Something different happens when using the [] operator:

#include <iostream>
#include <string>

using namespace std;

void remodel(string & str){
    string * ps = new string(str);
    ps[0] = 'n';
    cout<<*ps<<endl;
    delete ps;
}

int main(){
    string str = "Hello world";

    remodel(str);

    cin.get();
    return 0;
}

Output

n

In the above code, using the [] operator on the index 0 replaces the entire string with the letter 'n'. This is confirmed in the debugger where I can see a complete reassignment of values from "Hello world" to "n"

Just to elaborate, if I place a breakpoint so the program stops just before executing ps[0] = 'n', then upon inspecting the variable ps, it seemingly stores an address that is used to reach the string "Hello world". After executing this line, however, the same address can only be used to reach the string/character "n".

My hypothesis was that using the [] operator results in a null character being placed just after specified index..but I have been unable to confirm this.

for example, in the above code using ps[0] I tried to print ps1, ps[2] just to see what would come.

What I got in output either a neverending (empty) output of what seemed like spaces, or a bunch of gibberish. It seems for my null character hypothesis for not to be the case. For good measure, I also tried to manually place a null character at some position like ps[10] but got a segmentation fault..the memory previously allocated to my string had gone out of bounds!

So, it appears I need a good revision on this topic, can someone explain whats going on? Please feel free to let me know if something in this question is vague or badly expressed, I'll do my best to fix it.

  • 9
    Don't use `string*`. Just use `string` directly. You weren't calling `string::operator[]`, but the built in `[]` operator for pointers – Justin Jun 04 '18 at 19:43
  • 2
    With `at` ["Bounds checking is performed, exception of type std::out_of_range will be thrown on invalid access."](https://en.cppreference.com/w/cpp/string/basic_string/at) – Fred Larson Jun 04 '18 at 19:44
  • "_In the above code, using the [] operator on the index 0 replaces the entire string with the letter 'n'_" It's because `ps[0]` doesn't do what you think it does. It **doesn't** even invoke the `operator[]` of `std::string`. In this case, `ps[0] = 'n'` is equivalent to `*ps = 'n'`. – Algirdas Preidžius Jun 04 '18 at 19:44
  • 2
    You need to deference the pointer before you can invoke the operator or use really goofy looking syntax. eg: `(*ps)[0] = 'n';` But prefer to not use the pointer or raw dynamic allocation. – user4581301 Jun 04 '18 at 19:45
  • 5
    For any array ***or pointer*** `p` and index `i`, the expression `p[i]` is equal to `*(p + i)`. With `ps[0]` you're dereferencing the pointer `ps` to get the first element in the "array" it points to. It is equal to `*ps = 'n'`. – Some programmer dude Jun 04 '18 at 19:46
  • `ps->operator[](0) = 'n';` is another way, if you are so inclined. – Mat Jun 04 '18 at 19:46
  • 1
    @Mat Or just `(*ps)[0] = 'n';` – Justin Jun 04 '18 at 19:47
  • 3
    Recommended reading: [Why should C++ programmers minimize use of 'new'?](https://stackoverflow.com/questions/6500313/why-should-c-programmers-minimize-use-of-new) – user4581301 Jun 04 '18 at 19:48
  • Thank you all! In all honesty, I guess I was not differentiating between the string [] operator and the pointer [] operator..in the sense that I was taking both to be the same thing. My key takeaway here is that they are quite distinct. In which case, in the particular example (*ps)[0] = 'n' would do what I actually was trying to do. All the responses have been enlightening. – user3233029 Jun 04 '18 at 20:34
  • Possible duplicate of [What is the difference between string::at and string::operator\[\]?](https://stackoverflow.com/questions/14699060/what-is-the-difference-between-stringat-and-stringoperator) – phuclv Jul 02 '19 at 02:14
  • @phuclv No. This question is about the difference between string::at and the builtin operator[]. – L. F. Jul 02 '19 at 08:51

1 Answers1

3

Your second program is malformed. It's not using std::string::operator[] at all.

string * ps = new string(str);
ps[0] = 'n';

Not only does std::string support the [] operator, every pointer to a type also supports the [] operator. It's how C style arrays work, and it's what you're doing in the code above.

ps isn't a string. It's a pointer. And ps[0] is the one string, not unlike *ps.

You probably wanted this instead:

#include <iostream>
#include <string>

using namespace std;

void remodel(string & str){
    string * ps = new string(str);
    (*ps)[0] = 'n';
    // or: ps->operator[](0) = 'n';
    cout<<*ps<<endl;
    delete ps;
}

int main(){
    string str = "Hello world";

    remodel(str);

    cin.get();
    return 0;
}

Or, more idiomatically, use this instead:

#include <iostream>
#include <string>

using namespace std;

void remodel(string & str){
    string ps = str;
    ps[0] = 'n';
    cout<<ps<<endl;
}

int main(){
    string str = "Hello world";

    remodel(str);

    cin.get();
    return 0;
}
Drew Dormann
  • 50,103
  • 11
  • 109
  • 162
  • why not pass `str` by value and remove the `ps`? – 463035818_is_not_a_number Jun 04 '18 at 20:16
  • well depends if OP wanted to modify `str` or not, you dont – 463035818_is_not_a_number Jun 04 '18 at 20:17
  • There are certainly a lot of refinements that could be made to the code beyond "Why isn't this doing what I expect?" ... I started sliding down that slope myself. – Drew Dormann Jun 04 '18 at 20:23
  • Thanks for the answer. tbh, I think this question itself culminated from me going off on a tangent while following a book section on the auto_ptr. To open the problem, the book put forward the remodel function (but with only the first line similar to mine), and I kind of started sliding down from there... – user3233029 Jun 04 '18 at 20:49