strcpy() 是什么?
strcpy() 是 C 标准库 <string.h> 中的一个函数,它的全称是 string copy(字符串复制),它的核心功能是将源字符串(source string)的内容完整地复制到目标字符串(destination string)中,并在目标字符串的末尾自动添加一个空字符 '\0'。

函数原型
在使用 strcpy() 之前,你需要在代码文件的开头包含头文件 <string.h>。
#include <string.h> // 必须包含的头文件 char *strcpy(char *dest, const char *src);
参数详解:
-
dest(destination - 目标):- 这是一个指向字符数组的指针,也就是目标字符串的起始地址。
- 必须有足够的空间来容纳源字符串的内容,否则会导致缓冲区溢出,这是非常严重的安全漏洞。
- 它的类型是
char *,并且没有被const修饰,意味着函数可以修改这个指针指向的内容。
-
src(source - 源):- 这是一个指向常量字符数组的指针,也就是源字符串的起始地址。
- 函数会从这个地址开始读取字符,直到遇到空字符
'\0'为止。 - 它的类型是
const char *,意味着函数承诺不会修改这个指针指向的内容。
返回值:
strcpy()函数会返回目标字符串dest的起始地址(也就是dest指针的值)。- 这个返回值的主要用途是允许函数调用被链接在一起(链式调用),
strcpy(strcpy(dest1, src), src2)。
工作原理
strcpy() 的工作流程非常简单:

- 从
src指向的地址开始读取字符。 - 将读取到的字符依次写入到
dest指向的地址中。 - 每写入一个字符,
src和dest指针都会自动向后移动一个位置。 - 当从
src读取到空字符'\0'时,复制过程停止。 - 将这个
'\0'也写入到dest的当前位置。
图示:
初始状态:
dest: [ ][ ][ ][ ][ ] (未初始化的内存)
src: H e l l o \0
复制过程:
步骤1: dest[0] = 'H'
dest: [H][ ][ ][ ][ ]
src: e l l o \0
步骤2: dest[1] = 'e'
dest: [H][e][ ][ ][ ]
src: l l o \0
... (继续)
步骤5: dest[4] = 'o'
dest: [H][e][l][l][o]
src: \0
步骤6: dest[5] = '\0' (复制结束)
dest: [H][e][l][l][o][\0]
src: (已到达末尾)
代码示例
示例 1:基本用法
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!"; // 源字符串
char dest[20]; // 目标字符串,确保空间足够
// 将 src 的内容复制到 dest 中
strcpy(dest, src);
printf("源字符串 src: %s\n", src);
printf("目标字符串 dest: %s\n", dest);
return 0;
}
输出:
源字符串 src: Hello, World!
目标字符串 dest: Hello, World!
重要的注意事项(⚠️ 警告)
这是 strcpy() 最关键的部分,也是初学者最容易犯错的地方。
缓冲区溢出
strcpy() 不会检查目标缓冲区 dest 的大小,如果源字符串 src 的长度(包括 '\0')超过了目标缓冲区 dest 的容量,多出来的字符就会溢出,覆盖掉 dest 之后内存空间的数据,导致程序崩溃、数据损坏或严重的安全漏洞。

