strcpy,strncpy函数详解

 strcpy函数

在C语言中,strcpy()函数用于将一个字符串复制到另一个字符串中。

函数原型如下:

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

参数解释:

  • destination:目标字符串,将会被复制到。
  • source:源字符串,将会被复制到目标字符串中。

函数返回值:

  • 返回指向目标字符串的指针。

场景一:

#include <stdio.h>
#include <string.h>
 
int main()
{
    char arr[10] = "########";
    printf("%s\n", strcpy(arr,"hello"));
 
    return 0;
}

输出的结果

hello

场景二: 

#include <stdio.h>
#include <string.h>
 
int main()
{
    char arr1[10] = "**********";
    char arr2[10] = "abcd";
    printf("%s\n", strcpy(arr1, arr2));
    return 0;
}

输出结果

abcd

注意点

1.源字符必须以 '\0'结束:

#include <stdio.h>
#include <string.h>
 
int main()
{
    char arr1[10] = "**********";
    char arr2[10] = { 'a','b','c','d' };
    printf("%s\n", strcpy(arr1,arr2));
 
    return 0;
}


这里的代码会出错,'\0'是停止拷贝的终止条件,arr2字符数组所在的内存空间后面存储的内容并不知道,不遇到 '\0' 拷贝就不会停止,这就会导致越界访问,程序就会出现问题。

2.目标空间必须足够大,以确保能存放得下放源字符串

#include <stdio.h>
#include <string.h>
 
int main()
{
    char arr1[5] = "*****";
    char arr2[] = "hello world";
    printf("%s\n", strcpy(arr1,arr2));
 
    return 0;
}


 这里虽然拷贝成功并将结果输出了,但程序却崩溃了。目标空间太小,不足以放置拷贝的源字符串,会造成溢出的情况

3.目标空间必须可变

#include <stdio.h>
#include <string.h>
 
int main()
{
    char* str1 = "hello world";
    char str2[10] = "*********";
    printf("%s\n", strcpy(str1,str2));
 
    return 0;
}


这里的程序也出现了错误。str1指向的是常量字符串,是不可以被修改掉的,目标空间必须是可以被修改的,因为要将拷贝的字符串放在目标空间中。而源字符串可以是能够修改的、也可以是不能修改的,因为strcpy函数的第二个参数已经用const关键字修饰了,保证了拷贝过程中不会被修改。

模拟实现

strcpy函数的模拟实现方式可以有多种,这主要取决于你对函数安全性、性能以及内存操作的不同需求。以下是几种常见的实现方式:

1. 基本实现

这是最直接的实现方式,它逐个复制源字符串的字符到目标字符串,直到遇到源字符串的结束符\0。

 char *my_strcpy(char *dest, const char *src) {
 assert(dest&&str);
  
 char *orig_dest = dest; // 保存dest的原始指针  
   while (*src != '\0') {  
 *dest++ = *src++;  
 }  
   // 添加结束符'\0'  
 *dest = '\0';  
   // 返回原始dest指针  
 return orig_dest;  
 } 

2. 指针算术实现

这种实现方式使用指针算术来简化复制过程,减少了对dest的多次解引用。

 char *my_strcpy_pointer_arithmetic(char *dest, const char *src) {
 assert(dest&&str);  
 
char *orig_dest = dest;  
   while ((*dest++ = *src++) != '\0');  
   return orig_dest;  
 } 

3. 考虑安全性的实现

为了避免缓冲区溢出,你可以在实现中检查目标字符串dest的缓冲区大小。然而,strcpy函数本身并不检查缓冲区大小,这是其不安全的地方。一个更安全的版本是strncpy,但如果你想要模拟实现一个带缓冲区大小检查的strcpy,可以这样做:

 char *my_safe_strcpy(char *dest, const char *src, size_t dest_size) {
 assert(dest&&str);
  
 char *orig_dest = dest;  
 size_t i;  
   // 确保目标缓冲区至少有1个字节的空间以存储'\0'  
 if (dest_size == 0) {  
 return NULL;  
 }  
   for (i = 0; i < dest_size - 1 && src[i] != '\0'; ++i) {  
 dest[i] = src[i];  
 }  
   // 添加结束符'\0'并确保不会超出目标缓冲区  
 dest[i] = '\0';  
   return orig_dest;  
 } 

