【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);
}