strcpy与memcpy以及strncpy

本文详细介绍了strcpy、memcpy和strncpy三个函数的功能与区别。包括它们如何实现字符串和内存的复制,以及使用时需要注意的问题。

1. strcpy函数

   strcpy提供了字符串的复制。即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符。

   函数原型及实现:

  1. char* strcpy(char* strDst, const char* strSrc)      
  2. {  
  3.     assert((strDst != NULL) && (strSrc != NULL));  
  4.     char* address = strDst;   
  5.     while((*strDst++ = *strSrc++) != '/0');  
  6.     return address;  
  7.   }  
  

 

  注意:

  1. 该函数会连同字符串的结束字符'/0'一起拷贝到字符数组中,故字符数组的长度应该至少是字符串的长度加1。

  例:

  char str[] = "123456";

  这里str是一个字符数组,它存放了一个字符串"123456",由于字符串还有一个结束符"/0",所以此数组的长度为7而不是6。

 

   char *str = "123456";  //该字符串的长度为6(字符串以字符'/0'结尾,不计入字符串长度)

   char   dst[7];   //字符数组的长度必须至少为字符长度加1,如6+1=7。

   strcpy(dst, str);

  2. 该函数会拷贝字符串的内容直至遇到第一个字符值为0的字符(第一个字符值为0的字符也会被拷贝),故如果一个字符串或字符数组含

     有大量的值为0的数据,则不宜用该函数进行拷贝操作,可用memcpy函数。

 

2. memcpy函数

   memcpy提供了一般内存的复制。即memcpy对于需要复制的内容没有限制,因此用途更广。

   该函数将一个大小为size的内存段的值拷贝到另一内存段中。

   其实现如下:

  1. void *memcpy(void *memTo, const void *memFrom, size_t size)     
  2. {  
  3.     assert((memTo != NULL) && (memFrom != NULL)); //memTo和memFrom必须有效  
  4.     char *tempFrom = (char *)memFrom;             //保存memFrom首地址  
  5.      char *tempTo = (char *)memTo;                  //保存memTo首地址  
  6.     while(size -- > 0)                //循环size次,复制memFrom的值到memTo中  
  7.         *tempTo++ = *tempFrom++ ;   
  8.     return memTo;   
  9. }  
  

 

 

3. strcpy与memcpy的区别

  3.1 复制的内容不同。

     strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。

  3.2 复制的方法不同。

     strcpy不需要指定长度,它遇到字符串结束符"/0"便结束。memcpy则是根据其第3个参数决定复制的长度。

  3.3 用途不同。

     通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy。

 

4. strncpy

strncpy的实现如下

  1. char *strncpy(char *dst, const char *src, size_t count)  
  2. {  
  3.         assert((dst != NULL) && (src != NULL));  
  4.         char *tmp = dst;  
  5.   
  6.         while (count-- && (*dst++ = *src++) != '/0')  
  7.         {  
  8.                 /* nothing */;  
  9.         }  
  10.   
  11.         return tmp;  
  12. }  

 

该函数用于拷贝count个字符。

 

注意:

1. count一定要小于dst的大小。

2.调用完该函数后一定要加上一句:dst[count] = '/0';否则不安全,如strlen等函数要求参数必须是以'/0'结尾的字符串。

   因为当count小于src的大小时,src的结束字符'/0'并不会被拷贝,故应该为dst加上一个结束符。

例:

  1. char *str = "123456";  
  2.   
  3. char dst[7];  
  4.   
  5. int count = 6;  
  6.   
  7. strncpy(dst, str, count);  //count=6一定要小于dst的长度(7)。  
  8.   
  9. dst[count] = '/0';  
        