错误示例:
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "This is a very long string that will cause a buffer overflow!";
char dest[10]; // 目标缓冲区太小了!
// 危险!这行代码会引发缓冲区溢出
strcpy(dest, src);
printf("目标字符串 dest: %s\n", dest); // 输出是不可预测的,程序可能已经崩溃
return 0;
}
后果:
- 程序可能直接崩溃(段错误)。
- 程序可能继续运行,但
dest之后的数据(如其他局部变量)被破坏。 - 攻击者可以利用此漏洞执行任意代码。
目标缓冲区必须可写
dest 必须是一个字符数组(分配在栈上或堆上),或者是一个指向动态分配内存的指针。不能是一个字符串字面量,因为字符串字面量通常存储在只读的内存区域(如程序的代码段)。
错误示例:
#include <stdio.h>
#include <string.h>
int main() {
// "Hello" 是一个字符串字面量,存储在只读内存区
char *dest = "Hello";
char src[] = "World";
// 错误!尝试修改只读内存,会导致程序崩溃(段错误)
strcpy(dest, src);
printf("dest: %s\n", dest);
return 0;
}
正确做法:
int main() {
// 使用字符数组,它存储在可写的栈内存中
char dest[] = "Hello";
char src[] = "World";
strcpy(dest, src); // 正确
printf("dest: %s\n", dest); // 输出: World
return 0;
}
目标缓冲区必须足够大
即使 dest 是一个字符数组,也必须确保其大小足够容纳 src 的内容。
错误示例:
int main() {
char src[] = "12345";
char dest[4]; // 大小是4,只能存3个字符 + '\0'
strcpy(dest, src); // 危险!需要6个字节的空间('1','2','3','4','5','\0')
return 0;
}
更安全的替代方案
正是因为 strcpy() 存在缓冲区溢出的风险,C 标准库提供了更安全的版本。
strncpy()
strncpy() 允许你指定最大复制的字符数,从而防止溢出。
char *strncpy(char *dest, const char *src, size_t n);
n: 是要复制的最大字符数。- 优点:可以防止缓冲区溢出。
- 缺点:
src的长度小于n,dest的剩余部分不会被自动用'\0'填充,可能会包含垃圾数据。src的长度大于或等于n,dest的字符串将不会以'\0',这会导致后续使用字符串的函数(如printf("%s", dest))越界读取,同样是危险的。
strncpy() 的正确用法(手动添加 '\0'):
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello";
char dest[10];
// 最多复制 9 个字符,为 '\0' 留出空间
strncpy(dest, src, 9);
// 重要!src 非常长,strncpy 不会添加 '\0',所以必须手动添加
dest[9] = '\0';
printf("dest: %s\n", dest);
return 0;
}
snprintf() (推荐)
这是现代 C 编程中最推荐使用的安全函数之一。
int snprintf(char *str, size_t size, const char *format, ...);
str: 目标缓冲区。size: 目标缓冲区的大小(包括为'\0'预留的空间)。format: 格式字符串,后面跟着要写入的变量。- 优点:
- 绝对安全:它会确保写入的字符数(包括
'\0')永远不会超过size。 - 功能更强大,不仅可以复制字符串,还可以格式化输出。
- 绝对安全:它会确保写入的字符数(包括
snprintf() 示例:
#include <stdio.h>
int main() {
char src[] = "Hello, snprintf!";
char dest[10];
// 安全地将 src 复制到 dest,最多写入 9 个字符
// snprintf 会自动在末尾添加 '\0'
snprintf(dest, sizeof(dest), "%s", src);
printf("dest: %s\n", dest); // 输出: Hello, sn
return 0;
}
在这个例子中,sizeof(dest) 是 10。snprintf 最多会写入 9 个字符(从 src 复制过来的字符),然后第 10 个位置会自动放上 '\0',完全避免了溢出风险。
| 函数 | 原型 | 安全性 | 特点 |
|---|---|---|---|
strcpy() |
char *strcpy(char *dest, const char *src); |
不安全 | 简单易用,但极易导致缓冲区溢出。 |
strncpy() |
char *strncpy(char *dest, const char *src, size_t n); |
相对安全 | 可限制长度,但需手动处理 '\0',否则仍有风险。 |
snprintf() |
int snprintf(char *str, size_t size, ...); |
非常安全 | 强烈推荐,自动处理长度和 '\0',功能强大。 |
核心建议:
- 永远不要在新的代码中使用
strcpy(),除非你 100% 确定源字符串的长度绝对安全,并且你完全清楚其风险。 - 优先使用
snprintf(),它是现代 C 语言中最安全、最灵活的字符串复制/格式化函数。 - 如果必须使用
strncpy(),请务必记得手动在目标字符串的末尾添加'\0'。