在这个实现中,我们传递了一个额外的参数dest_size来表示目标字符串dest的缓冲区大小。我们确保在复制过程中不会超出这个大小,并在最后添加一个结束符\0。

注意事项:

  1. 基本实现和指针算术实现都没有检查目标缓冲区的大小,因此它们可能导致缓冲区溢出。在实际应用中,应该避免使用这些不安全的实现,除非你能确保目标缓冲区足够大。
  2. 考虑安全性的实现通过检查目标缓冲区的大小来防止缓冲区溢出,但这也增加了函数的复杂性。在性能要求较高的场景中,可能需要权衡安全性和性能。
  3. 在实际编程中,通常建议使用标准库提供的strcpy、strncpy等函数,并根据需要选择适当的安全措施,如确保目标缓冲区足够大或使用更安全的字符串处理函数。

strncpy函数

strncpy 是 C 语言标准库中的一个函数,用于将源字符串的前 n 个字符(包括空字符 \0,如果源字符串在 n 个字符之前结束)复制到目标字符串中。

与 strcpy 不同,strncpy 不会自动在目标字符串的末尾添加空字符 \0,除非源字符串的长度小于或等于 n

因此,在使用 strncpy 时,通常需要手动添加空字符以确保目标字符串是一个有效的 C 字符串。

它的原型如下:

char *strncpy(char *dest, const char *src, size_t n);

其中,dest是目标字符串的指针,src是源字符串的指针,n是要复制的字符数。

strncpy函数会将src指向的字符串的前n个字符复制到dest指向的字符串中,并在复制完成后返回dest的指针。

注意点

strncpy不会自动向目标空间追加‘\0’

如果复制的字符数n大于src指向的字符串的长度,那么dest指向的字符串会被'\0'字符填充,直到复制完n个字符为止。

如果n小于src指向的字符串的长度,那么dest指向的字符串不会被终止符'\0'填充,而且可能不是一个有效的C字符串。

示例代码如下:

#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "Hello, World!";
    char dest[20];

    strncpy(dest, src, 5);
    dest[5] = '\0';

    printf("Copied string: %s\n", dest);

    return 0;
}

这段代码将src字符串的前5个字符复制到dest字符串中,并手动添加了终止符'\0'。最后输出的结果为"Hello"。

目标空间必须足够大

如果n小于src指向的字符串的长度,那么dest指向的字符串不会被终止符'\0'填充,而且可能不是一个有效的C字符串。

我们上面举了例子,就不多说了

模拟实现

strncpy函数的模拟实现方式可以有多种,但基本的思路都是按照strncpy的定义来进行:复制源字符串的前n个字符到目标字符串,并确保目标字符串至少包含n个字符(如果需要的话,用空字符\0填充剩余部分)。以下是几种可能的模拟实现方式:

1. 基本实现

这是最直接的模拟实现方式,按照strncpy的定义逐字符复制,并在需要时添加空字符\0。

 #include <stddef.h> // 包含 size_t 的定义  
   char *my_strncpy_basic(char *dest, const char *src, size_t n) {
 assert(dest&&str);  
 
char *orig_dest = dest;  
 size_t i;  
   for (i = 0; i < n && src[i] != '\0'; ++i) {  
 dest[i] = src[i];  
 }  
   // 如果还没有达到 n 个字符,用 '\0' 填充剩余部分  
 for (; i < n; ++i) {  
 dest[i] = '\0';  
 }  
   return orig_dest;  
 } 

2. 优化版实现

