[c语言]将strcpy()函数从低端到高端的实现

C语言结构体数组:从原理到实战的完整开发指南 在C语言程序设计中,数据结构是组织和存储数据的核心机制。结构体(struct)作为一种复合数据类型,允许将不同类型的数据成员封装为一个逻辑整体,实现了数据的自定义打包。数组则提供了对同类型元素的连续存储和高效随机访问能力。将两者结合形成的结构体数组,在内存中以连续块的形式存储多个结构体实例,既保持了数组的遍历效率,又具备了结构体的数据建模灵活性。这一技术组合在工程实践中价值显著,尤其适用于需要管理批量、多属性实体数据的场景,如学生信息管理、传感器数据采集和游戏角色属性维护。通过qsort函数对结构体数组进行 阅读详情

简介

  本文将实现库函数strcpy,并将低端的写法到高端的写法进行演示讲解。使自己写的strcpy()函数不再那么low!!!

正文

  我们要实现strcpy()函数,就先要了解这个函数是干什么用的;strcpy()函数是用来拷贝字符串的,在函数中有两个形参,一个源字符串,还有一个目标字符串,使用拷贝函数将源字符串中的内容拷贝到目标字符串并返回目标字符串,这样就完成了拷贝。
  那么我们来实现,首先我们根据逻辑写,给形参传递源字符串的首地址和目标字符串的首地址。然后将源字符串中的字符一个一个赋给目标字符串,一直到’\0’结束。
代码如下:

//1.low逼代码
#include<stdio.h>
void my_strcpy(char *dest, char *str)
{
	 while(*str != '\0')
	 {
	  	*dest = *str;
	  	dest++;
	  	str++;
	 }
 *dest = *str;//赋值结束,将'\0'赋给目标字符串,此时的str指向的就是'\0'
}
int main()
{
 	char *p = "hello world";
	char arr[30] = {0};
 	my_strcpy(arr,p);
 	puts(arr);
 	return 0;
}

这样代码就算完成了,但是这种代码其实很low,为什么呢?我们来看看下面这段代码!!!

//2.还是比较low逼的
#include<stdio.h>
void my_strcpy(char *dest, char *str)
{
 	while(*dest++ = *str++)
	{
 		 ;
 	}
}
int main()
{
 	char *p = "hello world";
 	char arr[30] = {0};
 	my_strcpy(arr,p);
 	puts(arr);
 	return 0;
}

我们将while循环里的内容放进了判断部分,这样是不是就简洁了许多,这样的代码省去了很多麻烦,在while循环进行判断的同时顺便将赋值操作也进行了,在赋值进行到结束字符时,也就是0,条件为假,跳出循环,同时赋值也完成了,这样的代码是不是更胜一筹呢?不,这种代码还是比较low的。
  当我们的源字符串为空(NULL)呢?这个时候程序就会报错!那怎么办呢?看下面这种改进!!

//较高分代码
#include<stdio.h>
#include<assert.h>
void my_strcpy(char *dest, char *str)
{
 	assert(str != NULL);//断言
 	assert(dest != NULL);
 	//if(str == NULL)
 	// return;
 	while(*dest++ = *str++)
 	{
  		;
 	}
}
int main()
{
 	char *p = "hello world";
 	char arr[30] = {0};
 	my_strcpy(arr,p);
 	puts(arr);
 	return 0;
}

  在while循环之前加上断言assert();提前将错误杜绝在编译的时候,加上断言有助于程序猿发现这些难以发现的错误,比如,当源字符串指向空指针的时候,这个时候将空指针赋给目标字符串,那么这个时候如果不加断言,程序猿就很难发现程序中的错误。如果加上断言,那么在编译的时候,程序就会报错,并且报出错误的位置,减去了很多不必要的麻烦。
  但是在这如果不用断言,而用if语句进行判断,如果源字符串指向空指针,就直接return;,这样讲道理是可以的,并且没有任何问题的,但是一个程序给用户用的话,用户用的是release版本的,我们程序猿用的是debug版本的,如果用了断言assert,那么在release版本中,编译器会自动将assert语句优化掉,但是if语句并不会优化掉,所以在release版本中if语句是一直存在的,这样断言assert的优势就显示出来了。
  这样是不是就是高分代码了?算是。但是我们还能继续提升我们的这段代码的逼格。看下面

