今天被一个c函数折腾了好久,主要是遇到两方面问题:
问题1:
strncpy_s到底几个参数??
上网查原型
_ACRTIMP errno_t __cdecl strncpy_s(
_Out_writes_z_(_SizeInBytes) char* _Destination,
_In_ rsize_t _SizeInBytes,
_In_reads_or_z_(_MaxCount) char const* _Source,
_In_ rsize_t _MaxCount
);
明明是4个撒,但是我用4个参数调用死活不行,就像这样
char str1[20]; char str2[30]; char* str3; strncpy_s(str1, str2, 15);//不报错 strncpy_s(str3, str2, 15);//提示参数错误 strncpy_s(str3, 15,str2, 15);//不报错
类似代码中的问题折腾半天,后来在发现是参数类型错误,str1是数组,当然也能当做指针,str3是指针,不能当做数组。两者作为函数参数时,str1隐含了数组长度作为参数,str3则没有长度,因此需要把其长度作为参数供函数使用。把数组长度作为函数的隐藏参数我不知道是编译器自动做出的改变还是c++标准就是如此,我是第一次遇到此问题,印象深刻。我查头文件时,并未发现strncpy_s有多个重载。
下面问题又来了,问题2:
strncpy_s(str3, 15,str2, 15);//不报错,但运行时报错 strncpy_s(str3, 16,str2, 15);//运行时不报错
截图如下:
strncpy_s第二个参数为目标字符串大小,第四个参数为源字符串长度。测试发现,当目标字符串长度 大于 源字符串长度时,函数成功完成。当目标字符串长度 等于或小于 源字符串长度时函数失败,并报运行时错误 “Buffer is too small” ??
小于时我能理解,等于时我不理解,也没有找到相关说明。
再次编写代码测试:
int main()
{
char s1[30];
char* p = s1;
char s2[] = "abcdefg";
char* p1 = (char*)malloc(sizeof(char) * 15);
memset(p1, 0, sizeof(char) * 15);
printf("转换前的长度n");
printf("s1长度:%lldn", strlen(s1));
printf("p长度:%lldn", strlen(p));
printf("s2长度:%lldn", strlen(s2));
printf("p1长度:%lldn", strlen(p1));
printf("转换后的长度n");
strncpy_s(p,8, s2,strlen(s2));
strncpy_s(p1, 8, s2, strlen(s2));
printf("s1长度:%lldn", strlen(s1));
printf("p长度:%lldn", strlen(p));
printf("s2长度:%lldn", strlen(s2));
printf("p1长度:%lldn", strlen(p1));
char s3[] = "qwertyuio lll";
char mask[] = "111111111111111";
strncpy_s(p1, 16, s3, 15);
strncpy_s(p1, 12, s3, 11);
printf("复制12个字符时p1内容:%sn", p1);
printf("复制12个字符时p1长度:%lldn", strlen(p1));
strncpy_s(p1, 10, s3, 9);
printf("复制9个字符时p1内容:%sn", p1);
printf("复制9个字符时p1长度:%lldn", strlen(p1));
strncpy_s(p1, 9, s3, 8);
printf("复制8个字符时p1内容:%sn", p1);
printf("复制8个字符时p1长度:%lldn", strlen(p1));
//printf("p长度:%lldn", sizeof(s2));
printf("%s", p1);
}
通过分析发现,指针或数组未初始化之前,strlen不能返回正确长度。
而后的输出证明:strncpy_s函数 在复制字符串时,会自动在末尾加上字符串结束符号' ',指示字符串结束,而其第四个参数仅指示需要复制的字符数,并不复制字符串隐含的结束符号' '。通过精心构造的字符串更深入分析会发现,strncpy_s在复制源字符串时,遇到' '就结束了,后面的根本就复制不进去,而复制后目标字符串长度正好在' '之前。
可以得出结论:strncpy_s在复制源字符串时,遇到' '结束符号就停止,而不管参数四中设置的源字符串长度大小。复制过程中只复制字符,不会复制' '结束符号。复制完成后,函数会在目标字符串末尾自动加上' '结束符号。若‘ ’结束符号位置超出了参数2中设置的源字符串长度,则会导致运行时错误。
因此,strncpy_s正确用法如下:
strncpys(pDstStr,nSourceLength+1,pSourceStr,nSourceLength);