在 C 语言中,`strcpy`、`strncpy` 和 `memcpy` 是用于内存或字符串复制的常用函数。它们都定义在 `<string.h>` 头文件中,但用途和安全性有显著区别。 下面详细解释这三个函数的用法、差异、潜在风险及安全替代方案,并给出示例代码。 --- ### 1. `strcpy` **功能:** 将一个字符串(包括结尾的 `\0`)复制到另一个字符数组中。 **原型:** ```c char *strcpy(char *dest, const char *src); ``` **特点:** - 不检查目标缓冲区大小 - 一直复制直到遇到源字符串的结束符 `\0` - **容易造成缓冲区溢出(不安全)** #### 示例: ```c #include <stdio.h> #include <string.h> int main() { char dest[10]; const char *src = "Hello"; strcpy(dest, src); // 安全,因为 "Hello" 长度为 5 + \0 = 6 < 10 printf("dest: %s\n", dest); return 0; } ``` ⚠️ **危险示例:** ```c const char *src = "This string is too long!"; strcpy(dest, src); // 缓冲区溢出!未定义行为 ``` --- ### 2. `strncpy` **功能:** 复制最多 `n` 个字符从 `src` 到 `dest`。 **原型:** ```c char *strncpy(char *dest, const char *src, size_t n); ``` **特点:** - 可指定最大复制长度 `n` - 如果 `src` 长度小于 `n`,则用 `\0` 填充剩余空间 - 如果 `src` 长度大于等于 `n`,**不会自动添加 `\0`** → 可能导致非空终止字符串 #### 示例: ```c #include <stdio.h> #include <string.h> int main() { char dest[10]; strncpy(dest, "Hello World", sizeof(dest) - 1); // 安全做法 dest[sizeof(dest) - 1] = '\0'; // 手动确保结尾为 \0 printf("dest: %s\n", dest); // 输出: Hello Wor return 0; } ``` ✅ **最佳实践使用 `strncpy`:** ```c strncpy(dest, src, sizeof(dest) - 1); dest[sizeof(dest) - 1] = '\0'; // 强制补 \0 ``` ⚠️ 注意:`strncpy` 并非完全安全,因为它不保证结果是有效的 C 字符串(缺少 `\0`)。 --- ### 3. `memcpy` **功能:** 复制 `n` 个字节的原始内存数据,不限于字符串。 **原型:** ```c void *memcpy(void *dest, const void *src, size_t n); ``` **特点:** - 按字节复制,不关心是否是字符串 - 不检查 `\0`,也不做任何填充 - 适用于结构体、数组等任意内存块复制 - 若用于字符串且 `n` 错误,可能导致缺失 `\0` #### 示例: ```c #include <stdio.h> #include <string.h> int main() { char src[] = "Copy Me!"; char dest[20]; memcpy(dest, src, strlen(src) + 1); // +1 包含 \0 printf("dest: %s\n", dest); return 0; } ``` ⚠️ 错误用法: ```c memcpy(dest, src, 5); // 只复制前5个字符,可能没有 \0 printf("%s", dest); // 危险!如果 dest 没有 \0,行为未定义 ``` --- ### 对比总结表: | 函数 | 是否处理字符串 | 是否保证 `\0` 结尾 | 安全性 | 适用场景 | |------------|----------------|--------------------|------------|------------------------------| | `strcpy` | ✅ | ✅ | ❌ 不安全 | 已知目标足够大时 | | `strncpy` | ✅ | ❌(需手动加) | ⚠️ 较安全 | 固定长度缓冲区复制 | | `memcpy` | ❌(通用内存) | ❌(必须自己控制) | ✅(可控) | 结构体、二进制数据、带长字符串 | --- ### 推荐的安全替代方案 现代编程推荐使用更安全的函数: #### ✅ `strlcpy`(BSD/Linux,部分系统支持) ```c size_t strlcpy(char *dest, const char *src, size_t size); ``` - 总是确保 `\0` 结尾 - 返回所需总长度,便于判断是否截断 #### ✅ `strcpy_s`(C11 Annex K,MSVC 支持较好) ```c errno_t strcpy_s(char *dest, rsize_t destsz, const char *src); ``` - 更严格的安全检查 - 需要传入目标缓冲区大小 #### 示例(MSVC 或启用了安全扩展): ```c strcpy_s(dest, sizeof(dest), src); ``` --- ### 完整对比代码示例: ```c #include <stdio.h> #include <string.h> int main() { char buf1[10], buf2[10], buf3[10]; const char *long_str = "TooLongString"; // ❌ strcpy: 危险 // strcpy(buf1, long_str); // 缓冲区溢出! // ✅ strncpy: 控制长度,但要手动补 \0 strncpy(buf2, long_str, sizeof(buf2) - 1); buf2[sizeof(buf2) - 1] = '\0'; // ✅ memcpy: 精确控制字节数 + 手动加 \0 size_t len = sizeof(buf3) - 1; memcpy(buf3, long_str, len); buf3[len] = '\0'; printf("buf2: %s\n", buf2); printf("buf3: %s\n", buf3); return 0; } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值