在某些情况下,如果知道源字符串的长度不会超过n,可以稍微优化这个过程,避免不必要的空字符填充。

 char *my_strncpy_optimized(char *dest, const char *src, size_t n) { 
 assert(dest&&str);
 
 char *orig_dest = dest;  
 size_t i;  
   for (i = 0; i < n && src[i] != '\0'; ++i) {  
 dest[i] = src[i];  
 }  
   // 如果源字符串自身长度小于 n,确保目标字符串以 '\0' 结尾  
 if (src[i] == '\0') {  
 dest[i] = '\0';  
 }  
   return orig_dest;  
 } 

3. 指针算术实现

使用指针算术可以简化循环内部的索引操作,使得代码更简洁。

 char *my_strncpy_pointer_arithmetic(char *dest, const char *src, size_t n) {
 assert(dest&&str);
  
 char *orig_dest = dest;  
 const char *src_end = src + n; // 计算 src 中要复制的字符的结束位置  
   // 复制字符直到达到 n 个字符或遇到 src 的结束符 '\0'  
 while (src < src_end && *src != '\0') {  
 *dest++ = *src++;  
 }  
   // 用 '\0' 填充剩余部分  
 while (dest < orig_dest + n) {  
 *dest++ = '\0';  
 }  
   return orig_dest;  
 } 

注意事项:

  1. 无论采用哪种实现方式,都需要确保目标缓冲区dest有足够的空间来存储至少n个字符,包括结尾的空字符\0。如果dest的空间不足,可能会导致缓冲区溢出。
  2. 在实际应用中,还需要考虑错误处理,比如当dest或src为NULL时应该怎么做。
  3. 在性能敏感的场合,可以根据实际情况选择最合适的实现方式。例如,如果源字符串通常很长,使用指针算术可能更有效率;如果源字符串通常较短,基本的循环实现可能就足够了。
  4. 这些模拟实现都是基于标准strncpy函数的行为,并假设调用者已经正确地处理了缓冲区大小和空指针等问题。在真实环境中使用时,还需要添加适当的错误检查和边界条件处理来确保程序的健壮性。

与strcpy的区别

strncpystrcpy都是C语言中的字符串处理函数,它们的主要功能都是复制字符串,但它们在处理字符串的方式上有一些重要的区别。

  1. 复制长度

    • strcpy函数会复制源字符串的所有字符,直到遇到空字符\0为止。这意味着如果源字符串的长度超过了目标字符串的缓冲区大小,那么strcpy可能会导致缓冲区溢出,这是一个常见的安全问题。
    • strncpy函数则复制源字符串的前n个字符到目标字符串中,无论是否遇到空字符\0。如果源字符串的长度小于n,那么strncpy会在目标字符串的剩余位置填充\0,直到复制了n个字符。如果源字符串的长度大于或等于n,strncpy不会添加额外的\0,这可能会导致目标字符串不是一个有效的C字符串(即不以\0结尾)。因此,在使用strncpy时,通常需要手动检查并添加\0,以确保字符串的正确性。
  2. 安全性

    • 由于strcpy不会检查目标缓冲区的大小,因此它更容易导致缓冲区溢出。这种溢出可以被恶意利用,造成严重的安全问题。
    • strncpy虽然在一定程度上可以避免缓冲区溢出(如果正确使用,并且n不超过目标缓冲区的大小),但它并不总是生成有效的C字符串。因此,在使用strncpy时,需要特别注意确保目标字符串的正确性。

总的来说,虽然strcpystrncpy都用于复制字符串,但它们在处理字符串的方式和安全性上有显著的不同。在编写涉及字符串操作的代码时,应根据具体情况选择适当的函数,并确保正确使用它们,以避免潜在的安全问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/583357.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Stable Diffusion 参数介绍及用法

大模型 CheckPoint 介绍 作用&#xff1a;定调了作图风格&#xff0c;可以理解为指挥者 安装路径&#xff1a;models/Stable-diffusion 推荐&#xff1a; AnythingV5Ink_v32Ink.safetensors cuteyukimixAdorable_midchapter2.safetensors manmaruMix_v10.safetensors counterf…

