8.2.2.2. strcpy

Time: 00:01:06 | Download: Large, Large (CC), Small | Streaming, Streaming (CC) | Slides (PDF)

Given two C-strings defined as char* s1 and char* s2, the statement s1 = s2; compiles without error. So, copying a C-string with the assignment operator appears straightforward. However, when used with pointer operands, including C-strings, the assignment operator copies the address in the right-hand operand to the left-hand operand - see Figure 1(b), which illustrates pointer assignment. Specifically, the assignment operator does not copy the string text to which the pointer points. Copying a string is still a necessary operation, and so the C-string library provides a function to perform the task: strcpy(s1, s2);.

strcpy: String-Copy

Two C-strings represented as sequences of squares. String s1 stores the characters 'EXAMPLE', and string s2 stores 'HELLO'. The picture illustrates the copy operation as 'H' in s2 replacing the first 'E' in s1; 'E' in s2 replacing 'X' in s1, until '\0' in s2 replaces the 'L' in s1.

strcpy(s1, s2)

Copying C-Strings. The source (the second argument) is copied character-by-character (including the null termination character) to the destination (the first argument). If the source is shorter than the destination, the characters following the copied null terminator become irrelevant. For example, the null terminator in s2[5] overwrites the 'L' in s1[5], which makes the 'E' and the null terminator at positions 6 and 7 in s1 irrelevant because after the copy, s1 logically ends with the null terminator at position 5. The strcpy function is unusual in that it is not necessary to null terminate the destination, s1 in the example, before calling the function.
Header File:
#include <cstring>
Standard Prototype:
char* strcpy(char* destination, const char* source);
Please see strcpy for more information
Microsoft Prototype:
errno_t strcpy_s(char* dest, size_t size, const char* source);
Returns 0 when the copy succeeds; returns non-0 on failure.
Please see strncpy_s for more information

Examples

char* s1;
char s2[15] = "Hello world";
strcpy(s1, s2);
char s1[5];
char s2[15] = "Hello world";
strcpy(s1, s2);
(a)(b)
Common strcpy errors.
  1. char* does not allocate memory to store the copied C-string.
  2. Although s1 is defined as an array, it's too small to hold all of the s2 characters.
The strcpy function does not require s1 to have a null termination character.
Standard Version Microsoft Version
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;

int main()
{
	char s1[100] = "EXAMPLE";
	char* s2 = "HELLO";

	cout << strcpy(s1, s2) << endl;
	cout << s1 << endl;

	return 0;
}
#include <iostream>
#include <cstring>
using namespace std;

int main()
{
	char s1[100] = "EXAMPLE";
	char* s2 = "HELLO";

	cout << strcpy_s(s1, 100, s2) << endl;
	cout << s1 << endl;

	return 0;
}
 
Output:
HELLO
HELLO
0
HELLO
(a)(b)
The strcpy function. The string-copy function copies its second argument to its first. Both arguments are passed by pointer, but the second argument is const and can't be modified. The standard and Microsoft versions return the copied string through the first argument.
  1. The standard version returns s1 as the return value, making the copied C-string available a second way.
  2. The Microsoft version returns an error condition: 0 when the function succeeds and non-0 when it fails.

Possible Implementations

char* strcpy(char* dest, const char* source)
{
	for (size_t i = 0; i <= strlen(source); i++)
		dest[i] = source[i];

	return dest;
}

 
char* strcpy(char* dest, const char* source)
{
	char* s = dest;

	while (*(s++) = *(source++))
		;

	return dest;
}
(a)(b)
Implementations of the standard strcpy function.
  1. A straightforward implementation using a for-loop and array notation (i.e., the index operator []) to copy the contents of one C-string array to another. Notice the use of <= rather than < - the additional iteration copies the null terminator at the end of source to destination.
  2. Although the function only has three statements, understanding what they do is challenging. To begin, recall that pass-by-pointer involves two variables or bits of data: the local pointer variable and the original data to which it points (see Figure 4), a C-string in this example. The use of the const keyword with the second argument prevents the function from changing the original C-string, but the function can change the local pointer variable source. The function can change dest and the C-string to which it points. Saving the address stored in dest to s preserves that address for the return statement.

    Turning our attention to the while-loop, we see that the loop has a null statement, indicated by the semicolon below the loop. So, it does all the work in the loop test inside the parentheses. We see the same pattern on both sides of the assignment operator. To help understand that pattern, notice the use of the post-increment operator; so, we first use the value in the variable, and then increment the value. Initially, source and dest point to the first character in their respective C-strings; following the increment operation, they point to the second character, and so on until the loop reaches the end of source.

    To get the individual characters, we must dereference each C-string. The inner or grouping parentheses are necessary because the dereference operator has higher precedence than the auto-increment operator. Without the parentheses, the increment operator would increment the character (e.g., 'A' + 1 = 'B') rather than the pointer. So, the loop extracts a character from source and assigns it to dest. It then increments both pointers to the next characters in the strings and repeats the copy. The loop continues until it copies the '\0' at the end of source to dest. The '\0' is the character-equivalent of 0, which ends the loop (see Boolean Type and Values).