37

Can someone please explain to me why strcpy() is necessary to assign strings to character arrays, such as in the following code snippet.

int main(void) {

char s[4];

s = "abc"; //Fails
strcpy(s, "abc"); //Succeeds

return 0;
}

What is the reason that s = "abc" fails? And why is strcpy() the only way to assign strings to char arrays after they have been declared? It seems strange to me that you have to use a function to carry out a basic assignment.

C_p678
  • 437
  • 1
  • 5
  • 5

4 Answers4

39

Arrays in C are non-assignable and non-copy-initializable. That's just how arrays are in C. Historically, in value context (on the RHS of assignment) arrays decay to pointers, which is what formally prevents assignment and copy-initialization. This applies to all arrays, not only to char arrays.

C language inherits this arrays behavior from its predecessors - B and BCPL languages. In those languages arrays were represented by physical pointers. (And obviously re-assignment of pointers is not what you'd want to happen when you assign one array to another.) In C language arrays are not pointers, yet they do "simulate" the historical behavior of B and BCPL arrays by decaying to pointers in most cases. This historical legacy is what keeps C arrays non-copyable to this day.

One exception from the above is the initialization with a string literal. I.e. you can do

char c[] = "abc";

in which case conceptually we are copying string literal "abc" to array c. Another exception is array wrapped into a struct type, which is copied when the whole struct object is copied. And that's about it.

This means that whenever you want to copy a naked (non-wrapped) array, you have to use a library-level memory copying function, like memcpy. strcpy is just a flavor of that specifically tailored to work with strings.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 1
    Just to clarify, all array types can be initialized with a proper initializer of the form `{ val0, val1, ... }`. – Jens Gustedt Aug 01 '11 at 21:29
  • You don't *have* to use a library function; you can assign individual characters, e.g. `for (char *dst = s, *src = "abc"; *dst++ = *src++;) ;`. The library function is a better choice though, as it is easier to read and may be optimized for the system. – M.M Jan 23 '15 at 21:01
  • 1
    Yeah, to touch more on what @AnT said, `strcpy()` is almost exactly like `memcpy()`, except that it includes the null-byte. – RastaJedi Apr 18 '16 at 00:25
15

That's simply what arrays are in C. You can't assign to them. You can use pointers if you like:

char *p;
p = "abc";

Incidentally, there is a C FAQ.

Arrays are ``second-class citizens'' in C; one upshot of this prejudice is that you cannot assign to them.

cnicutar
  • 178,505
  • 25
  • 365
  • 392
  • Yeah I do use pointers, I just don't understand why s = "abc" doesn't work in my example. s is a char array, and so is "abc"... – C_p678 Aug 01 '11 at 16:03
  • 5
    @C_p678 - no, `s` is a char array, "abc" is a pointer to constant string. – MByD Aug 01 '11 at 16:03
  • 3
    @MByD: Not entirely correct. `"abc"` is not a pointer. `"abc"` an array of type `char[4]`, which in this context decays to a pointer of type `char *`. Note, that in C the string is not constant. It is non-modifiable all right, yet the type itself does not include `const` qualifier. – AnT stands with Russia Aug 01 '11 at 16:09
  • 2
    @AndryT: To be even pickier, "const" and "constant" are two very different things. "const" probably should have been called "readonly". A constant, or a constant expression, is one that can be evaluted at compile time; a const object is one that cannot be modified at runtime. Consider `const int r = rand();`. – Keith Thompson Aug 02 '11 at 03:03
4

Short answer: historical reasons. C never had a built in string type. It wasn't until C++ came along that std::string came into being, and even that did not arrive with the first implementations

Long answer: the type of "abc" is not char[], but rather char *. strcpy is one mechanism with which you can copy the data that the pointer points at (in this case that's ABC).

strcpy isn't the only way to initialize an array, however, it is smart enough to detect and respect the terminating 0 at the end of the string. You could also use memcpy to copy the string into s but that requires you pass in the length of the data to be copied, and to ensure the terminating 0 (NULL) is present in s

BubbleMaster
  • 184
  • 2
  • 10
Jeff Paquette
  • 7,089
  • 2
  • 31
  • 40
0

The C language lacks any convenient syntax for getting a pointer to a string literal along with an indication of its length. Some languages including many Pascal dialects prefix each string with a byte reporting its length; this works nicely for many purposes, but limits string literals to 255 characters. C's approach allows string literals of any length to be accommodated, but adds only a single byte of overhead regardless of length.

Zero-terminated strings are inferior to other forms for almost every purpose other than string literals, but literals are so far and away the most common form of string that many programs will have to deal with, and thus there is considerable advantage to having library functions deal with them effectively; it then becomes easier to use zero-terminated strings in cases where they are less than ideal than to have a separate set of library routines for other types.

supercat
  • 77,689
  • 9
  • 166
  • 211