2024年的Java版本选择?java 17 安装

文章目录 2024年的Java版本选择&#xff1f;java 1.8 和 java17 什么区别&#xff1f;java 17 安装windows 11安装java 17C:\Program Files\Common Files\Oracle\Java\javapath是什么 2024年的Java版本选择&#xff1f; 3年前&#xff0c;java 1.8是市场主流&#xff08;还有一…

STM32用HAL库函数实现硬件IIC

/*出处&#xff1a;【STM32入门教程-2024】第12集 IIC通信与温湿度传感器AHT20(DHT20)_哔哩哔哩_bilibili */ AHT20驱动 这篇笔记我主要介绍代码实现&#xff0c;想要了解原理的请自己看视频&#xff0c;我不过多赘述了。 AHT20通信数据帧格式&#xff1a; ①对照手册上的通…

面对网络安全,做好风险评估对企业会带来哪些帮助

随着信息技术的飞速发展&#xff0c;网络安全问题日益凸显&#xff0c;成为企业不容忽视的重要议题。企业作为社会经济活动的主要参与者&#xff0c;其网络安全不仅关系到自身的生存与发展&#xff0c;更与国家的经济安全、社会稳定息息相关。因此&#xff0c;企业必须高度重视…

K8s: Prometheus 服务结构以及基础抓取数据服务部署

Prometheus 发布应用之后&#xff0c;就有持续运维的事情&#xff0c;就是平台监控Prometheus 是一个云原生的日志监控平台&#xff0c;是一个实时标准的一个技术它是著名的 cncf 里的一个重要的开源项目 上面整个图片是在云原生应用及K8s应用架构下的一个日志监控的一个标准的…

ezplot--Matlab学习

目录 一、代码 二、效果 ​编辑 三、ezplot讲解 四、如何自定义一个函数 一、代码 clc; clear; t0:32; x4(t) cos(2*pi*t/4).*sin(2*pi*t/4); x8(t) cos(2*pi*t/8).*sin(2*pi*t/8); x16(t) cos(2*pi*t/16).*sin(2*pi*t/16); subplot(3,1,1) ezplot(x4,[0,32]); subplot…

《软件设计师教程:数据库系统基础知识大总结》

​ 个人主页&#xff1a;李仙桎 &#x1f525; 个人专栏: 《软件设计师》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ​ ⛺️前言&#xff1a;各位铁汁们好啊&#xff01;&#xff01;&#xff01;今天继续正式学习中级软件设计师考试相关的内容&#xff0c;后续不断更新…

python学习笔记B-11:序列结构之列表--二维列表的遍历和生成式

二维列表的遍历方式&#xff0c;使用双层for循环&#xff0c;遍历索引号。 二维列表的生成式&#xff0c;也是使用类似双层循环的形式生成。 print("##初始化二维列表&#xff0c;每个元素就是1个列表") lst [["东方延续","太空军自然选择号舰长&qu…

【AI心理咨询应用】继Woebot之后,国内诞生的“LLM+CBT”应用:白小喵

导言 AI认知行为疗法&#xff08;Cognitive Behavioral Therapy&#xff0c;CBT&#xff09;早在2017年便有了首例&#xff0c;即美国知名CBT治疗机器人Woebot。 然而&#xff0c;Woebot在CBT的完整落地上仍有缺陷问题&#xff0c;LLM的出现促进了对该问题的解决&#xff0c;…

typeScript 安装

1、安装typescript 安装npm i -g typescript 查看是否安装成功 tsc -v 2、使用ts // 浏览器不支持ts 需要编译成 es5 let str: string ts 在终端输入 tsc index.ts 会将其生成一个对应的index.js文件 在电脑上首次使用TS的时候&#xff0c;执行TS 的命令的时候报错 打开PowerS…

RustGUI学习(iced)之小部件(三):如何使用下拉列表pick_list?

