函数重现系列导航
1. 函数简介
strncpy 函数为 C 库函数之一,用于字符串的拷贝。
- 原型:
char* strncpy(char* dest, const char* src, size_t num);
- 所属头文件:<string.h>
- 功能:将
src
指向的字符串的前num
个字节拷贝到dest
指向的内存空间,当num
大于src
所指向的字符串长度时,多余部分字符将由\0
填充。- 返回:指向目标字符串的指针。
2. 函数说明
- 既然为 strncpy 函数的重现,那么所重现的 strncpy 函数的基本功能、调用方法应与原库函数保持一致。
- 在确保
dest
所指向的有效内存空间足够大的情况下,strncyp 的推荐用法为strncyp(buf, p, strlen(p) + 1);
,使用strlen(p) + 1
作为num
保证了拷贝完后dest
指向的字符串以\0
结尾。- strncpy 函数支持内存覆盖,且能正确地完成内存覆盖,即能保证目标字符串数据的完整性。当可能发生内存覆盖(源字符串在目标字符串之前)时,应先定位到源字符串与目标字符串的第
num
个字符处,从后向前进行字符串的拷贝。为了提高拷贝效率,可以按位宽进行拷贝后再按字符拷贝。- 函数返回值为目标字符串是为了让函数能够支持链式表达式,例如
strlen(strncpy(..))
、printf("%s\n",strncpy(..))
等。
3. 函数重现:
char* strncpy(char* dest, const char* src, size_t num)
{
// 如果两指针指向相同的内存地址,则直接返回即可
if (dest == src)
{
return dest;
}
int src_len = 0;
const char* psrc = src;
while (*psrc++ != '\0')
{
src_len++;
}
// 计算出实际需要拷贝的字节数
const int new_num = num > src_len? src_len : num;
// 计算出以位宽为最小单位的个数以及剩余部分的字节数
int word_num = new_num / sizeof(size_t);
int byte_slice = new_num % sizeof(size_t);
if (src < dest)
{
char* bdest = (char*)((char*)dest + new_num - 1);
const char* bsrc = (char*)((char*)src + new_num - 1);
// 按字节从后向前拷贝
while (byte_slice--)
{
*bdest-- = *bsrc--;
}
size_t* wdest = (size_t*)((size_t*)dest + word_num - 1);
const size_t* wsrc = (size_t*)((size_t*)src + word_num - 1);
// 按位宽从后向前拷贝
while (word_num--)
{
*wdest-- = *wsrc--;
}
}
else
{
size_t* wdest = (size_t*)dest;
const size_t* wsrc = (size_t*)src;
char* bdest = (char*)((size_t*)dest + word_num);
const char* bsrc = (char*)((size_t*)src + word_num);
// 按位宽从前向后拷贝
while (word_num--)
{
*wdest++ = *wsrc++;
}
// 按字节从前向后拷贝
while (byte_slice--)
{
*bdest++ = *bsrc++;
}
}
if (num > src_len)
{
// 计算出拷贝长度大于源字符串长度的字节数,并尽量按位宽为单位进行拷贝
int word_surplus = (num - src_len) / sizeof(size_t);
int byte_surplus = (num - src_len) % sizeof(size_t);
char* bdest = dest + src_len;
while (byte_surplus-- > 0)
{
*bdest++ = '\0';
}
size_t* wdest = (size_t*)bdest;
while (word_surplus-- > 0)
{
*wdest++ = 0;
}
}
return dest;
}