strcpy

C语言标准库函数
原型声明:extern char *strcpy(char dest[],const char *src);
头文件:#include < string.h>
功能:把从src地址开始且含有NULL结束符的字符串复制到以dest开始的 地址空间
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
返回指向dest的 指针

编辑本段典型实现

/**********************
* C语言标准 库函数strcpy的一种典型的工业级的最简实现
* 返回值:
* 返回目标串的地址。
* 对于出现异常的情况ANSI-C99标准并未定义,故由实现者决定返回值,通常为NULL。
* 参数:
* strDestination
*  目标串
* strSource
* 源串
***********************/
char *strcpy(char *strDestination,const char *strSource)
{
assert(strDestination!=NULL && strSource!=NULL);
char *strD=strDestination;
while ((*strDestination++=*strSource++)!='\0');
return strD;
}

编辑本段出现频率最高的笔试题strcpy写法

题目

已知strcpy函数的原型是:
char * strcpy(char * strDest,const char * strSrc);
⒈不调用 库函数,实现strcpy函数。
⒉解释为什么要返回char *。

解说

⒈strcpy的实现代码
char * strcpy(char * strDest,const char * strSrc)
{
char * strDestCopy=strDest; //[3]
if ((strDest==NULL)||(strSrc==NULL)) //[1]
throw "Invalid argument(s)"; //[2]
while ((*strDest++=*strSrc++)!='\0'); //[4]
return strDestCopy;
}
错误的做法:
[1]
(A)不检查 指针的有效性,说明答题者不注重代码的健壮性。
(B)检查 指针的有效性时使用((!strDest)||(!strSrc))或(!(strDest&&strSrc)),说明答题者对C语言中类型的隐式转换没有深刻认识。在本例中char *转换为bool即是类型隐式转换,这种功能虽然灵活,但更多的是导致出错概率增大和维护成本升高。所以C++专门增加了bool、true、false三个 关键字以提供更安全的 条件表达式
(C)检查 指针的有效性时使用((strDest==0)||(strSrc==0)),说明答题者不知道使用 常量的好处。直接使用字面 常量(如本例中的0)会减少程序的可维护性。0虽然简单,但程序中可能出现很多处对 指针的检查,万一出现笔误, 编译器不能发现,生成的程序内含逻辑错误,很难排除。而使用NULL代替0,如果出现拼写错误, 编译器就会检查出来。
[2]
(A)return new string("Invalid argument(s)");,说明答题者根本不知道返回值的用途,并且他对 内存泄漏也没有警惕心。从函数中返回函数体内分配的内存是十分危险的做法,他把释放内存的义务抛给不知情的调用者,绝大多数情况下,调用者不会释放内存,这导致内存泄漏。
(B)return 0;,说明答题者没有掌握异常机制。调用者有可能忘记检查返回值,调用者还可能无法检查返回值(见后面的链式表达式)。妄想让返回值肩负返回正确值和异常值的双重功能,其结果往往是两种功能都失效。应该以 抛出异常来代替返回值,这样可以减轻调用者的负担、使错误不会被忽略、增强程序的可维护性。
[3]
(A)忘记保存原始的strDest值,说明答题者逻辑思维不严密。
[4]
(A)循环写成while (*strDest++=*strSrc++);,同[1](B)。
(B)循环写成while (*strSrc!='\0') *strDest++=*strSrc++;,说明答题者对边界条件的检查不力。循环体结束后,strDest字符串的末尾没有正确地加上'\0'。
⒉返回strDest的原始值使函数能够支持链式 表达式,增加了函数的“附加值”。同样功能的函数,如果能合理地提高的可用性,自然就更加理想。
链式 表达式的形式如:
int iLength=strlen(strcpy(strA,strB));
又如:
char * strA=strcpy(new char[10],strB);
返回strSrc的原始值是错误的。其一,源字符串肯定是已知的,返回它没有意义。其二,不能支持形如第二例的 表达式。其三,为了保护源字符串, 形参用const限定strSrc所指的内容,把const char *作为char *返回,类型不符,编译报错。
在上面的语句中, 循环语句while ((*strDest++=*strSrc++)!='\0');较难理解,可以把这句理解为以下操作。
第一种:
while⑴
{
char temp;
temp=*strDest=*strSrc;
strDest++;
strSrc++;
if('\0'==temp)
break;
}
第二种:
while(*strSrc!='\0')
{
*strDest=*strSrc;
strDest++;
strSrc++;
}
*strDest=*strSrc;
个人意见:throw用法明显的运行不通,如果要判断加#include<assert.h>
如果 表达式的值为假,整个程序将退出,并输出一条 错误信息。如果 表达式的值为真则继续执行后面的语句。
使用这个宏前需要包含头文件 assert.h
#include <assert.h>
#include<iostream.h>; 
char * strcpy(char * strDest,const char *strSrc)
{
assert((strDest!=NULL) && (strSrc !=NULL));
char * strDestCopy=strDest;
while ((*strDest++=*strSrc++)!='\0');
return strDestCopy;
}
void main()
{
char a[20],c[]="i am teacher!";
strcpy(a,c);
cout<<a<<endl;
}
 
 
 