#include<stdio.h>
#include<assert.h>
void my_strcpy(char *dest, const char *str)//加上const保护不用改变的变量
{
 	assert(str != NULL);
 	assert(dest != NULL);
 	while(*dest++ = *str++)
 	{
  		;
 	}
}
int main()
{
 	char *p = "hello world";
 	char arr[30] = {0};
 	my_strcpy(arr,p);
 	puts(arr);
 	return 0;
}

  我们在形参中源字符串前加了const,就保护了源字符串不被改变,假如我们在复制的时候不小心将目标字符串和源字符串的位置写反了,那么就是将目标字符串的内容拷贝到源字符串中了,这样就适得其反了。
  在源字符串前加上const就会完美的规避这种情况,如果写反,那么编译的时候就会报错,并且让我们很快的就找到问题所在。
  这样的代码没毛病,但是还是有一点点小瑕疵的,我们来看看完美的代码!!!

#include<stdio.h>
#include<assert.h>
char *my_strcpy(char *dest, const char *str)
{
 	char *ret = dest;//将目标空间的起始地址存在ret中
 	assert(str != NULL);
 	assert(dest != NULL);
 	while(*dest++ = *str++)
 	{
  		;
 	}
 return ret;//返回目标空间的起始地址
}
int main()
{
 	char *p = "hello world";
 	char arr[30] = {0};
 	my_strcpy(arr,p);
 	puts(arr);
 	return 0;
}

  我们可以在MSDN中搜索一下库函数strcpy()函数,结果如下
在这里插入图片描述
我们可以看到库函数类型并不是我们之前写的void,而是char*类型的
那我们再看看函数的返回值

在这里插入图片描述
我们可以看到返回的是目标字符串
  我们再将这几处一修改,这样的代码就是完美的代码了,毫无瑕疵。
问题来了,为什么要用char*类型呢?为什么要有返回值呢?
答案就是为了实现链式访问,只有函数有了返回值,这样才能使用返回值进行链式访问!!!

总结

  以上就是实现库函数strcpy的过程,总而言之,自己实现库函数的时候还是要看看库函数的原型是如何定义的,往原型上靠拢,写出的代码就是比较完美的,以此类推也可以实现别的库函数,比如strlen(),strcat()等等。

C语言联合体(Union)详解:内存共享原理、应用场景与避坑指南 在C语言编程中,数据结构是组织和管理内存的核心概念。联合体(Union)作为一种特殊的数据结构,其核心原理在于让多个成员共享同一块内存空间,这与结构体(Struct)为每个成员分配独立内存的方式形成鲜明对比。这种内存共享机制的技术价值在于能够实现极致的空间节省,尤其适用于内存资源受限的嵌入式系统编程。从应用场景来看,联合体是处理网络协议解析、硬件寄存器映射以及实现变体类型(Variant)的理想工具。通过精准控制内存布局,程序员可以高效地处理异构数据。本文聚焦于联合体的内存布局、典型应用如协议解析和节省内存 阅读详情

相关推荐

金融级IT架构-数字银行的云原生架构解析

最近断断续续花了差不多2到3周的时间阅读完由电子工业出版社出版的《金融级IT架构:数字银行的云原生架构解密》的这本书,作者是作者是网商银行技术编委会。 本书契合了当前银行业分布式架构转型趋势,内容是经过实践检验的领先技术介绍了网商银行IT技术架构演进路线,涵盖了分布式、单元化、弹性混合云、云原生多个基础架构领域,同时介绍了技术风险、安全可信、业务架构等多方面的技术实践经验。 对于这本书实际很早搜索云原生相关书籍的时候就搜索到,但是一看标题是金融IT架构方面的因此没有引起太多的重视,后面由华章...

年少有为 4064

C语言结构体赋值:从浅拷贝到深拷贝的内存操作解析

在C语言编程中,结构体是组织复杂数据的基础数据结构,它允许将不同类型的数据成员组合成一个整体。结构体赋值的底层原理本质上是内存字节的按位复制,编译器会根据结构体大小生成类似memcpy的指令。这种机制在提升代码简洁性的同时,也带来了潜在的技术风险,尤其是当结构体包含指针成员时,默认的赋值操作仅复制指针地址而非指向的数据,导致浅拷贝问题。浅拷贝会引发数据共享、双重释放或内存泄漏等严重错误,这在涉及动态内存管理的工程实践中尤为关键。因此,理解并正确实现深拷贝技术,即手动为指针成员分配独立内存并复制内容,是确保程

weixin_30564785的博客 337

从48V到800V:TI BMS芯片如何应对高压电池管理挑战?

