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++ = ' ';