做C++试题时无意中看到此题,因起一振思想风暴!且看:

 

int main() {

       char p1[ 10 ], p2[ 10 ];

       strcpy( p1, "abc" );

       strcpy( p2, "ABC" );

       char str[ 50 ] = "xyz";

       strcpy( str + 2, strcat( p1, p2 ) );

       cout << str << endl;

       return 0;

}

输出为: xyabcABC

对于strcpy()来说,大家并不陌生,无非是把第二个参数的内容复制进第一个参数里嘛。但能否正确并恰如其分地运用好它,这也是得仔细琢磨的。

其原形:char* strcpy( char *to, const char *from );

首先看看使用strcpy()时错误的例子:

错甲:

int main() {

       char first_name[ 100 ] = "Stone Cold ";

       char last_name[ 50 ] = "Steve Austin";

       strcpy( first_name , last_name );

       cout << first_name << endl;

       return 0;

}

错!因为从函数原形的参数表里面儿,我们已经看到:第一个参数是 to,也就是说从from来的数据将会直接流至并占有to的地盘,覆盖掉to内的数据!如例所示,这么一来,输出将会是:Steve Austin,而原来的Stone Cold就被覆盖掉了。悲剧!Tragedy !

 

错乙:

int main() {

       char first_name[ 12 ] = "Stone Cold ";

       char last_name[ 13 ] = "Steve Austin";

       strcpy( first_name + 11, last_name );

       cout << first_name << endl; 

       return 0;

}

strcpy()最典型最常犯的错误!——数组定义的太小了!你想想看呐:last_name[]数组里的那13个字符复制到first_name[]数组里面后,那么原来的那12个字符大小的一亩三分地儿,还够用吗?肯定不够!!!所以,千万要提前定义得足够大!

 

 

错丙:

int main() {

       char* first_name = "Stone Cold ";

       char* last_name = "Steve Austin";

       strcpy( first_name, last_name );

       cout << first_name << endl;

       return 0;

}

错!根本就没有用数组!必须得是数组!即便是你甘心让last_name覆盖了first_name、最后输出Steve Austin,也不行!其实这么干,编译也不会报错,但一执行,电脑就有死机倾向了,根本无法执行,一执行必死机……

 

例丁:

int main() {

       string first_name = "Stone Cold ";

       string last_name = "Steve Austin";

       strcpy( first_name + 11, last_name );

       cout << first_name << endl;

       return 0;

}

不行!大错特错!虽然从函数名上看它是string copy的缩写,但它是属于C函数,而在C函数中根本就没有什么string类!!所以你直接用strcpy()来操作string类型的数据注定失败!!

 

我地个亲娘来!这么容易犯错呀!!那么到底什么才是正确的实验、使用方法呢!别急,且看:

 

int main() {

       char first_name[ 500 ] = "Stone Cold "; // 千万提前定义足够大的数组!为后来存储接纳新的数据做好准备!

       char last_name[ 20 ] = "Steve Austin";

       strcpy( first_name + 11, last_name ); //请千万找准连体的位置,否则遗恨终身!

       cout << first_name << endl;

       return 0;

}

这便是strcpy()的最佳范例!其原则如下:1、千万足够大;2、找准连体位置;3、只用于数组,不用于string, char*什么的。

额外地,咱再补充一点:strcpy() 复制时,是连同结束标志 ‘\0’ 一起复制的,而原数组(即参数1)的’\0’被舍弃。咱们锱珠必较地实验一下啊:

       char first_name[ ] = "Stone Cold "; first_name数组里有11个字符外加一个‘\0’,总共占用12个字节。同理,last_name[]占用13个字节。把last_name[]的13个字节复制给first_name[]之后,它就最少得占用25个字节了。实则不然,只占24!因为first_name[]里的结束标志‘\0’被抛弃了。这样一来,下面的程序就运行得通了:

 

 

int main() {

       char first_name[ 24 ] = "Stone Cold ";

       char last_name[ 13 ] = "Steve Austin";

       strcpy( first_name + 11, last_name );

       cout << first_name << endl;

       return 0;

}

不过话说回来,希望大家在实际编程中不要这么干,因为万一有个闪失,程序就会出错。定义数组时尽管大方一点,多几个闲着的城池无所谓!

 

那么,还有一个呀——strcat()是哪个老几?它又有何用?

strcat 的原形为:char *strcat( char *str1, const char *str2 ); 其实它和strcpy的功用有相似之处。它是把第二个参数的内容连接复制到第一个参数内容的尾巴上。如此看来,针对本题而言,它比strcpy()更合适、更简便,即:

int main() {

       char first_name[ 24 ] = "Stone Cold "; //依然是前者的结束标志‘\0’被抛弃.

       char last_name[ 13 ] = "Steve Austin";

       strcat( first_name, last_name ); //无须找连体点,它自己会接上去!

       cout << first_name << endl;

       return 0;

}

如果你要问此函数的名字是什么单词的缩写。嗯?英语中有个动词concatenate, 意思是连接上,估计是把中间的cat提炼出来作为函数名的一部分吧,嘿嘿。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值