复制:另造一份的意思,地址不同;赋值:起个别名的意思,地址相同。
复制函数:char *strcpy(char* dest, const char *src);
头文件:#include
功能:把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
返回指向dest的指针。
实现代码:
char* strcpy(char* des,const char* source)
{
char* r=des;
assert((des != NULL) && (source != NULL));
while((*r++ = *source++)!='\0');
return des;
}
注意点:
假如source所指向的数据段是一段协议数据,而协议数据中间包含了一些数据0,这时复制就会出现错误,会出现复制不完整的现象。比如char source[10] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x00, 0x47, 0x48, 0x49, 0x4a};
正常复制:
#include
#include
#include
int main(){
char* dest = NULL;
char source[10] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a};
dest = (char *)malloc(strlen(source)+1);
strcpy(dest, source);
printf("source address is %p, dest address is %p.\n", &source, dest);
printf("source lenth is %d, source is %s.\n", strlen(source), source);
printf("dest lenth is %d, dest is %s.\n", strlen(dest), dest);
free(dest);
return 0;
}
运行环境:ubuntu14.04,平台自带gcc编译器
运行结果:
root@ubuntu:/home/jack# make
gcc -o test test.c -lpthread
root@ubuntu:/home/jack# ./test
source address is 0xbfe65902, dest address is 0xa026008.
source lenth is 10, source is ABCDEFGHIJ.
dest lenth is 10, dest is ABCDEFGHIJ.
root@ubuntu:/home/jack#
测试程序下载地址:https://download.csdn.net/download/sleeping_sunshine/11596997
没毛病!再来一段:
#include
#include
#include
int main(){
char* dest = NULL;
char source[10] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x00, 0x47, 0x48, 0x49, 0x4a};
dest = (char *)malloc(strlen(source)+1);
strcpy(dest, source);
printf("source address is %p, dest address is %p.\n", &source, dest);
printf("source lenth is %d, source is %s.\n", strlen(source), source);
printf("dest lenth is %d, dest is %s.\n", strlen(dest), dest);
free(dest);
return 0;
}
运行环境:ubuntu14.04,平台自带gcc编译器
运行结果:
root@ubuntu:/home/jack# make
gcc -o test test.c -lpthread
root@ubuntu:/home/jack# ./test
source address is 0xbf8ae7a2, dest address is 0x939e008.
source lenth is 5, source is ABCDE.
dest lenth is 5, dest is ABCDE.
root@ubuntu:/home/jack#
看出问题没?
这在工程项目中是很大的问题,工作设备牵涉大量的外围部件,他们与主机通过约定的协议进行数据的传送,往往一串数据中包含很多位的数字 0 ,也就是 结束符 '\0'('\0'的ASCII码是0),所以复制时经常会提前结束;
测试程序下载地址:https://download.csdn.net/download/sleeping_sunshine/11603540
#include
#include
#include
int main(){
char* source = "hello boy!";
char* dest = NULL;
dest = source;
printf("source address is %p, dest address is %p.\n", source, dest);
printf("source lenth is %d, source is %s\n", strlen(source), source);
printf("dest lenth is %d, dest is %s\n", strlen(dest), dest);
return 0;
}
运行环境:ubuntu14.04,平台自带gcc编译器
运行结果:
root@ubuntu:/home/jack# make
gcc -o test test.c -lpthread
root@ubuntu:/home/jack# ./test
source address is 0x8048570, dest address is 0x8048570.
source lenth is 10, source is hello boy!
dest lenth is 10, dest is hello boy!
root@ubuntu:/home/jack#
可以看出赋值后的目标地址不变的。
测试程序下载地址:https://download.csdn.net/download/sleeping_sunshine/11597057
destinin:表示复制的目标字符数组;
source:表示复制的源字符数组;
maxlen:表示复制的字符串长度。
一般实现代码:
char *strncpy(char *dest, const char *src, size_t len)
{
assert(dest!= NULL && src != NULL);
char *res = dest;
while (len--)
{
*dest++ = *src++;
}
return res;
}
我们在复制之前一般都会知道源字符串或者说是数组的长度,进而进行小于等于源数据长度的复制,但是有没有可能存在这种情况:源字符串长度为5,而要复制10的长度的字符。通常来说只需在assert语句中加一个判断即可避免这种情况,即:
assert((dest!= NULL) && (src != NULL) && (len <= strlen(src)));
那假如我就想随意一点,复制长度任意 ,代码里面该怎么处理。
首先要明确一点:
如果strlen(src) < len,dest数组就用额外的NULL字节填充到len长度。
char *strncpy1(char *dest, const char *src, size_t len)
{
assert(dest != NULL && src != NULL);
char *res = dest;
int nullSet = 0;
if (strlen(src) < len){//src长度小于len
nullSet = len - strlen(src);
len = strlen(src);
}
while (len--){
*dest++ = *src++;
}
if( 0 == nullSet ){
*dest = '\0';
}
while (nullSet--){
*dest++ = '\0';
}
return res;
}
举个例子:
#include
#include
#include
#include
char *strncpy1(char *dest, const char *src, size_t len)
{
assert(dest != NULL && src != NULL);
char *res = dest;
int nullSet = 0;
if (strlen(src) < len){//src长度小于len
nullSet = len - strlen(src);
len = strlen(src);
}
while (len--){
*dest++ = *src++;
}
if( 0 == nullSet ){
*dest = '\0';
}
while (nullSet--){
*dest++ = '\0';
}
return res;
}
int main(){
char* source1 = "hello-boy!";
char source2[] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a};
char* dest1 = (char *)malloc(5);
char* dest2 = (char *)malloc(20);
char* dest3 = (char *)malloc(5);
char* dest4 = (char *)malloc(20);
strncpy1(dest1, source1, 5);
strncpy1(dest2, source1, 20);
strncpy1(dest3, source2, 5);
strncpy1(dest4, source2, 20);
printf("source1 address is %p, source1 is %s.\n", source1, source1);
printf("source2 address is %p, source2 is %s.\n", source2, source2);
printf("dest1 address is %p, dest1 is %s.\n", dest1, dest1);
printf("dest2 address is %p, dest2 is %s.\n", dest2, dest2);
printf("dest3 address is %p, dest3 is %s.\n", dest3, dest3);
printf("dest4 address is %p, dest4 is %s.\n", dest4, dest4);
free(dest1);
free(dest2);
free(dest3);
free(dest4);
return 0;
}
运行环境:ubuntu14.04,平台自带gcc编译器
运行结果:
root@ubuntu:/home/jack# make
gcc -o test test.c -lpthread
root@ubuntu:/home/jack# ./test
source1 address is 0x80488c2, source1 is hello-boy!.
source2 address is 0xbf8d36c2, source2 is ABCDEFGHIJ.
dest1 address is 0x9b05008, dest1 is hello.
dest2 address is 0x9b05018, dest2 is hello-boy!.
dest3 address is 0x9b05030, dest3 is ABCDE.
dest4 address is 0x9b05040, dest4 is ABCDEFGHIJ.
root@ubuntu:/home/jack#
可以看出,即使复制的长度大于src字符串的长度,也可以正确复制。(用库函数strcpy()当然也可以完成此功能,此处书写的strcpy1()只为了说明len大于strlen(src)情况下的处理)。
测试程序下载地址:https://download.csdn.net/download/sleeping_sunshine/11600165
既然指定了复制的字节数,那么复制的前len个字节中包含有0x00,会不会提前终止呢?
#include
#include
#include
#include
int main(){
char* source1 = "hello-boy!";
char source2[] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x00, 0x49, 0x4a};
char* dest1 = (char *)malloc(5);
char* dest2 = (char *)malloc(20);
char* dest3 = (char *)malloc(5);
char* dest4 = (char *)malloc(20);
strncpy(dest1, source1, 5);
strncpy(dest2, source1, 20);
strncpy(dest3, source2, 5);
strncpy(dest4, source2, 20);
printf("source1 address is %p, source1 is %s.\n", source1, source1);
printf("source2 address is %p, source2 is %s.\n", source2, source2);
printf("dest1 address is %p, dest1 is %s.\n", dest1, dest1);
printf("dest2 address is %p, dest2 is %s.\n", dest2, dest2);
printf("dest3 address is %p, dest3 is %s.\n", dest3, dest3);
printf("dest4 address is %p, dest4 is %s.\n", dest4, dest4);
free(dest1);
free(dest2);
free(dest3);
free(dest4);
return 0;
}
运行环境:ubuntu14.04,平台自带gcc编译器
运行结果:
root@ubuntu:/home/jack# make
gcc -o test test.c -lpthread
root@ubuntu:/home/jack# ./test
source1 address is 0x8048780, source1 is hello-boy!.
source2 address is 0xbfc3d9e2, source2 is ABCDEFG.
dest1 address is 0x9e53008, dest1 is hello.
dest2 address is 0x9e53018, dest2 is hello-boy!.
dest3 address is 0x9e53030, dest3 is ABCDE.
dest4 address is 0x9e53040, dest4 is ABCDEFG.
果然发生了截断,也就是说:对于字节数组(可以看成一种特殊字符串)的复制,当其中包含0x00时,不可使用strcpy()或者strncpy()函数,比较好的解决办法就是利用for循环来确认复制的位数。在工程实践中,外围部件按协议发来的数据往往就是一串16进程数,对其进行解析时尤其要注意这点!
测试程序下载地址:https://download.csdn.net/download/sleeping_sunshine/11600176