11

I've done a bit of basic reading and from what I've gathered .c_str() always has a null terminator.

I have a fairly simple C++ program:

int main(int argc, char** argv)
{
  std::string from = "hello";
  char to[20];
  memcpy(to, from.c_str(), strlen(from.c_str())+1);
  std::cout<< to << std::endl;
  return 0;
}

Will that memcpy ensure that I copy over a null-terminated string to my variable to (provided that my string from is shorter in length)?

Max
  • 113
  • 1
  • 1
  • 6

4 Answers4

8

You should use std::string to copy strings. However, if you want to do it like that you should use strcpy instead of memcpy

int main(int argc, char** argv)
{
  std::string from = "hello";
  char to[20];
  strcpy(to, from.c_str());
  std::cout<< to << std::endl;
  return 0;
}
ronag
  • 49,529
  • 25
  • 126
  • 221
5

memcpy doesn't know what is a string. you give it a range to copy. it depends on strlen here to provide the termination point of range

Neel Basu
  • 12,638
  • 12
  • 82
  • 146
2

Yes, this will work as long as your string in from is shorter than 20. Oh, no, wait, we are also copying the NULL terminator so it must be shorter than 19. I guess you see how that can lead to some confusion.

Which is by the way exactly the reason why this code is dangerous: I am assuming this is demo code and your actual code will get that string from some sort of input. At that moment you will not be able to control how long it is. You can truncate it but you might forget to do that which means that your program will be copying content to memory that possibly does not belong to it. This might lead to a crash but at least to undefined behaviour as you are overwriting memory that might contain other important data.

Using the string class actually helps to avoid such problems by not having to specify the string length. I would suggest using this class and only do operations involving c_str() when absolutely necessary.

Chris
  • 6,914
  • 5
  • 54
  • 80
0

The answer to your question is "yes" (as long as you char array is big enough, you should put a verification step).

If you really want to do this, you can do:

int main(int argc, char** argv)
{
  std::string from = "hello";
  char* to = new char[from.length() + 1];
  strcpy(to, from.c_str()); ///Or memcpy(to, from.c_str(), from.length() + 1 );
  std::cout<< to << std::endl;
  delete[] to;
  return 0;
}

Which is safer as long as you are not writing another, longer string into "to"

Antonio
  • 19,451
  • 13
  • 99
  • 197
  • Hello Does this solve the possible size limit problems which was 20 in previous example? why do you use delete? why do you use dynamic memory allocation? – Meric Ozcan Feb 03 '21 at 13:02
  • 1
    @MericOzcan 1) Yes 2) In order to free the memory after we have finished using it. We need `delete[]` because we used `new[]` 3) It is the only correct way to allocate a buffer whose size is not known at compile time – Antonio Feb 03 '21 at 14:42