strcpy_s是strcpy的安全版本,它之所以安全,是因为其在拷贝字符串的时候会有越界的检查工作。以下是strcpy_s的实现代码,在tcscpy_s.inl文件可以找到:
/***
*tcscpy_s.inl - general implementation of _tcscpy_s
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* This file contains the general algorithm for strcpy_s and its variants.
*
****/
_FUNC_PROLOGUE
errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC)
{
_CHAR *p;
size_t available;
/* validation section */
_VALIDATE_STRING(_DEST, _SIZE);
_VALIDATE_POINTER_RESET_STRING(_SRC, _DEST, _SIZE);
p = _DEST;
available = _SIZE;
while ((*p++ = *_SRC++) != 0 && --available > 0)
{
}
if (available == 0)
{
_RESET_STRING(_DEST, _SIZE);
_RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);
}
_FILL_STRING(_DEST, _SIZE, _SIZE - available + 1);
_RETURN_NO_ERROR;
}
_VALIDATE_STRING应该是验证字符串的合法性,是否以null结尾。
_VALIDATE_POINTER_RESET_STRING应该是记录字符串的原始信息,以便拷贝失败以后恢复。
当目的地空间不够时,会根据_VALIDATE_POINTER_RESET_STRING记录的信息恢复字符串,并且(在Debug模式下)以弹出对话框的形式报告错误。
_FILL_STRING完成在字符串最后加上null结束符的工作。以前没有注意到这一点,所以犯了一个以下的错误,先看源代码:
const int ALLOC_GRANULARITY = 64 * 1024; //分配粒度:64K
//随机产生一个指定范围内的随机数
inline int RandomGen(int nMin, int nMax)
{
return (rand() % (nMax - nMin + 1) + nMin);
}
int _tmain(int argc, _TCHAR* argv[])
{
srand((unsigned)time(NULL));
char *pBuf = new char[ALLOC_GRANULARITY]; //缓存
//读取500个单词到vector
vector<string> vecWord; //存放单词的vector
//省略读取F:\\hp1.txt文件中的单词并存放在vector中的代码。。。。
//fill the buffer
string str;
char *p = pBuf;
str = vecWord[RandomGen(0, nWordNum-1)]; //get a string from the vector randomly
while ((p+str.length()) < pBuf + ALLOC_GRANULARITY)
{
//copy string into the buffer
strcpy_s(p, str.length()+1, str.c_str());
//set pointer p to the end of the string
p += str.length();
//把单词最后一个null符号用空格覆盖,然后指针前移,否则会导致pBuf指向的字符串始终是第一个得到的字符串
*p++ = ' ';
str = vecWord[RandomGen(0, nWordNum-1)]; //get a string from the vector randomly
}
vecWord.clear();
//省略写文件的代码。。。。
delete pBuf;
return 0;
}
以上需要的地方有如下几点:
1. string::c_str()返回的const char*是包含null结束符的,所以在使用strcpy_s需要在第二个参数指定缓冲区大小的时候加上1,因为string::length()返回的长度是不包括null结束符的
2. 要把每个单词都保存进pBuf中,还需要把每个单词的null结束符先覆盖掉,否则从pBuf读取字符串的时候只会读取到第一个存入的单词。所以这两行代码很重要:
//set pointer p to the end of the string
p += str.length();
//把单词最后一个null符号用空格覆盖,然后指针前移,否则会导致pBuf指向的字符串始终是第一个得到的字符串
*p++ = ' ';