电池管理系统是电动汽车和储能系统的核心,负责监控电池状态、保障安全并优化性能。其核心原理在于通过高精度测量电池电压、电流和温度,结合算法估算电池的荷电状态与健康状态,从而实现精准的能量管理与寿命预测。在技术价值层面,高精度测量能最大化利用电池化学窗口,提升能量密度与续航里程;而符合功能安全标准的设计则是防止热失控等安全事故的基石。随着汽车电气化从48V轻混系统向400V/800V高压平台演进,BMS面临着测量精度、功能安全、高压隔离通信和系统成本等多重挑战。德州仪器的BQ796xx和BQ75614系列芯片,

weixin_27017211的博客 341

(C语言进阶)strcpy

下面是将要介绍的几个函数: 结果如下 : 输出结果为:拷贝原理: 那么,如果拷贝内容没有包含'\0'呢?那就是下面这种情况 输出结果:拷贝原理:解释:strcpy拷贝到'\0'就停止,但是没有'\0'只能继续拷贝直到找到'\0'。否则输出结果不为正确的拷贝结果。因此要遵守源字符串必须以 '\0' 结束。 输出结果:(输出有误且有报错结果) 因此,我们在拷贝的时候需要做到目标空间必须足够大,以确保能存放源字符串 输出结果:调试: 用指针指向的字符串来举例,指针指向的内容是不可以改

来两颗橘子吧的博客 218

555定时器呼吸灯电路制作全攻略:从仿真到实物搭建(附避坑指南)

本文详细介绍了使用555定时器制作呼吸灯电路的完整流程,从基础原理到实物搭建,包括电路设计、元件选择、仿真验证、焊接技巧及调试优化。特别提供了避坑指南,帮助电子爱好者快速掌握这一经典DIY项目,实现美观的呼吸灯效果。

weixin_33734785的博客 402

Matlab TreeBagger实战:用随机森林预测房价的5个关键步骤(附完整代码)

本文详细介绍了使用Matlab的TreeBagger工具包构建随机森林模型预测房价的完整流程。通过波士顿房价数据集实战,涵盖数据预处理、模型构建、参数调优、特征重要性分析及高级应用(如分位数回归)等5个关键步骤,并附有完整代码,帮助读者快速掌握这一强大的回归分析工具。

ol789012的博客 444

【C语言】strcpy()函数详解(字符串拷贝函数)

有关C语言库函数strcpy()函数的详解,内容包括:函数简介,参数及返回值分析,函数的具体使用示例,模拟编写程序实现strcpy()函数功能等相关内容.

C/C++领域,数据结构,linux,MySQl学习者 6万+

openeuler在线/离线安装docker服务

openeuler在线/离线安装docker服务

haixuti7的博客 1071

【C语言】strcpy()函数

strcpy()函数:是将一个字符串复制到另一块空间地址中 的函数,‘\0’是停止拷贝的终止条件,同时也会将 '\0' 也复制到目标空间。本文介绍了strcpy函数的具体使用以及需要注意的事项。

weixin_47970952的博客 16万+

如何更好的理解PFC(功率因数校正)

此电路虽然简单,可以在前期设计的无PFC功能的设备上,简单的增加一个合适的电感(适当的选取L和C的值),从而达到具有PFC的作用,但是这种简单的、低成本的无源PFC输出纹波较大,滤波电容两端的直流电压也较低,电流畸变的校正及功率因数补偿的能力都很差,而且L的绕制及铁芯的质量控制不好,会对图像及伴音产生严重的干扰,只能是对于前期无PFC设备使之能进入市场的临时措施。)在t4~t5期间尽管二极管左边电压在逐步上升,但是由于二极管右边的Uc放电缓慢右边的电压Uc仍旧大于左边,二极管仍旧反偏截止。

U_YAO的博客 948

S32K324 Stack异常分析及解决方案

在项目开发过程中,在一次软件变更时,调整了task优先级之后导致应用层软件中的float数据经常性的变为NAN,导致应用层功能失效。本文记录下这个bug的分析及解决过程。该问题排查了好几天,最开始正向排查不出来,差点放弃了,ETAS OS也没有人支持,只能换一种思路,通过反向推,最终定位到问题,能完美解决,还是很欣慰的。遇到问题不可怕,Bug一直都会有,主要是在解决问题中的思路和方法,不断总结积累,总会越来越好的!

赞的博客 597

C语言strcpy()函数详解

