在C语言中,字符串一直都是热点,关于strcpy函数大家都很熟悉,但是真正了解的很少,一旦用到总会报一大堆莫名其妙错误,今天我就来给大家详细剖析一下strcpy函数。

虽然不能看到strcpy的内部实现,但是我们通过查阅<string.h>可以看到strcpy函数的声明。

char *  __cdecl strcpy(char *, const char *);

那个_cdecl是一个函数调用约定,暂且不讨论,我们今天就来说一下strcpy指针形参加const与不加的区别,帮助大家更好使用这个函数

首先我们要理解这两种语句有何不同

 char *p="abcd";
char str[]="abcd";

这两条语句都是存储abcd字符串,但是经过编译链接后,会产生不同的结果
语句1,常量字符串会保存在程序的常量区,编译时会将该字符串在常量区的起始地址拷贝过来存在指针p中,

语句2  常量字符串也会保存在程序的常量区,但是在字符数组str初始化时i,会将字符串拷贝到str中,即数组中存储字符串副本

即str[0]='a';str[1]='b';str[2]='c';str[3]='d';str[4]='\0';

如图所示

我们看到在地址0x0042201C 处存储的是字符串常量abcd,而语句1汇编指令mov  dword ptr ds:[ebp-4], 0xoo42201C,作用就是把常量字符串地址存到[ebp-4]这个内存空间(即变量名为p的内存地址)

语句2则是将该常量值一个个拷贝到数组中,即字符串存储在数据段中

那么这样区分之后,会产生一个是否允许修改的差异,我们都知道常量区中的内容不允许修改,而数据区的内容是可读可写的,因此,如果我们这样写

 p[]='w';
str[]='q';

会发现 虽然语句1编译链接都通过,但是运行时会报错,这是因为语句1试图非法修改常量区的值,而常量区是允许修改,只能读取

而语句2则可以使程序正常运行,因为str数组只是常量字符串的一份副本,这份副本存在数据区,可以修改,而且不会影响到常量区字符串的值

明白了关于指向字符串常量的指针和存储字符串常量的数组之间的差异后,我们接下来讨论指针形参输出型和输入型问题

对于形参是指针类型的,我们都知道是传址调用,也明白函数内形参的改变会影响到形参,这就涉及一个实参是否允许修改的问题

char * strcpy(char * strDest,const char * strSrc);

这个函数形参,一个是不加const修饰,一个是加上了const修饰,有何区别呢?这个函数是将strSrc指向的字符串复制到strDest中,(连同字符串结束符'\0'一起复制),

那么就是说,strDest指向的值是可以修改的,而strSRC指向的值在函数中是不允许修改的,我们把加上const修饰的参数称为输入型参数,即只允许读取,不允许写入,把不加const修饰的参数称为输出型参数,即可以在函数内部进行读写改变,从而在主调函数中看到改变。

通过刚才的探讨,我们可以很容易知道如下四条语句哪些会使程序运行时出错

char *p="";
char *q="abcd";
char str1[]="";
char str2[]="hijk";
strcpy(p,q);①
strcpy(p,str1);②
strcpy(str1,p);③
strcpy(str1,str2);④

很明显,标号①②的语句都会运行时出错,因为strcpy的第一个形参要求是可以写入的,而p,q都是指向了常量区字符串的首地址,不可写入

标号③④都是可以正常运行,但是推荐写法③,因为写法④设计一个隐式转换问题,将str2转换成了常指针了。

下面给出一个strcpy函数的实现

char * strcpy(char *strDest,const char *strSrc)
{
assert((strDest!=NULL)&&(strSrc!=NULL)); //断言两个指针都不是空指针
char *address=strDest; //函数要返回复制后的字符串首地址
while((*(strDest++)=*(strSrc++))!='\0');//连同结束符一起复制
return address; //返回复制后的字符串首地址
}

总结

1 char *p="1234";指针p指向常量区,不允许修改内容及p[0]='a'非法

2 char str[5]="abcd"  字符数组str复制了常量区字符串“abcd”的值,而字符数组是在数据段,可以进行修改及str[0]='1'合法

3 对于strcpy函数的第一个形参,是输出型形参,因此只能是数组名,而不能是字符指针变量

4 对strcpy的第二个形参,是输入型形参,可以是数组名或者是字符指针变量,但最好是字符指针变量

