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?

gsamaras
  • 71,951
  • 46
  • 188
  • 305
anonymous
  • 141
  • 2
  • 14

4 Answers4

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.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • @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! :) – gsamaras Dec 14 '18 at 15:32
  • 2
    Happens to me all the time ;) Nice answer now :) – Matthieu Brucher Dec 14 '18 at 15:33
  • @gsamaras, can you please explain why my array length showed up to be 6? I didnt get that completely. – anonymous Dec 14 '18 at 16:07
  • This is what happens with Undefined Behavior @anonymous.. `strlen()` continued reading further from the memory allocated for your string, plus a/some character(s) that added two to the length, until it found a NULL (a zero let's say), in that case. – gsamaras Dec 14 '18 at 16:11
  • It could have been more than "two characters" after it read through my string of 4 characters until it found NULL? – anonymous Dec 14 '18 at 16:12
  • 1
    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 :) – gsamaras Dec 14 '18 at 16:14
  • 1
    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 – ChilliDoughnuts Dec 14 '18 at 16:15
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
Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62
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
gsamaras
  • 71,951
  • 46
  • 188
  • 305
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
-2

Instead of this char a[s.length()];

Do this char a[s.length() + 1]

bass king
  • 1
  • 1
  • 4
    No, for the same reason as to the answer below. That's not valid C++ – Ted Lyngmo Dec 14 '18 at 15:30
  • @HolyBlackCat Actually, gsmaras edited his answer which at first was completely wrong. It's more than probable that bass king wrote it whithout seeing edits to other answer. Also, while VLA are not valid C++, this is semi correct (missing setting 0) answer to the ASKED QUESTION which is "why garbage output and different length" – Kegluneq Dec 14 '18 at 15:36
  • @Kegluneq I can understand how this answer could be seen as answering the question, which is why it should also be ranked low so that noone actually goes ahead _solving_ their problems using it. – Ted Lyngmo Dec 14 '18 at 16:02