strcpy()函数的原型定义在strcpy()函数是C语言标准库中一个重要的字符串处理函数,用于将一个字符串复制到另一个字符串。通过理解其定义、用法和实现,我们可以在各种字符串处理任务中有效地使用它。尽管strcpy()函数在处理小规模字符串复制时性能表现良好,但在大规模字符串复制任务中,可以考虑使用更高效的数据结构或第三方库。在使用strcpy()函数时,务必确保目标缓冲区有足够的空间来容纳源字符串及其终止字符,避免缓冲区溢出。此外,注意处理空指针,以避免未定义行为。

新华编程特战队 6262

在 SAP BTP 中为 SAP AI Core 创建 Service Instance 和 Service Key 的完整实战指南

摘要:本文详细介绍了在SAP BTP上创建AI Core服务实例和密钥的关键步骤,这是实现ABAP系统与Gen AI大语言模型集成的核心技术环节。文章通过一个制造业财务问答场景的案例,系统梳理了从前提条件准备、架构理解到具体操作的全过程,重点解析了service instance创建、X.509证书配置等关键节点。特别强调了Extended计划选择、证书格式等易错点,为ABAP开发人员实现Gen AI场景提供了实用指南。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 271

strcpy函数详解看这一篇就够了-C语言(函数实现、使用用法举例、与strncpy的区别)

首先要明确strcpy的功能是:将参数src字符串拷贝至参数dest所指的地址 目录 函数介绍 与strncpy的区别 函数实现1: 函数实现2 改进: 用法示例: 函数介绍 函数原型:char*strcpy(char*dest,const char*src) //将src复制到dest字符数组中 头 文 件:#include <string.h> 返 回 值:char* 类型,返回的是第一个参数的值,即一个目的字符的首地址; 注 意: 1、strcpy...

kim的博客 7万+

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

strcpy memcpy memmove区别和实现

memcpy与memmove的目的都是将N个字节的源内存地址的内容拷贝到目标内存地址中。 但当源内存和目标内存存在重叠时,memcpy会出现错误,而memmove能正确地实施拷贝,但这也增加了一点点开销。 memmove的处理措施: (1)当源内存的首地址等于目标内存的首地址时,不进行任何拷贝 (2)当源内存的首地址大于目标内存的首地址时,实行正向拷贝 (3)当源内存

amwpynnpyu的专栏 1032

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

C语言string.h库函数深度解析:从原理到嵌入式实战应用

