1

Why is there an extra character at the end of my string?

#include <iostream>
using namespace std;
int main() {
    int num;
    cin >> num;                                     // Reading input from STDIN
    cout << "Input number is " << num << endl;          // Writing output to STDOUT
    char c1, s2[10];
    for (int i=0; i<num; i++)
    {
         cin >> c1;
         if(c1==0){
             break;
         }
        s2[i] = c1;
    }
    cout <<"output= "<< s2;
}

output example

4                                                                                                                             
Input number is 4                                                                                                             
a l e x                                                                                                                       
output= alex@ 

Why is the "@" being added to the end of the string? At first i thought it was a random garbage value but every time I run the program its always the same symbol

  • 1
    @Atr0x You can't assign arrays with a size of a non-const variable on runtime in C++. – DLCom Jun 20 '20 at 12:06

4 Answers4

3

cout, when printing a c-string, expects it to zero terminated. Whereas you haven't done so for the array s2.

You can zero initialize the entire array:

char s2[10] = {};

Or just zero terminate the last byte:

  int i = 0;
  for (i=0; i<num; i++)
  {
      cin >> c1;
      if(c1==0) {
          break;
      }
      s2[i] = c1;
  }

  s2[i] = '\0';

In any case, you need to be wary of potential buffer overflow (e.g. if num is too large).

Alternatively, you can consider using std::string instead of a fixed length array.

P.P
  • 117,907
  • 20
  • 175
  • 238
  • If the `break` gets executed, the loop will break earlier than `num` passes, and `s2[num]` will be past the end of the input. – Pete Becker Jun 20 '20 at 15:07
  • True. But I doubt that OP intended to input null character via stdin. It looks more like a misunderstanding. – P.P Jun 20 '20 at 15:21
3

You're reading from a memory location that hasn't been initialized. By using an array of ten characters and only initializing the first four (or whatever else the number is), all other characters stay uninitalized. What data is actually read from an uninitialized location is undefined, meaning it's pretty much up to your compiler that chooses to read the equivalent value of "@" from that location. You can fix that issue by using a memory bit of the appropriate size. For this, you just replace the line

    char c1, s2[10];

with

    char c1;
    char* c2 = new char[num + 1] //num + 1 is necessary to contain a string terminator, see the other answers

this way, you dynamically allocate exactly the size you need.

Don't forget to delete[] c2; afterwards.

DLCom
  • 210
  • 1
  • 9
  • If the user enters a `0` prior to the end of the array, then it will still (potentially) print junk. – ChrisMM Jun 20 '20 at 12:57
  • This has nothing to do with the problem. The question asks about the case when `num` is 4, which fits in the statically allocated array. And even if it were larger, the allocation should be `num + 1` to allow for the nul terminator. – Pete Becker Jun 20 '20 at 15:03
  • It does have to do with the problem, actually. 4 *does* fit into the array, so the memory that gets printed is allocated. This doesn't mean, however, that the individual memory addresses are *initialized*. Combining those uninitialized addresses with the missing string terminator causes the problem OP describes. You're right, though, it should be num + 1. – DLCom Jun 20 '20 at 18:27
3

You are using a Character sequence well explained here.

By convention, the end of strings represented in character sequences is signaled by a special character: the null character, whose literal value can be written as '\0' (backslash, zero).

In this case, the array of 20 elements of type char called foo can be represented storing the character sequences "Hello" and "Merry Christmas" as:

enter image description here

Notice how after the content of the string itself, a null character ('\0') has been added in order to indicate the end of the sequence. The panels in gray color represent char elements with undetermined values.

I offer a c++17 solution with the constructor initialization although I may prefer either a dynamic array or std::string instead of a char. I also added a simple integer check that always should be used. Also a few versions of avoiding the use of the whole namespace std for various reasons, mostly to avoid unnecessary errors.

#include <iostream>
#include <limits> //numeric_limits

using std::cout, std::endl, std::cin; //<- explicit declared

int main() {
    int num;
    while(!(cin >> num)){  //check the Input format for integer the right way
        cin.clear();
        cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        cout << "Invalid input.  Try again: ";
      };

    cout << "Input number is " << num << endl;
    char c1, s2[num+1]{}; // Initialize with an empty string
    for (int i = 0; i < num; i++)
    {
        cin >> c1;
        if (c1 == 0) {
            break;
        }
        s2[i] = c1;
    }
    cout << "output= " << s2 << endl;

return 0;
}
Ingo Mi
  • 999
  • 12
  • 26
2

This happens because s2 is actually not a string and does not have the \0 character, which would mean the end of the string. Therefore, cout prints your string and will continue to move further in memory, byte by byte, interpreting each of them as a character to be output until it encounters the \0 character. In order to fix this, you can initialize s2 with an empty string, so the array will initially be completely filled \0.

#include <iostream>

using namespace std;

int main() {
    int num;
    cin >> num;
    cout << "Input number is " << num << endl;
    char c1, s2[10] = ""; // Initialize with an empty string
    for (int i = 0; i < num; i++)
    {
        cin >> c1;
        if (c1 == 0) {
            break;
        }
        s2[i] = c1;
    }
    cout << "output= " << s2;
}
Rustam D9RS
  • 3,236
  • 1
  • 10
  • 17