Jump to content

Hello visitors, welcome to the Hacker World Forum!

Red Team 1949  (formerly CHT Attack and Defense Team) In this rapidly changing Internet era, we maintain our original intention and create the best community to jointly exchange network technologies. You can obtain hacker attack and defense skills and knowledge in the forum, or you can join our Telegram communication group to discuss and communicate in real time. All kinds of advertisements are prohibited in the forum. Please register as a registered user to check our usage and privacy policy. Thank you for your cooperation.

TheHackerWorld Official

Featured Replies

Posted

 

.不考虑内存重叠的strncpy

网上很多博客也写了这个函数,面试也常常会遇到,但是,我发现网上的很多代码都是有问题的,我们先看下大部分网上博客的实现:

char *strncpy(char *dst, const char *src, size_t len)
{
	assert(dst != NULL && src != NULL);
	char *res = dst;
	while (len--)
	{
		*dst++ = *src++;
	}
	return res;
}

看着好像没啥问题,但是,当src的长度小于len呢?这份代码没有处理这个问题。当src的长度小于len时,应该如何处理?《C和指针》p179给出的答案是:
“ 和strcpy一样,strncpy把源字符串的字符复制到目标数组。然而,它总是正好向dst写入len个字符。如果strlen(src)的值小于len,dst数组就用
额外的NUL字节填充到len长度,如果strlen(src)的值大于或等于len,那么只有len个字符被复制到dst中。”
注意!它的结果将不会以NUL字节结尾。(NUL即‘\0’).

由此可见,我们还需要判断strlen(src)是否小于len,如果是,还需要在dst后面添加NUL,因此,正确的代码应该如下:

char *strncpy(char *dest, const char *src, size_t len)
{
	assert(dest != NULL && src != NULL);
	char *res = dest;
	int offset = 0;
	if (strlen(src) < len)//src长度小于len
	{
		offset = len - strlen(src);
		len = strlen(src);
	}

	while (len--)
	{
		*dest++ = *src++;
	}
	while (offset--)
	{
		*dest++ = '\0';
	}
	return res;
}

使用这个函数,尤其需要注意,不要出现len>strlen(dst)的情况,如果len>strlen(dst),那么会破坏dst后面的内存:在这里插入图片描述
我们假设前面红色部分是dst,然后strncpy(dst,src,10);那么后面黄色部分的内存就被破坏了。strncpy是不负责检测len是否大于dst长度的。

总的来说,strncpy总是复制len个字符到dst指向的内存!!!

所以,还会出现下面的情况

char message[] = "abcd";
strncpy(message, "abcde",5);
cout << message;

输出是abcde烫烫烫烫烫烫烫烫烫烫烫烫烫烫 (结果不唯一)

message的内存是有5个字节的,但是将abcde拷贝过去时,最后面的‘\0’被覆盖了,strncpy并不会负责添加‘\0’到dst结尾,因此,输出该字符串是,会在e字符后面一直找到‘\0’才结束,因此就会出现乱码。

2.考虑内存重叠的strncpy

面试中经常会遇到让你写一个能够处理内存重叠的strncpy,标准库中的strncpy是不考虑内存重叠的,如果出现内存重叠,结果将是未定义的。
网上的很多博客也有这个代码的实现,其实很多也是有问题的,没有考虑src长度小于len的问题:

char *strncpy(char *dst, const char *src, size_t len)
{
	assert(dst != NULL && src != NULL);
	char *res = dst;
	if (dst >= src && dst <= src + len - 1)//重叠,从后向前复制
	{
		dst = dst + len - 1;
		src = src + len - 1;
		while (len--)
			*dst-- = *src--;
	}
	else
	{
		while (len--)
			*dst++ = *src++;
	}
	return res;
}

那么,如果要处理内存重叠,该怎么办?如果内存重叠和src的长度小于len这两种情况同时出现,又如何处理?在这里插入图片描述
见图,假设红色部分为src,黄色为dst。如果出现内存重叠,我们很容易想到:从后往前拷贝。如果src的长度小于len,则在后面补NUL。

char *strncpy(char *dst, const char *src, size_t len)
{
	assert(dst != NULL && src != NULL);
	char *res = dst;
	int offset = 0;
	char *tmp;
	if (strlen(src) < len)//src长度小于len
	{
		offset = len - strlen(src);
		len = strlen(src);
	}

	if (dst >= src && dst <= src + len - 1)//重叠,从后向前复制
	{
		dst = dst + len - 1;
		src = src + len - 1;
		tmp = dst;
		while (len--)
			*dst-- = *src--;
	}
	else
	{
		while (len--)
			*dst++ = *src++;
		tmp = dst;
	}
	while (offset--)
	{
		*tmp++ = '\0';
	}
	return res;
}

那么,如果len的值大于dst的值,就会破坏dst后面的内存空间,这应该是要避免的。

最后,我们看一个有意思的东西:(此处strncpy是考虑内存重叠的版本)
在这里插入图片描述
message的长度增加了0.0 当然 ,它后面的内存被破坏了,这可能带来严重的后果。
最后,使用strncpy时,最好自动添加‘\0’在结尾。

Create an account or sign in to comment

Recently Browsing 0

  • No registered users viewing this page.