前言 本专栏是学习Rust的GUI库iced的合集&#xff0c;将介绍iced涉及的各个小部件分别介绍&#xff0c;最后会汇总为一个总的程序。 iced是RustGUI中比较强大的一个&#xff0c;目前处于发展中&#xff08;即版本可能会改变&#xff09;&#xff0c;本专栏基于版本0.12.1. 概述…

2024年,新手做抖音小店想要赚钱,必须明白三件事!

大家好&#xff0c;我是电商糖果 有不少小店的商家都说过&#xff0c;现在的抖音小店比三四年前复杂了。 三四年前抖音小店刚刚出现&#xff0c;平台规则还没有那么多&#xff0c;很多机制也不太成熟。 那个时期的抖店说是捡钱的&#xff0c;一点儿都不假。 但是如果说你现…

Linux详解:进程等待

文章目录 进程等待等待的必要性进程等待的方法waitwaitpid获取子进程status阻塞等待 与 非阻塞等待 进程等待 等待的必要性 子进程退出&#xff0c;父进程不进行回收的话&#xff0c;就可能造成僵尸进程&#xff0c;进而造成内存泄露 如果进程进入了僵尸状态&#xff0c;kill…

机器学习:驱动现代交通运输革命的AI智慧引擎

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

玄子Share-引导过程与服务控制

玄子Share-引导过程与服务控制 Linux操作系统引导过程 系统初始化进程 init 进程 由 Linux 内核加载运行 /sbin/init 程序init 进程是系统中第一个进程init 进程的 PID&#xff08;进程标记&#xff09;号永远为 1 Systemd Systemd是Linux操作系统的一种init软件CentOS7中采用…

【Linux开发 第十二篇】搭建JavaEE环境

搭建开发环境 搭建javaEE环境 搭建javaEE环境 在Linux下开发JavaEE需要安装软件包&#xff1a; 安装jdk 安装步骤&#xff1a; 在opt目录下创建jdk目录通过xftp上床到jdk目录中进入到jdk目录中&#xff0c;解压jdk压缩包在/usr/local下创建java目录将解压完成的jdk文件移动…

SpringBoot框架学习笔记(一):依赖管理和自动配置

本文为个人笔记&#xff0c;仅供学习参考之用&#xff0c;如有不当之处请指出。 本文基于springboot2.5.3版本&#xff0c;开发环境需要是 jdk 8 或以上&#xff0c;maven 在 3.5 1 SpringBoot 基本介绍 1.1 官方文档 &#xff08;1&#xff09; 官网 : https://spring.io/pr…

张朝阳对话华为Fellow陈海波:万物智联时代,鸿蒙如何实现“换道超车”?

随着智能终端设备的普及和万物智联时代的加速到来&#xff0c;鸿蒙生态的高速发展正引发全行业的关注。 搜狐创始人、董事局主席兼CEO、物理学博士张朝阳与华为Fellow、基础软件首席科学家陈海波带来了一场关于鸿蒙生态的公开课。鸿蒙技术架构有哪些领先性?HarmonyOS发布5年来…

compose调用系统分享功能分享图片文件

compose调用系统分享功能图片文件 简介UI界面提供给外部程序的文件访问权限创建FileProvider设置共享文件夹 通用分享工具虚拟机验证结果参考 本系列用于新人安卓基础入门学习笔记&#xff0c;有任何不同的见解欢迎留言 运行环境 jdk17 andriod 34 compose material3 简介 本案…

Hadoop3:集群搭建及常用命令与shell脚本整理(入门篇,从零开始搭建)

一、集群环境说明 1、用VMware安装3台Centos7.9虚拟机 2、虚拟机配置&#xff1a;2C&#xff0c;2G内存&#xff0c;50G存储 3、集群架构 从表格中&#xff0c;可以看出&#xff0c;Hadoop集群&#xff0c;主要有2部分&#xff0c;一个是HDFS服务&#xff0c;一个是YARN服务 …
最新文章