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

参考:
参考1
参考2

问题提出

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

问题解决

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

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

#include
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;
}
  1. strcpy 和 strncpy 的区别?

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

strcpy特点:

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

strncpy特点:

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

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

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

strcpy函数缺陷:

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

strncpy函数缺陷:

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

解决缺陷的方法

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

  2. 使用替代函数: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;
}

你可能感兴趣的:(c,字符串)