关于strcpy函数形参类型的解析和指针作为输入型输出型参数的不同的更多相关文章

  1. 通过指定函数/方法形参类型提高PHP代码可靠性

    指定形参类型是PHP 5就支持的一项特性.形参支持array - 数组. object - 对象两种类型. class User{ public $name; public $password; fu ...

  2. C/C++——strcpy函数的实现

    题目:     已知strcpy函数的原型是:         char * strcpy(char * strDest,const char * strSrc);     1.不调用库函数,实现st ...

  3. 《征服 C 指针》摘录5:函数形参 和 空的下标运算符[]

    一.函数的形参的声明 C 语言可以像下面这样声明函数的形参: void func(int a[]) {     // ... } 对于这种写法,无论怎么看都好像要向函数的参数传递数组. 可是,在 C ...

  4. python学习道路(day4note)(函数,形参实参位置参数匿名参数,匿名函数,高阶函数,镶嵌函数)

    1.函数 2种编程方法 关键词面向对象:华山派 --->> 类----->class面向过程:少林派 -->> 过程--->def 函数式编程:逍遥派 --> ...

  5. memcpy、memmove、memset及strcpy函数实现和理解

    memcpy.memmove.memset及strcpy函数实现和理解 关于memcpy memcpy是C和C++ 中的内存拷贝函数,在C中所需的头文件是#include<string.h> ...

  6. strcpy函数的C/C++实现

    2013-07-05 14:07:49 本函数给出了几种strcpy与strncpy的实现,有ugly implementation,也有good implementation.并参考标准库中的imp ...

  7. strcmp函数和strcpy函数

    (一)strcmp函数 strcmp函数是比較两个字符串的大小,返回比較的结果.一般形式是: i=strcmp(字符串,字符串); 当中,字符串1.字符串2均可为字符串常量或变量:i   是用于存放比 ...

  8. C#中:函数访问级别对函数形参访问级别的约束

    Inconsistent accessibility: parameter type 'Program.CommandLineInfo' is less accessible than method ...

  9. strcpy函数用法

    字符串是数组类型,不能通过赋值运算进行,要通过strcpy进行拷贝,其中目的字符串必须是字符串变量,源字符串可以是常量,复制后源字符串保持不变. strcpy()是C中的一个复制字符串的库函数,在C+ ...

随机推荐

  1. docker(一) Centos7下安装docker

    docker(一) Centos7下安装dockerdocker(二) windows10下安装dockerdocker(三) 镜像和容器常用命令 docker(四) 使用Dockerfile构建镜像 ...

  2. 采用VSPD、ModbusTool模拟串口、MODBUS TCP设备进行Python采集软件开发

    版权声明:本文为博主原创文章,欢迎转载,并请注明出处.联系方式:460356155@qq.com 不少仪器/设备都提供了数据采集的接口,其中不少是串口或网络的MODBUS/TCP协议. 串口是比较简单 ...

  3. JS生成 UUID的方法

    方法一. function uuid() { var s = []; var hexDigits = "0123456789abcdef"; for (var i = 0; i & ...

  4. java多线程2

    今日大部分时间花在了C语言的链表上了,以下是我今日所学习的java多线程内容,今天学习的是多线程里的其他命令,wait,notify,nofityAll,分别是等待,唤醒,全部唤醒. 附今日敲的代码: ...

  5. poj-2195(最小费用流)

    题意:给你一个n*m的地图,H代表这个点有一个房子,m代表这个点是一个人,每次h走一步就花费一,问最小花费使得每个人能进入一个房间 代码:建立一个源点和汇点,每个人和源点相连,每个房子和汇点相连,每个 ...

  6. [SimplePlayer] 3. 视频帧同步

    Frame Rate 帧率代表的是每一秒所播放的视频图像数目.通常,视频都会有固定的帧率,具体点地说是每一帧的时间间隔都是一样的,这种情况简称为CFR(Constant Frame Rate);另外一 ...

  7. mpvue——动态渲染echarts图表

    前言 使用mpvue-echarts来写图表,那个F2再提醒自己下要踩坑不能忘记.遇到了一个问题就是数据不能动态的去渲染,这个其实官方给了我们对应的方法 懒加载 代码 修改了调用initChart() ...

  8. VScode中python环境配置

    vscode中python环境配置 想要在vscode中运行python代码必须要告诉vscode使用哪个解释器才行 方法1. 打开命令面板(Ctrl+Shift+P)输入Python: Select ...

  9. php中fastcgi和php-fpm是什么东西

    参考和学习了以下文章: 1. mod_php和mod_fastcgi和php-fpm的介绍,对比,和性能数据 2. 实战Nginx_取代 为了如何一步步的引出fastcgi和php-fpm,我先一点一 ...

  10. 第十一节:Bundles压缩合并js和css及原理分析

    一. 简介 1.背景:浏览器默认一次性请求的网络数是有上限的,如果你得js和css文件太多,就会导致浏览器需要多次加载,影响页面的加载速度, MVC中提供Bundles的方式压缩合并js和css,是M ...