关于strcpy_s的使用

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++ = ' ';
posted @ 2012-03-20 18:42  kcy-666  阅读(23601)  评论(1编辑  收藏  举报