Copying
memcpy
函数原型
void * memcpy ( void * destination, const void * source, size_t num );
复制代码
函数功能
将 num 字节的值从 source 指向的位置直接复制到 destination 指向的内存块。
destination 和 source 指向的对象的底层类型与此函数无关;结果是数据的二进制副本。
注意事项
该函数不检查 source 中的任何终止空字符,它总是精确地复制 num 个字节。为了避免溢出,目标和源参数指向的数组大小至少应为 num 字节,并且不应重叠(对于重叠的内存块,memmove 是一种更安全的方法)。
返回值
返回指向 destination 的指针
函数实现
void * memcpy ( void * destination, const void * source, size_t num ){ void * ptr = destination; if(NULL == destination || NULL == source || 0 == num) return ptr; while(num--) *(char*)ptr = *(char*)source; return ptr;}
复制代码
测试用例
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;}
output:person_copy: Pierre de Fermat, 46
复制代码
memmove
函数原型
void * memmove ( void * destination, const void * source, size_t num );
复制代码
函数功能
与 memcpy()完全一样,唯一的区别在于 memmove()可以处理内存块重叠的情况
模拟实现
void* memmove(void* destination, const void* source, size_t num) { if (NULL == destination || NULL == source || 0 == num) return destination;
char* pdes = (char*)destination; char* psrc = (char*)source;
if (pdes < psrc) while (num--) *pdes++ = *psrc++; else { char* lastdes = pdes + (num - 1); char* lastsrc = psrc + (num - 1); while (num--) *lastdes-- = *lastsrc--; } return destination;}
复制代码
库函数的实现是通过使用额外的内存保存 source 的内容,再将其复制到 destination,上述实现进行了优化,避免了额外的内存开销。
此外,上面采取的是所谓的 byte-to-byte-copy,除此之外,应该考虑到字节对齐问题,从内存对齐边界开始拷贝会有许多的优化方案可以使用,我们还可以使用 word-to-word-copy,page-to-page-copy 等。
测试用例
int main (){ char str[] = "memmove can be very useful......"; memmove (str+20,str+15,11); puts (str); return 0;}
output:memmove can be very very useful.
复制代码
strcpy
函数原型
char * strcpy ( char * destination, const char * source );
复制代码
函数功能
将源指向的 C 字符串复制到目标指向的数组中,包括终止的空字符(并在该处停止)。
注意事项
为避免溢出,destination 指向的数组大小应足够长,以包含与 source 相同的 C 字符串(包括终止的空字符),并且不应在内存中与 source 重叠。
返回值
返回 destination 指针
模拟实现
char* strcpy(char* destination,const char* source){ char* pdes = destination;
if(NULL == destination || NULL == source) return pdes;
while((*(pdes++) = *(source++))!='\0'); return destination;}
复制代码
测试用例
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;}
output:str1: Sample stringstr2: Sample stringstr3: copy successful
复制代码
strncpy
函数原型
char * strncpy ( char * destination, const char * source, size_t num );
复制代码
函数功能
与 strcpy()相比,除了以 source 中出现'\0'结束符外,还以复制完 num 个字节后函数执行结束。
注意事项
注意以 num 为结束条件时,destination 是否带有'\0'结束符
模拟实现
char* strncpy(char* destination,const char* source, size_t num){ char* pdest = destination;
if(NULL == destination || NULL == source || 0 == num) return destination;
while((num--)&&((*(pdest++) = *(source++))!='\0')); return destination;}
复制代码
测试用例
int main (){ char str1[]= "To be or not to be"; char str2[40]; char str3[40];
/* copy to sized buffer (overflow safe): */ strncpy ( str2, str1, sizeof(str2) );
/* partial copy (only 5 chars): */ strncpy ( str3, str2, 5 ); str3[5] = '\0'; /* null character manually added */
puts (str1); puts (str2); puts (str3);
return 0;}
output:To be or not to beTo be or not to beTo be
复制代码
Concatenation
strcat
函数原型
char * strcat ( char * destination, const char * source );
复制代码
函数功能
将 source 字符串的副本附加到 destination 字符串。destination 中终止的空字符将被源的第一个字符覆盖,并且空字符将包含在由目标中的两个字符串联而成的新字符串的末尾。
注意事项
目的地和来源地不得重叠。destination 的长度必须能容纳 source 的长度(即 sizeof(destination) > strlen(destination)+strlen(source))
返回值
返回 destination 指针
模拟实现
char* strcat(char* destination, const char* source) { if (NULL == destination || NULL == source) return destination;
char* pdest = destination; while (*pdest != '\0') pdest++;
const char* psrc = source;
while (*psrc != '\0') *(pdest++) = *(psrc++);
return destination;}
复制代码
测试用例
int main (){ char str[80] = {0}; strcpy (str,"these "); strcat (str,"strings "); strcat (str,"are "); strcat (str,"concatenated."); puts (str); return 0;}
output:these strings are concatenated.
复制代码
strncat
函数原型
char * strncat ( char * destination, const char * source, size_t num );
复制代码
函数功能
与 strcat()功能基本一样,增加了额外的终止条件,source 的前 num 个字符附加到目标,再加上一个终止的空字符。
模拟实现
char* strncat(char* destination, const char* source, size_t num) { if (NULL == destination || NULL == source) return NULL;
char* pdest = destination; while (*pdest != '\0') pdest++;
const char* psrc = source;
while (*psrc != '\0' && (num--)) *(pdest++) = *(psrc++);
if(0 == num) pdest = '\0';
return destination;}
复制代码
测试用例
int main (){ char str1[20] = {0}; char str2[20] = {0}; strcpy (str1,"To be "); strcpy (str2,"or not to be"); strncat (str1, str2, 6); puts (str1); return 0;}
output:To be or not
复制代码
Comparison
memcmp
函数原型
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
复制代码
函数功能
将 ptr1 所指向的内存块的前 num 个字节与 ptr2 所指向的前 num 个字节进行比较。
注意事项
对自定义数据类型进行比较时,注意内存对齐,保证所有内存都已被初始化。
返回值
如果它们都匹配,则返回零;如果不匹配,则会返回一个不同于零的值,表示哪个更大。
模拟实现
int memcmp ( const void * ptr1, const void * ptr2, size_t num ){ assert(NULL == ptr1 ); assert(NULL == ptr2 ); assert(0 == num);
while (--num &&*(char*) ptr1 == *(char *)ptr2) { ptr1 = (char *)ptr1 + 1; ptr2 = (char *)ptr2 + 1; }
return (*(unsigned char*) ptr1 - *(unsigned char*)ptr2 );}
复制代码
测试用例
int main (){ char buffer1[] = "DWgaOtP12df0"; char buffer2[] = "DWGAOTP12DF0";
int res = memcmp ( buffer1, buffer2, sizeof(buffer1) );
if (res > 0) printf ("'%s' is greater than '%s'.\n",buffer1,buffer2); else if (res < 0) printf ("'%s' is less than '%s'.\n",buffer1,buffer2); else printf ("'%s' is the same as '%s'.\n",buffer1,buffer2);
return 0;}
output'DWgaOtP12df0' is greater than 'DWGAOTP12DF0'.
复制代码
strcmp
函数原型
int strcmp ( const char * str1, const char * str2 );
复制代码
函数功能
将 C 字符串 str1 与 C 字符串 str2 进行比较。此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续使用以下对,直到字符不同或到达终止的空字符。
返回值
如果它们都匹配,则返回零;如果不匹配,则会返回一个不同于零的值,表示哪个更大。
注意事项
strcmp()函数用于字符串的比较。memcmp()即使遇到'\0'也会继续比较,两者的入参不一样,结束条件不一样。
模拟实现
int strcmp ( const char * str1, const char * str2 ){ assert(NULL == str1 ); assert(NULL == str2 );
while ((*str1 != '\0') && (*str2 = '\0')&& *(str1++) == *(str2++));
return (*str1 - *str2 );}
复制代码
测试用例
int main (){ char key[] = "apple"; char buffer[80] = {0}; do { printf ("Guess my favorite fruit? "); fflush (stdout); scanf ("%79s",buffer); } while (strcmp (key,buffer) != 0); puts ("Correct answer!"); return 0;}
output:Guess my favourite fruit? orangeGuess my favourite fruit? appleCorrect answer!
复制代码
others
memset
函数原型
void * memset ( void * ptr, int value, size_t num );
复制代码
函数功能
将 ptr 指向的内存块的前 num 字节设置为指定值(解释为无符号字符)。
注意事项
是按字节进行初始化内存,一般初始化为 0。
返回值
返回指针 ptr
模拟实现
void * memset ( void * ptr, int value, size_t num ){ if( NULL == ptr || 0 == num) return ptr; char* p = (char*) ptr; while(num--) *(p++) = value; return ptr;}
复制代码
测试用例
int main (){ char str[] = "almost every programmer should know memset!"; memset (str,'-',6); puts (str); return 0;}
output:------ every programmer should know memset!
复制代码
strlen
函数原型
size_t strlen ( const char * str );
复制代码
函数功能
计算字符串 str 的长度(不计算空字符)
注意事项
与 sizeof 的区别,sizeof()是关键字,而 strlen()是函数,sizeof()计算空字符,而 strlen()不计算空字符
返回值
字符串 str 的长度
模拟实现
size_t strlen ( const char * str ){ if(NULL == str) return 0; size_t count = 0; while(*(str++)!='\0') count++; return count;}
复制代码
测试用例
int main() { char szInput[256] = "123456"; cout << Mystrlen(szInput) << endl; cout << sizeof(szInput) << endl; return 0;}
output:6256
复制代码
评论