3

I was trying to rotate a string circularly by 1 shift. Here's the simple code:

#include <bits/stdc++.h>
using namespace std;

int main() {
  string s = "1010";
  char a[s.length()];
  for (int i = 0; i < s.length() - 1; i++) {
    a[i] = s[i+1];
  }
  a[s.length()-1] = s[0];
  std::cout << a << '\n';
  std::cout << strlen(a) << '\n';
}

When I run this code, I get the following output:

aditya@aditya-Inspiron-3558:~/miscCodes$ ./a.out 
0101�
6

How's my array's length is changing? And due to garbage values?

4
  • 4
    This is not valid C++ char a[s.length()]; Commented Dec 14, 2018 at 15:21
  • On top of out of bounds access, you have to null-terminate C-strings to use them with std::cout and strlen Commented Dec 14, 2018 at 15:22
  • On top of those 2 comments above, you should also null-terminate your C-style string. Commented Dec 14, 2018 at 15:22
  • 1
    char a[s.length() + 1] = {0}; will fix your code. Commented Dec 14, 2018 at 15:22

3 Answers 3

10

Variable Length Arrays (VLA) are not part of Standard C++. Read more in Why aren't variable-length arrays part of the C++ standard?


But let's say, that you use a compiler extension that allows them, then the problem is that you use a C function here:

std::cout << strlen(a) << '\n';

which expects a C string, which means a NULL-terminated string.

That means that you should make your array big enough to hold the NULL termination character, like this:

char a[s.length() + 1];

since string::length() will return 4 for the string "1010". That means that the C string should be this: "1010\0", i.e. the actual string, appended with the NULL terminating character. As a result, you would need an array of size 5 to store that string.

An easy fix would be:

char a[s.length() + 1] = {0};

which will NULL initialize every cell of the array. Then you will overwrite every cell of it with characters, except from the last cell, specially reserved for the NULL terminator.

Another approach would be to only assign the NULL terminator to the last cell of your string, like a[s.length()] = '\0';. Notice how s.length() now is the index to the last element of your array.


Standard C string functions (like strlen()) depend on the NULL termination character to mark the end of the string. In the absence of that important character, they do not know when to stop, thus accessing memory beyond from the point they are meant to visit.

That invokes Undefined Behavior (UB), which, in your computer, is accessing memory with garbage values.

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

7 Comments

@MatthieuBrucher this is what happens when you have an event of 5 hours in work. Thank you very much for the downvote that alerted me! :)
Happens to me all the time ;) Nice answer now :)
@gsamaras, can you please explain why my array length showed up to be 6? I didnt get that completely.
Yes @anonymous, you cannot tell for sure what it would have been (this is what happens with Undefined Behavior). For example, in your computer, it's 6, in mine it could be another number (even a correct number if I was unlucky (in the sense that I wasn't going to be alerted)), and on TedLyngmo's computer 42 :)
Yes, it could read for three, four, or any amount of characters past the array. That is what happens with undefined behavior. edit: ok everyone beat me to it
|
8

First, your code is not valid C++, as you are using Variable Length Arrays. Use an std::vector instead:

std::vector<char> a(s.length() + 1, 0); // Adding +1 to add space for the 0-terminated string

for (int i = 0; i < a.size() - 2; i++) { // Because of the null terminator and the first offset
  a[i] = s[i+1];
}
a[a.size()-2] = s[0];

Then after output using data:

std::cout << a.data() << '\n';
std::cout << a.size() << '\n'; // Will give you +1 because we give the size of the container and not thew size of the string

5 Comments

In your for loop, wouldn't it be for(int i = 0; i < s.length()-1;i++) ?
Anyways if s = "1010", our vector a contains "010", please check it out.
That's the consequence, the assignment for 1 must also be -2.
Sorry, didn't get you
Modified my answer: a[a.size()-2] = s[0]; otherwise the last element is not updated.
4

You've already gotten excellent answers so this is just an add-on.

#include <bits/stdc++.h> is not a standard header file and it will make you lazy since it includes all that you probably need and a lot more. Include only the headers you need, especially if you are going to do using namespace std;, which is also a bad idea.

Apart from that, to solve the problem of rotating elements in your string, take a look at std::rotate. It can rotate not only strings, but std::vectors etc. Example doing a left rotate one step:

#include <iostream>
#include <algorithm> // std::rotate

int main() {
    std::string s = "1234";
    std::string cpy = s;

    //          first elem   new first elem   last elem
    std::rotate(cpy.begin(), cpy.begin() + 1, cpy.end());
    std::cout << s.size() << " " << s << "\n";
    std::cout << cpy.size() << " " << cpy << "\n";
}

Output

4 1234
4 2341

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.