字符串处理是编程的基础,其核心在于对内存中字符序列的高效操作与安全控制。C语言标准库中的string.h提供了一系列底层函数,如strcpy、strcat和memcpy等,它们直接操作内存,性能高效,是系统编程和嵌入式开发的基石。理解这些函数的实现原理,例如strcpy的缓冲区溢出风险、strncpy的终止符陷阱以及memcpy与memmove在处理内存重叠时的区别,对于编写健壮、安全的代码至关重要。在嵌入式开发中,尤其是在资源受限的STM32等平台,掌握这些函数的定制化实现和优化策略(如对齐访问、使用编译

weixin_34080571的博客 376

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

C语言重点知识梳理_复习

本文系统讲解了C语言中的核心概念和技术要点,主要内容包括: 数据存储机制 整型数据的原码/反码/补码表示 大端/小端存储模式及检测方法 浮点数的IEEE 754存储标准(S/M/E三部分) 数组与指针 数组名与指针的区别 指针数组与数组指针的差异 二维数组的内存布局 函数指针的定义与使用 重要库函数 字符串处理函数(strlen/strcpy/strcat等) 内存操作函数(memcpy/memmove/memset) 类型转换函数(atoi/itoa) 复合数据类型 结构体内存对齐规则 联合体的共享内存特

心动的那一刻,记忆便盛开了花 660

C语言二维数组:从内存布局到动态创建与性能优化

数组是计算机科学中用于存储同类型数据集合的基础数据结构,它将数据元素通过索引组织在连续的内存空间中,以实现高效的随机访问。其核心原理在于通过基地址和偏移量计算公式直接定位元素,这种机制奠定了高效数据处理的基石。在工程实践中,数组的技术价值尤为突出,它是实现矩阵运算、图像像素处理、游戏地图及表格数据管理的底层支撑。理解多维数组,特别是二维数组在内存中的‘行优先’连续布局,是进行缓存友好型程序设计、避免性能陷阱的关键。本文聚焦于C语言中二维数组的静态与动态创建、指针操作、函数参数传递等核心机制,并深入探讨了其在

weixin_34387468的博客 287

C语言指针数组与数组指针:内存模型、步长差异与实战应用

在C语言编程中,指针是理解内存布局和数据操作的核心概念。指针本质上是一个存储内存地址的变量,通过指针可以间接访问和操作数据,这是实现动态内存管理、高效数据传递和复杂数据结构的基础。指针数组与数组指针是两种极易混淆但至关重要的复合类型,它们的核心差异在于类型系统和指针运算的“步长”不同。指针数组的本质是一个数组,其每个元素都是一个指针,常用于管理字符串列表、命令行参数或动态分配的异构数据块;而数组指针的本质是一个指针,它指向一个完整的数组,主要用于向函数传递多维数组,确保编译器能正确计算行偏移。理解二者的内存

weixin_30596165的博客 357

C++程序存储空间问题

健仔说到的一个问题。 void Test(void) { char str[2]; strcpy(str, "hello world"); printf(str); cout << "fuck" << endl; } 这样的代码,其实在strcpy时已经出错了,为什么还可以继续输出?然后才报错? 查看strcpy的源代码如此: char * strcpy(char * dest,c

Sigh~ 1009

C语言数组深度解析:从内存模型到实战避坑指南

在计算机编程中,数据结构是组织和存储数据的基础,而数组作为最基本的数据结构之一,其核心原理在于连续内存分配与固定类型元素存储。这种设计使得数组能够通过下标直接计算出元素的内存地址,从而实现O(1)时间复杂度的随机访问,这是链表等非连续结构无法比拟的效率优势。从技术价值看,数组不仅是算法实现的基石,更是理解内存管理、指针运算和缓存友好编程的关键。在嵌入式系统、操作系统内核和高性能计算等应用场景中,对数组的高效运用直接影响程序性能。本文将聚焦C语言数组的内存模型、指针关系及动态内存管理,特别针对数组越界和字符串

weixin_33816821的博客 400

C语言数组初始化全解析:从基础语法到高效实践与内存安全

数组是编程中用于存储同类型数据集合的基础数据结构,其核心原理是在内存中分配连续的空间。正确的初始化技术不仅能确保数据安全、避免未定义行为,还能显著提升程序性能,是编写健壮高效代码的关键。在C语言中,数组初始化方法经历了从传统的循环赋值、初始化列表到C99指定初始化器的演变,每种方法在内存布局和编译器优化层面都有不同影响。对于需要快速清零或填充的场景,memset函数提供了高效的字节级操作;而在处理稀疏数组或需要明确下标含义时,指定初始化器能极大提升代码可读性。理解这些方法的适用场景和底层原理,有助于开发者在

weixin_33811539的博客 423

简单的内存溢出破解实例

字典序列:从第一字符开始比较,按照字母表顺序排列,如果相同就比较下一位。如果字符串a,b前n位相同,a第n+1位不存在,则有a#李龙海 案例分析 #include<stdio.h> #include<string.h> #define PASSWARD "1234567" int verify_password(char* pwd){ int valid_flag=0; char b

u013380033的专栏 877

缓冲区溢出[函数调用时的堆栈变化]

一个正常的程序在内存中通常分为程序段,数据端和堆栈三部分。程序段里放着程序的机器码和只读数据,这个段通常是只读,对它的写操作是非法的。数据段放的是程序中的静态数据。动态数据则通过堆栈来存放。     在内存中,它们的位置如下:        /――――――――\  内存低端    程序段    ―――――――――    数据段    ―――――――――    堆栈    \―――――――――/内

极客剑 916

通通透透讲溢出攻击

缓冲区溢出技术基础   为了提高大家的技术水平,为了更了解我们讨论的这种技术,为了把这个论坛建成一个更更好的论坛,下面我为大家推出一系列完整的有关溢出,溢出攻击的文章。让大家更能了解到这个天天说但又不太清楚怎么回事的东西。我想,看了这个以后大家也不再会问,为什么我用了这个工具,怎么没有用呀什么的问题?   在这里强调一下,想完全看的懂这篇文章,至少需要具备一定的汇编语言,C语言和LINU...

djbjh55539的博客 125

每天学习一点string.h

面试中总会遇到让写字符串的caozu

lannykuaile的专栏 510
上一篇: [c语言]求二进制位1的
下一篇: [C语言]调整数组使奇数全部都位于偶数前面。
coolnut12138
博客等级 码龄9年 51粉丝 75原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值