0

I have the following example, taken from here:

// strings and c-strings
#include <iostream>
#include <cstring>
#include <string>

int main ()
{
  std::string str ("Please split this sentence into tokens");

  char * cstr = new char [str.length()+1];
  std::strcpy (cstr, str.c_str());

  // cstr now contains a c-string copy of str

  char * p = std::strtok (cstr," ");
  while (p!=0)
  {
    std::cout << p << '\n';
    p = strtok(NULL," ");
  }

  delete[] cstr;
  return 0;
}

As far as I understand str is a string, str.c_str() is a pointer pointing to the first element of an array that contains characters of str as its elements. Then using std::strcpy we take the value of the address given as its second argument and assign this value to the pointer that is given as the first argument (cstr).

However, I have the following example, taken from here:

#include <iostream>
#include <cstring>

int main()
{
    char *str = new char[100];
    std::strcpy(str, "I am string!");
    std::cout << str;
    delete[] str;
}

And now as the second argument we have a string (and not a pointer to array as it was in the first example).

Can anybody, please, clarify this inconsistency?

Roman
  • 124,451
  • 167
  • 349
  • 456
  • 2
    For a bit of clarification: `"..."` is called a string literal and is *not* a `std::string`. You might be getting confused since `std::string` has a constructor which allows implicit conversion from character pointers, ie `std::string(char const* str)` – Pubby Apr 11 '13 at 08:06
  • Just for the record: `strtok` shouldn't be used in code that you have to maintain. (It's one of those functions like `gets`, that are there for historical reasons, but which shouldn't be used in new code.) – James Kanze Apr 11 '13 at 08:09
  • @Pubby, but why do we use a "string literal" as the second argument of `std::strcpy` in the second example, don't we need to use a pointer as the second argument (whose value will be passed to the first argument of `std::strcpy`)? – Roman Apr 11 '13 at 08:09
  • @Roman because string literals can be implicitly converted to `char const*`. How would you expect it to look? – Pubby Apr 11 '13 at 08:11
  • @Pubby, thank your for clarification. I did not know that `"..."` is interpreted as `char const*`, I thought that it is just a value of `string` type and we need to assign it to a variable (for example `x`) and that use `&x` as the second argument of `std::strcpy` to pass an address. But as I learned from you `"..."` is already an address (which is, to be honest, is a counterintuitive idea). For example, you would expect that 2 is just an integer value, not a pointer (and it is just a value, not a pointer). But, in contrast "abs" is not a value, it is already a pointer to an array. – Roman Apr 11 '13 at 08:24

4 Answers4

4
std::strcpy(str, "I am string!");

"I am string!"

Is string-literal. Really it's const char[13] (that is decaying to const char* when passing in function).

n3376 2.14.5/8

Ordinary string literals and UTF-8 string literals are also referred to as narrow string literals. A narrow string literal has type “array of n const char”, where n is the size of the string as defined below, and has static storage duration (3.7).

n3376 4.2/1 Implicit array to pointer conversion.

An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”. The result is a pointer to the first element of the array.

ForEveR
  • 55,233
  • 2
  • 119
  • 133
4

When using std::strcpy we take the value of the address given as its second argument and assign this value to the pointer that is given as the first argument (cstr).

char * strcpy ( char * destination, const char * source );

No strcpy actually read each character pointed by source and write them at destination, it stops when it reads a terminating null character.

In your second example, your source argument is a string-literal, which has a type const char[]. This string can be decayed into a const char* to be passed to strcpy.

A string literal is not much more than a pointer to a read-only location.

zakinster
  • 10,508
  • 1
  • 41
  • 52
  • Yes, I saw the cited explanation and this explanation is consistent with my first example. However, in the second example, we use string as the second argument and not a pointer whose values is an address. – Roman Apr 11 '13 at 08:04
  • As ForEver said, a string-literal is a const char[], so it can be decayed into a const char*. It's also a pointer to a read-only location. – zakinster Apr 11 '13 at 08:06
  • No, "I am string!" is also a pointer to an (unnamed) char array. – john Apr 11 '13 at 08:06
1

And now as the second argument we have a string (and not a pointer to array as it was in the first example)

In the second example you have a C string, which is a pointer to a NUL-terminated array of chars. There is no inconsistency.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • In the second example the second argument is "I am string!", which is just a string (as its value also says). It is not a C string. To get a C string we need to apply c_str() function to it. – Roman Apr 11 '13 at 08:06
  • @Roman: It *is* a C string, and you cannot apply `.c_str()` to it (try it!) – NPE Apr 11 '13 at 08:08
0

char *strcpy( char *dest, const char *src ); needs source pointer of const char and it copies the memory to destination pointer which is of type char. The function copy the string length from source untill it finds null terminated string of source. "I am string!" is a const char* const` which is a string literal mostly stored in read only marked memory.

Abhijit-K
  • 3,569
  • 1
  • 23
  • 31