Rooney10
Rooney10

Reputation: 31

Modifying the length and contents of the string?

To change the contents of a string in a function such that it reflects in the main function we need to accept the string as reference as indicated below.

Changing contents of a std::string with a function

But in the above code we are changing the size of string also(i.e, more than what it can hold), so why is the program not crashing ?

Program to convert decimal to binary, mind it, the code is not complete and I am just testing the 1st part of the code.

void dectobin(string & bin, int n)
{

  int i=0;

  while(n!=0)
  {
     
     bin[i++]= (n % 2) + '0';
     n = n / 2;
   }

  cout << i << endl;

  cout << bin.size() << endl;

  cout << bin << endl;
}

int main()
{
   string s = "1";
   dectobin(s,55);
   cout << s << endl;
   return 0;
}

O/p: 6 1 1 and the program crashes in codeblocks. While the above code in the link works perfectly fine.

It only outputs the correct result, when i initialize the string in main with 6 characters(i.e, length of the number after it converts from decimal to binary).

http://www.cplusplus.com/reference/string/string/capacity/

Notice that this capacity does not suppose a limit on the length of the string. When this capacity is exhausted and more is needed, it is automatically expanded by the object (reallocating it storage space). The theoretical limit on the length of a string is given by member max_size

If the string resizes itself automatically then why do we need the resize function and then why is my decimal to binary code not working?

Upvotes: 1

Views: 691

Answers (5)

Rajeev Atmakuri
Rajeev Atmakuri

Reputation: 888

The bounds of the string are limited by its current content. That is why when you initialise the string with 6 characters you will stay inside bounds for conversion of 55 to binary and program runs without error. The automatic expansion feature of strings can be utilised using std::string::operator+= to append characters at the end of current string. Changed code snippet will look like this:

void dectobin(string & bin, int n){
//...
bin += (n % 2) + '0';
//...
}

Plus you don't need to initialise the original string in main() and your program should now run for arbitrary decimals as well.

int main(){
//...
string s;
dectobin(s,55);
//...
}   

Upvotes: 0

Daniel Jour
Daniel Jour

Reputation: 16156

Accepting a reference to a string makes it possible to change instances of strings from the calling code inside the called code:

void access(std::string & str) {
  // str is the same instance as the function
  // is called with.
  // without the reference, a copy would be made,
  // then there would be two distinct instances
}

// ...
std::string input = "test";
access(input);
// ...

So any function or operator that is called on a reference is effectively called on the referenced instance.

When, similar to your linked question, the code

str = " new contents";

is inside of the body of the access function, then operator= of the input instance is called.

This (copy assignment) operator is discarding the previous contents of the string, and then copying the characters of its argument into newly allocated storage, whose needed length is determined before.

On the other hand, when you have code like

str[1] = 'a';

inside the access function, then this calls operator[] on the input instance. This operator is only providing access to the underlying storage of the string, and not doing any resizing.

So your issues aren't related to the reference, but to misusing the index operator[]:

Calling that operator with an argument that's not less than the strings size/length leads to undefined behaviour.

To fix that, you could resize the string manually before using the index operator.

As a side note: IMO you should try to write your function in a more functional way:

std::string toOct(std::string const &);

That is, instead of modifying the oases string, create a new one.

Upvotes: 0

john
john

Reputation: 87959

Your premise is wrong. You are thinking 1) if I access a string out of bound then my program will crash, 2) my program doesn't crash therefore I can't be accessing a string out of bounds, 3) therefore my apparently out of bounds string accesses must actually resize the string.

1) is incorrect. Accessing a string out of bounds results in undefined behaviour. This is means exactly what it says. Your program might crash but it might not, it's behaviour is undefined.

And it's a fact that accessing a string never changes it's size, that's why we have the resize function (and push_back etc.).

We must get questions like yours several times a week. Undefined behaviour is clearly a concept that newbies find surprising.

Upvotes: 2

Alex Lop.
Alex Lop.

Reputation: 6875

Check this link about std::string:

      char& operator[] (size_t pos); 
const char& operator[] (size_t pos) const;

If pos is not greater than the string length, the function never throws exceptions (no-throw guarantee). Otherwise, it causes undefined behavior.

In your while loop you are accessing the bin string with index that is greater than bin.size()

Upvotes: 1

mort
mort

Reputation: 13588

You aren't changing the size of the string anywhere. If the string you pass into the function is of length one and you access it at indices larger than 0, i.e., at bin[1], bin[2], you are not modifying the string but some other memory locations after the string - there might be something else stored there. Corrupting memory in this way does not necessarily directly lead to a crash or an exception. It will once you access those memory locations later on in your program.

Upvotes: 0

Related Questions