strcpy和strncpy和memcpy和memmove四个函数对比分析

    技术2023-11-20  79

    参考: 参考1 参考2

    问题提出

    sizeof(str) 和 strlen(str) 的区别?strcpy 和 strncpy 的区别?strcpy 和 strncpy 函数为什么要返回dest的副本?strcpy 和 strncpy 函数的缺陷有哪些?你如何解决?有替代函数吗?

    问题解决

    sizeof(str) 和 strlen(str) 的区别?

    sizeof(str) 会计算str所占总空间的字节数,strlen(str)会计算字符串的有效长度,不包括’\0’。

    #include<iostream> using namespace std; int main() { // 测试 strlen() 和 sizeof() char str[] = { "hello hello" }; int len1 = strlen(str); int len2 = sizeof(str); cout << len1 << endl; // len1 = 11 cout << len2 << endl; // len2 = 12 system("pause"); return 0; } strcpy 和 strncpy 的区别?

    区别是strncpy有参数控制拷贝的个数,不像strcpy,strncpy不会向dest追加结束标记’\0’

    strcpy特点:

    将src拷贝到dest中,包括’\0’字符为避免溢出dest指向的空间应该足够大能够放的下src

    strncpy特点:

    如果src的前n个字节不含’\0’字符,则结果不会以’\0’字符结束。如果src的长度小于n个字节,则以’\0’填充dest直到复制完n个字节。如果src中有’\0’,例如:“abc\0def” 则只会复制abcsrc和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。 strcpy 和 strncpy 函数为什么要返回dest的副本?

    为了实现函数连级使用 例如:strcpy(str3, strcpy(str1,str2))

    strcpy 和 strncpy 函数的缺陷有哪些?你如何解决?有替代函数吗?

    strcpy函数缺陷:

    要程序员保证dest大小能够存放src包括’\0’,一旦dest空间不够会在别的内存中写入,很危险。可能有覆盖问题

    strncpy函数缺陷:

    如果src的前n个字符不包含’\0’字符,strncpy函数不会在末尾补上’\0’,打印时会有乱码。如果src的长度小于n个字节,则以’\0’填充dest直到复制完n个字节,如果n远大于src这会导致效率问题。可能有覆盖问题

    解决缺陷的方法

    正确使用这两个函数: 1.使用strcpy时人工确定dest大小足够 2.使用strncpy时,确保 n = dest - 1 例如: strncpy(path, src, sizeof(path) - 1); path[sizeof(path) - 1] = ‘\0’;

    使用替代函数:memmove(),解决src可能被覆盖问题

    strcpy()实现

    char* my_strcpy(char* dest, const char* src) { //assert(dest != NULL && src != NULL); char* save = dest; while ((*dest++ = *src++) != '\0'); return save; }

    strncpy() 实现

    char* my_strncpy(char* dest, const char* src, size_t count) { //assert(dest != NULL && src != NULL); char* save = dest; while (count--) { if (*src != '\0') *dest++ = *src++; else *dest++ = '\0'; } return save; }

    memcpy()实现

    void* my_memcpy(void* dest, const void* src, size_t count) { assert(dest != nullptr && src != nullptr); char* p = (char*)dest; char* q = (char*)src; if (p == q) return p; while (count--) { *p++ = *q++; } return dest; }

    memmove()实现

    void* my_memmove(void* dest, const void* src, size_t count) { assert(dest != nullptr && src != nullptr); if (dest < src) // dest尾巴可能和src头部重合 { char* p = (char*)dest; char* q = (char*)src; while (count--) { *p++ = *q++; } } else // src尾部可能和dest头部重合 { char* p = (char*)dest + count; char* q = (char*)src + count; while (count--) { *--p = *--q; } } return dest; }

    测试用例

    int main() { // 测试 my_strcpy 和 my_strncpy char dest[20]; my_strcpy(dest, str); my_strncpy(dest, str, 15); cout << dest << endl; // 测试 my_memcpy 和 my_memmove char s1[] = "123456789"; char s2[] = "123456789"; my_memcpy(s1 + 2, s1, 5); cout << "my_memcpy: " << s1 << endl; my_memmove(s2 + 2, s2, 5); cout << "my_memmove: " << s2 << endl; system("pause"); return 0; }
    Processed: 0.015, SQL: 9