1. strcpy和strncpy。
功能演示;
a) strcpy函数。
strcpy函数在C语言中被定义为不安全字符串拷贝函数,一般项目中都不允许使用。
原型:char *strcpy(char *dest, const char *src);
该函数不检查长度,若原字符传src的长度大于目的字符串dst的长度,拷贝则会出现数组越界,编译不会出现问题,运行就会段错误,因此不
建议使用该函数,除非能很好的控制。
b) strncpy函数。
strncpy被经常使用,因为该函数会有长度控制。
原型:char *strncpy(char *dest, const char *src, size_t n);
和strcpy不同的是多了一个size_t类型的参数,该参数表示要从src开始的地方拷贝n字节长度的数据到dst中,但是如果原字符串长度大于目的
字符串dst的长度,那么就会和strcpy一样,因此实际操作中n的长度为目的字符串dest长度 - 1.
为什么传入长度为目的字符串长度 - 1,如下演示例子,strncpy拷贝字符串并不会在末尾加上'\0'字符,因此一般留一个字节加'\0'结束符。
有的时候可以看到strlcpy函数,这个函数在低内核版本还不是Linux库函数,高版本是否加入未验证过,有兴趣的可以看下。
CHAR szbuf[6];
strncpy(szbuf,"012345678", sizeof(szbuf));
Before Copy FF FF FF FF FF FF FF FF // szbuf内容
After Copy 30 31 32 33 34 35 FF FF // 没有结尾\0
CHAR szbuf[6];
strncpy(szbuf, "0123", sizeof(szbuf));
Before Copy FF FF FF FF FF FF FF FF // szbuf内容
After Copy 30 31 32 33 00 00 FF FF // 修改了整个目的缓冲区
由上面的例子可以看出,strncpy也不是很完美,它在拷贝前会将整个缓冲区全清零,当然这个很多时候都被忽略的,因为在实际写代码过程中
我们申请一个数组,第二步初始化时就是一个memset将缓冲区清零了。
如果考虑到效率问题,最有效的初始化数组的方式如下:
char szBuff[512];
szBuff[0] = '\0';
只清零第一个字节时防止被误用,因为对字符串操作时就会用到strlen函数计算长度。
在实际开发中字符串操作都是自己封装接口,例如:
size_t My_Strcpy(OUT CHAR *pcDst, IN const CHAR *pcSrc, IN size_t ulDstSize)
{
size_t ulSrcLen;
size_t ulCpyLen;
ulSrcLen = strlen(pcSrc);
if ( 0 != ulDstSize)
{
ulCpyLen = (ulSrcLen >= ulDstSize) ? (ulDstSize - 1) : ulSrcLen;
memcpy(pcDst, pcSrc, ulCpyLen);
pcDst[ulCpyLen] = '\0';
}
return (size_t)ulSrcLen;
}
OUT、IN标示参数的输入输出,无实际意义。
2. strcat和strncat。
功能演示:
strcat、strncat和strcpy、strlcpy很类似。
a) strcat函数。
原型:char *strcat(char *dest, const char *src);
strcat如果拼接长度控制不好会出现拼接越界。
b) strncat函数。
原型: char *strncat(char *dest, const char *src, size_t n);
Before strncat 30 31 00 FF FF FF B0 84 // szbuf内容
After strncat 30 31 32 33 34 35 00 84 // 写越界一个字节
char szbuf[6];
strlcpy(szbuf, "01", sizeof(szbuf));
strncat(szbuf, "23", sizeof(szbuf)-strlen(szbuf));
Before strlcat 30 31 00 FF FF FF B0 84 // szbuf内容
After strlcat 30 31 32 33 00 FF B0 84
跟strncpy类似,如果拼接越界会截取字符串,但是末尾不会加'\0'字符,拼接时也会将缓冲区清零。
实际开发中自己封装一个anqua
3. snprintf函数和vsnprintf。
功能演示:
a)snprintf函数.
原型:int snprintf(char *str, size_t size, const char *format, ...);
snprinf接口主动加'\0',拼接时若源字符串较长,则截断拷贝,向目的buf拷贝size - 1个字符,然后加'\0',但返回长度是源字符串的
长度(不是实际写入的字符串长度)
char szBuf[5];
len = snprintf(szBuf, sizeof(szBuf), "%s", "1234567");
printf(" len : %d\r\n szBuf: %s\r\n", len, szBuf);
输出:
len : 7
szBuf: 1234
所以,该接口在累加拼装字符串时要保证缓冲区足够大。否则,可能写越界。如下:
char szBuf [10];
int len = 0;
int max = 10;
len += snprintf (szBuf +len, max-len, "%s", "12345"); // max-len = 10
len += snprintf (szBuf +len, max-len, "%s", "123456"); // max-len = 5
len += snprintf (szBuf +len, max-len, "%s", "12345"); // max-len = -1
len += snprintf (szBuf +len, max-len, "%s", "12345");
Segmentation fault.
b) vsnprintf函数。
原型:int vsnprintf(char *str, size_t size, const char *format, va_list ap);
snprinf接口主动加'\0',拼接时若源字符串较长,则截断拷贝,向目的buf拷贝size - 1个字符,然后加'\0',返回最终生成的字符
串长度。
char szBuf[512];
long ulCnt = 0;
szBuf [0] = '\0';
ulCnt += (long)nsprintf(szBuf + ulCnt, sizeof(szBuf) - ulCnt, "%s ", szIfName);
ulCnt += (long)nsprintf(szBuf + ulCnt, sizeof(szBuf) - ulCnt, "%4d ", uiVlanID);
ulCnt += (long)nsprintf(szBuf + ulCnt, sizeof(szBuf) - ulCnt, "%4d ", uiIfIndex);