-1

I am studying c++, In a blog they introduced the concept of copy function. When I tried the same in my system, the result is not matching to what I expected. Please let me know what I did wrong here in the below code.

#include <iostream>

main(){

std::string statement = "I like to work in Google";
char compName[6];
statement.copy(compName, 6, 18);

std::cout<<compName;
}

I expected Google but actual output is Googlex

I am using windows - (MinGW.org GCC-6.3.0-1)

Samer
  • 123
  • 1
  • 8
  • That's because you're calling _undefined behavior_. – πάντα ῥεῖ May 04 '19 at 00:27
  • `compName` must be null-terminated before you pass it to `std::cout`. Otherwise, your program is literally meaningless according to the C++ Standard – alter_igel May 04 '19 at 00:29
  • @πάνταῥεῖ what do you mean undefined behavior? sorry I don't know c++. How to solve it? – Samer May 04 '19 at 00:29
  • @alterigel Oh okay. How to terminate it? – Samer May 04 '19 at 00:30
  • You need to make enough space for the terminating null character (`0` or `'\0'`) and make sure that it gets written. https://softwareengineering.stackexchange.com/questions/181505/what-is-a-null-terminated-string – alter_igel May 04 '19 at 00:32
  • All of this should be fully explained [in every good C++ book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). The best way to learn C++ is with a good book. Asking a single question and then waiting days for an answer, will simply take too long. C++ is the most complicated general purpose programming language in use today. – Sam Varshavchik May 04 '19 at 00:41
  • Undefined Behaviour: You can write code that is syntactically correct, but for one reason or another, the Standard does not define the results. Usually this happens where there is a note in the Standard document that says NEVER DO THIS. Since you should never to that, the standard doesn't bother specifying what happens if you do it. They leave it up to the people writing the C++ compiler to do whatever they want to do. Typically nothing is done and the program runs faster because it doesn't have non compliance tests. It's left to the programmer to include such tests if they require them – user4581301 May 04 '19 at 00:43
  • If you're learning C++, try not to use `char[]` arrays; at least until you need them. – Mirko May 04 '19 at 02:37

2 Answers2

3

You are confusing a sequence of characters, C style string, and std::string. Let's break them down:

  1. A sequence of characters is just that, one character after another in some container (in your case a C style array). To a human being several characters may look like a string, but there is nothing in your code to make it such.
  2. C style string is an array of characters terminated by a symbol \0. It is a carry over from C, as such a compiler will assume that if even if you don't tell it otherwise the array of characters may potentially be such a string.
  3. C++ string (std::string) is a template class that stores strings. There is no need to worry how it does so internally. Although there are functions for interoperability with the first two categories, it is a completely different thing.

Now, let's figure out how a compiler sees your code:

char compName[6];

This creates an array of characters with enough space to store 6 symbols. You can write C style strings into it as long as they are 5 symbols or less, since you will need to also write '\0' at the end. Since in C++ C style arrays are unsafe, they will allow you to write more characters into them, but you cannot predict in advance where those extra characters will be written into memory (or even if your program will continue to execute). You can also potentially read more characters from the array... But you cannot even ask the question where that data will be coming from, unless you are simply playing around with your compiler. Never do that in your code.

statement.copy(compName, 6, 18);

This line writes 6 characters. It does not make it into a C style string, it is simply 6 characters in an array.

std::cout<<compName;

You are trying to output to the console a C style string... which you have not provided to a compiler. So a an operator<< receives a char [], and it assumes that you knew what you were doing and works as if you gave it C string. It displays one character after another until it reaches '\0'. When will it get such a character? I have no idea, since you never gave it one. But due to C style arrays being unsafe, it will have no problem trying to read characters past the end of an array, reading some memory blocks and thinking that they are a continuation of your non-existent C style sting.

Here you got "lucky" and you only got a single byte that appeared as an 'x', and then you got a byte with 0 written in it, and the output stopped. If you run your program at a different time, with a different compiler, or compiled with different optimisations you might get a completely different data displayed.

So what should you have done?

You can try this:

#include <iostream>
#include <string>

int main()
{

  std::string statement = "I like to work in Google";
  char compName[7]{};
  statement.copy(compName, 6, 18);

  std::cout<<compName;

  return 0;
}

What did i change? I made an array able to hold 7 characters (leaving enough space for a C style string of 6 characters) and i have provided an empty initialisation list {}, which will fill the array with \0 characters. This means that when you will replace the first 6 of them with your data, there will be a terminating character in the very end.

Another approach would be to do this:

#include <iostream>
#include <string>

int main()
{

  std::string statement = "I like to work in Google";
  char compName[7];
  auto length = statement.copy(compName, 6, 18);
  compName[length] = '\0';

  std::cout<<compName;

  return 0;
}

Here i do not initialise the array, but i get the length of the data that is written there with a .copy method and then add the needed terminator in the correct position.

What approach is best depends on your particular application.

v010dya
  • 5,296
  • 7
  • 28
  • 48
1

When inserting pointer to a character into the stream insertion operator, the pointer is required to point to null terminated string.

compName does not contain the null terminator character. Therefore inserting inserting (a pointer to an element of) it into a character stream violates the requirement above.

Please let me know what I did wrong here

You violate the requirement above. As a consequence, the behaviour of your program is undefined.

I expected Google but actual output is Googlex

This is because the behaviour of the program is undefined.

How to terminate it?

Firstly, make sure that there is room in the array for the null terminator character:

char compName[7];

Then, assign the null terminator character:

compName[6] = '\0';
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Hey yes its working. Thanks for the answer, it worked. Just out of curiosity, why I have 2 downvotes? some thing wrong with my question? – Samer May 04 '19 at 00:54
  • @Samer I think that some people felt that it was a trivial question to find an answer for. I do not think so, so i have upvoted you, but somebody else downvoted and you are back at -2. – v010dya May 04 '19 at 01:02