C/C++:strcpy-strcnpy-memcpy-memmove

【strcpy】
原型声明:extern char strcpy(char dest, const char *src);
头文件:#include

char * strcpy(char * dest, const char * src)
{
    if ((NULL == src) || (NULL == dest)) //判断参数src和dest的有效性
      return NULL;
  char *rst = dest;        //保存目标字符串的首地址
  while ((*dest++ = *src++)!='\0'); //把src字符串的内容复制到dest下
  return rst;
}

举例:
例子摘自:http://www.cplusplus.com/reference/cstring/strcpy/

/* strcpy example */
include <stdio.h>
include <string.h

int main ()
{
     char str1[]="Sample string";
     char str2[40];
     char str3[40];
     strcpy (str2,str1);
         strcpy (str3,"copy successful");
     printf ("str1: %s\nstr2: %s\nstr3: %s\n",str1,str2,str3);
     return 0;
}
结果:
str1: Sample string
str2: Sample string
str3: copy successful

【memcpy】
函数原型:void *memcpy(void *dest, const void *src, size_t n);
功能:从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
返回值:指向dest的指针。
说明:memcpy会完整的复制n个字节,不会因遇到字符串结束符’\0’而结束。而strcpy则是遇到字符串结束符’\0’而结束。
代码:

void *memcpy(void *dest, const void *src, size_t n)
{
  if ((NULL == src) || (NULL == dest)) //判断参数src和dest的有效性
      return NULL;
  char *rst = dest;        //保存目标字符串的首地址
while(n--)               
        *(char *)dest++ = *(char *)src++ ;  
  return rst;
}

举例:
例子摘自:http://www.cplusplus.com/reference/cstring/memcpy/

/* memcpy example */
include <stdio.h>
include <string.h>
struct {
  char name[40];
  int age;
} person, person_copy;

int main ()
{
     char myname[] = "Pierre de Fermat";
     /* using memcpy to copy string: */
     memcpy ( person.name, myname, strlen(myname)+1 );
     person.age = 46;
     /* using memcpy to copy structure: */
     memcpy ( &person_copy, &person, sizeof(person) );
     printf ("person_copy: %s, %d \n", person_copy.name, person_copy.age );
     return 0;
}
结果:
person_copy: Pierre de Fermat, 46

strcpy和memcpy的区别:

(1)复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
(2)复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符”\0”才结束,所以容易溢出。 memcpy则是根据其第3个参数决定复制的长度。

相同点:

都没有考虑内存重叠问题

内存重叠问题:

举例:
例子摘自:http://blog.csdn.net/uusad/article/details/5273762

include <string.h>
include <stdlib.h>
include <stdio.h>
int main(){
        char *p = NULL;
        p = (char *)malloc(10);
        memcpy(p,"1234679",strlen("1246789"));
        printf("before p = %s/n", p);
        strcpy(p+1,p);//这重叠了
        printf("after p = %s/n", p);
      free(p);
}

这个时候如果使用strcpy函数则程序会崩溃。使用memcpy的话程序会等到错误的结果。
原因就是因为memcpy,strcpy这两个函数没有对内存重叠进行处理。使用这两个函数的时候只有程序员自己保证源地址与目标地址内存不重叠。或是使用memmov函数进行拷贝内存。
网上很多关于strcpy和memcpy的源码,很多版本的核心代码是使用while加上*des++=*sou++;完成。所以没有对内存的重叠进行处理。至于为什么使用memcpy程序只是等不到正确的结果,而使用strcpy程序还会崩溃?原因很简单memcoy有一个长度参数,只拷贝cnt个字节就结束了。而strcpy是根据判断源字串中的’/0’。

【memmove】
原型:void memmove( void dest, const void* src, size_t count );
头文件:

void *memmove(void *dest, const void *src, size_t count )
{
    if(NULL == dest || NULL == src){
        return NULL;
    }   
    void *rst = dst;
    if(dest <= src || (char *)dest >= (char *)src + len)
{
        //没有内存重叠,从低地址开始复制
        while(count --){
            *(char *)dest = *(char *)src;
            dest = (char *)dest + 1;
            src = (char *)src + 1;
        }
    }
else{
        //有内存重叠,从高地址开始复制
        src = (char *)src + len - 1;
        dest = (char *)dest + len - 1;
        while(count --){
            *(char *)dest = *(char *)src;
            dest = (char *)dest - 1;
            src = (char *)src - 1;
        }
    }
    return rst;
}
PS:按照ANSI(American National Standards Institute)标准,不能对void指针进行算法操作,即不能对void指针进行如p++的操作,所以需要转换为具体的类型指针来操作,例如char *。

【strncpy】
函数原型:函数原型char*strncpy(char*dest,char*src,size_t num);
功能:复制字符串src中的内容(字符,数字、汉字….)到字符串dest中,复制多少由num的值决定。

代码:

/**
这个函数会出现三种情况:
1、num<src串的长度(包含最后的'\0'字符):那么该函数将会拷贝src的前num个字符到dest串中(不会自动为dest串加上结尾的'\0'字符)
2、num=src串的长度(包含最后的'\0'字符):那么该函数将会拷贝src的全部字符到dest串中(包括source串结尾的'\0'字符);
3、num>src串的长度(包含最后的'\0'字符):那么该函数将会拷贝src的全部字符到destination串中(包括source串结尾的'\0'字符),并且在dest串的结尾继续加上'\0'字符,直到拷贝的字符总个数等于num为止。
*/
char *  strncpy (char * dest,const char * src ,size_t num)
{
     char *rst= dest;
     while (num && (*dest++ =*src++)) /* copy string */
            num--;
     if (num) 
            while (--num)
            {       *dest++ = '\0';         }
     return (rst);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章