精解CString类的GetBuffer,ReleaseBuffer 函数(VC++)

CString的GetBuffer用法

一.函数原型

CString::GetBuffer

LPTSTR GetBuffer( int nMinBufLength );

throw( CMemoryException );

Return Value

An LPTSTR pointer to the object’s (null-terminated) character buffer.

Parameters

nMinBufLength

The minimum size of the character buffer in characters. This value does not include space for a null terminator.

Remarks

Returns a pointer to the internal character buffer for the CString object. The returned LPTSTR is notconst and thus allows direct modification of CString contents.

If you use the pointer returned by GetBuffer to change the string contents, you must callReleaseBuffer before using any other CString member functions.

二.函数作用及使用范围

对一个CString变量,你可以使用的唯一合法转换符是LPCTSTR,直接转换成非常量指针(LPTSTR-[const] char*)是错误的。正确的得到一个指向缓冲区的非常量指针的方法是调用GetBuffer()方法。

GetBuffer()主要作用是将字符串的缓冲区长度锁定,releaseBuffer则是解除锁定,使得CString对象在以后的代码中继续可以实现长度自适应增长的功能。

CString ::GetBuffer有两个重载版本:

LPTSTR GetBuffer( );LPTSTR GetBuffer(int nMinBufferLength);

在第二个版本中,当设定的长度小于原字符串长度时,nMinBufLength = nOldLen,该参数会被忽

略,不分配内存,指向原CString;当设定的长度大于原字符串本身的长度时就要重新分配(reallocate)一块比较大的空间出来。而调用第一个版本时,应如通过传入0来调用第二个版本一样。

是否需要在GetBufer后面调用ReleaseBuffer(),是根据你的后面的程序是否需要继续使用该字符串变量,并且是否动态改变其长度而定的。如果你GetBuffer以后程序自函数就退出,局部变量都不存在了,调用不调用ReleaseBuffer没什么意义了。

最典型的应用就是读取文件:

CFile file;

// FILE_NAME 为实现定义好的文件名称

if(file.Open(FILE_NAME,CFile::modeRead))

{

       CString szContent;

       int nFileLength = file.GetLength();

       file.Read(szContent.GetBuffer(nFileLength),nFileLength);

       szContent.ReleaseBuffer();

       // 取得文件內容放在szContent中,我们之后可以对其操作

}

三.测试

以下就CString::GetBuffer,做简单测试:

测试1

// example for CString::GetBuffer

 

#include <stdio.h>

#include <afx.h>

 

void main(void)

{    

       CString s"abcd" );

       printf("(1)before GetBuffer:\n");

       printf("CString s.length=%d\n",s.GetLength());

       printf("CString s=%s\n",s);

      

       LPTSTR p = s.GetBuffer( 2 );

      

       printf("(2)after GetBuffer and before ReleaseBuffer:\n");

       printf("LPTSTR p=%s\n",p);    

       printf("p.length=%d\n",strlen(p));

printf("CString s=%s\n",s);      

       printf("CString s.length=%d\n",s.GetLength());

      

 

       s.ReleaseBuffer( );

       printf("(3)after ReleaseBuffer:\n");

       printf("LPTSTR p=%s\n",p);    

       printf("p.length=%d\n",strlen(p));

printf("CString s=%s\n",s);

       printf("CString s.length=%d\n",s.GetLength());    

}

测试结果1:

(1)before GetBuffer:

CString s.length=4

CString s=abcd

(2)after GetBuffer and before ReleaseBuffer:

LPTSTR p=abcd

p.length=4

CString s=abcd

CString s.length=4

(3)after ReleaseBuffer:

LPTSTR p=abcd

p.length=4

CString s=abcd

CString s.length=4

Press any key to continue

测试2:

LPTSTR p = s.GetBuffer( 2 ); 修改为:LPTSTR p = s.GetBuffer( 10 );

测试结果同1。

测试3:

在测试二的LPTSTR p = s.GetBuffer( 10 );后添加  p[5]='f';

测试结果同1。

测试4:

将测试三的p[5]='f';修改为p[4]='e';

测试结果4:

(1)before GetBuffer:

CString s.length=4

CString s=abcd

(2)after GetBuffer and before ReleaseBuffer:

LPTSTR p=abcde屯屯?

p.length=10

CString s=abcde屯屯?

CString s.length=4

(3)after ReleaseBuffer:

LPTSTR p=abcde屯屯?

p.length=10

CString s=abcde屯屯?

CString s.length=10

Press any key to continue

很显然(2)after GetBuffer and before ReleaseBuffer: CString s.length=4结果有问题。

注意:以上测试是在_MBCS环境下,如果换成_UNICODE则结果有可能不同。

参考:

《CString GetBuffer()》

http://blog.csdn.net/hbyh/archive/2007/09/15/1786574.aspx

CStringGetBuffer问题

http://game.tongji.net/thread-379834-1-1.html

《CString的GetBuffer》

http://www.programfan.com/blog/article.asp?id=40755

《CString GetBuffer() and ReleaseBuffer()》

http://blog.csdn.net/guanchanghui/archive/2006/09/13/1217096.aspx

CString::GetBuffer()与CString::ReleaseBuffer到底有什么用?

http://topic.csdn.net/t/20060313/22/4612156.html


====================================================================================================================

转载:http://blog.pfan.cn/xman/43212.html

GetBuffer()主要作用是将字符串的缓冲区长度锁定,releaseBuffer则是解除锁定,使得CString对象在以后的代码中继续可以实现长度自适应增长的功能。

CString ::GetBuffer有两个重载版本:

LPTSTR GetBuffer( );LPTSTR GetBuffer(int nMinBufferLength);

在第二个版本中,当设定的长度小于原字符串长度时,nMinBufLength = nOldLen,该参数会被忽

略,不分配内存,指向原CString;当设定的长度大于原字符串本身的长度时就要重新分配(reallocate)一块比较大的空间出来。而调用第一个版本时,应如通过传入0来调用第二个版本一样。

是否需要在GetBufer后面调用ReleaseBuffer(),是根据你的后面的程序是否需要继续使用该字符串变量,并且是否动态改变其长度而定的。如果你GetBuffer以后程序自函数就退出,局部变量都不存在了,调用不调用ReleaseBuffer没什么意义了。

这是一个非常容易被用错的函数,主要可能是由于大家对它的功能不太了解。其实点破的话,也不是那么深奥。
    GetBuffer(int size)是用来返回一个你所指定大小可写内存的成员方法。它和被重载的操作符LPCTSTR还是有点本质区别的,LPCTSTR是直接返回一个只读内存的指针,而GetBuffer则是返回一个可以供调用者写入的内存,并且,你可以给定大小。下面是个简单的,但也是非常典型的例子:
    int readFile(CString& str, const CString& strPathName)
    {
        FILE* fp = fopen(strPathName, "r"); // 打开文件
        fseek(fp, 0, SEEK_END);
        int nLen = ftell(fp); // 获得文件长度
        fseek(fp, 0, SEEK_SET); // 重置读指针
        char* psz = str.GetBuffer(nLen);
        fread(psz, sizeof(char), nLen, fp); //读文件内容
        str.ReleaseBuffer(); //千万不能缺少
        fclose(fp);
    }
    上面的函数是GetBuffer函数最典型的用法了,其实它就相当于申请一块nLen大小的内存,只不过,这块内存是被引用在CString对象的内部而已,这是非常有效的一种用法,如果不直接用GetBuffer函数来申请的话,那么你必须用new操作符(或者malloc()函数)在CString的外部申请,然后再将申请的内存拷贝到CString对象中,显然这是一个非常冗余的操作,会使你函数的效率大大下降。
    ReleaseBuffer函数是用来告诉CString对象,你的GetBuffer所引用的内存已经使用完毕,现在必须对它进行封口,否则 CString将不会知道它现在所包含的字符串的长度,所以在使用完GetBuffer之后,必须立即调用ReleaseBuffer函数重置 CString的内部属性,其实也就是头部信息。

 

补充一下:

GetBuffer说白了就两个功能:

1:就是将CString里面的内存交到外部一个来处理,外部可以直接修改它的内容。

2:重新修改CString的内存大小,这个数值不包含null结尾符。

另一个典型的用法:就是将CString里面的内容变为int或long型,需要先获取里面的内存指针。这样就可以先GetBuffer(内存大小)方便直接转换。

如果在外部修改了CString里面的内容,在重新使用CString之前,需调用ReleaseBuffer()也就是说,ReleaseBuffer不需要每次都调用。

MSDN原文:

If you use the pointer returned by GetBuffer to change the string contents, you must call ReleaseBuffer before using any other CSimpleStringTmember methods.

The buffer memory is automatically freed when the CSimpleStringT object is destroyed.

If you keep track of the string length yourself, you should not append the terminating null character. You must, however, specify the final string length when you release the buffer with ReleaseBuffer. If you do append a terminating null character, you should pass –1 (the default) for the length toReleaseBuffer, and ReleaseBuffer will perform a strlen on the buffer to determine its length.


=========================================================================================================================

CString str = "abcde\0cde";
输出字符串的值为: abcde

而字符串的长度为 s.GetLength() 的值为: 5

这是因为CString对象在赋值时只检查到'\0',后面的忽略了, 也就是说实际对象str内容为"abcde".

而str真正的存储空间为6(字符串以'\0'结尾).

所以说在字符长度和实际的空间是不一样的. 好!别跑!

请看下面有趣的程序:

CString str = "hello";

LPSTR pf = (LPSTR)(LPCSTR)s;

LPSTR pa = s.GetBuffer(0);

        你可以测得 pf == pa;

LPSTR pb = s.GetBuffer(10);

        你可以测得 pf != pb;

   

为什么:

我们都知道(LPSTR)(LPCSTR)s 实际指向对象str的实际字符串的内存地址, GetBuffer() 函数中的参数(其实就是重新申请的字符串的长度)如果小于等于先前的字符串长度, 则不会重新分配内存使用原来的内存所以 pf == pa, 如果大于先前的字符串长度, 则重新追加内存(也就是要复制原来的内容),

所以pf != pb.

   

注意GetBuffer()函数中的参数为重新申请的字符串的长度, 实际内存的大小应再加1.

  

CString s = "hello";

LPSTR pf = s.GetBuffer(0);

strcpy(pf,"hi");

这时对象str 的内容为 "hi"

但是s.GetLength()的值为5, 如果加上一条语句:

s.ReleaseBuffer();

则s.GetLength()的值为2

解释: 
CString对象在内存中用一个计数器来维持可用缓冲区的大小

void ReleaseBuffer( int nNewLength = -1 )
     {
          if( nNewLength == -1 )
          {
               nNewLength = StringLength( m_pszData );
          }
          SetLength( nNewLength );
     }

很明显ReleaseBuffer的作用就是更新字符串的长度。 CString内,GetLength获取字符串长度并不是动态计算的,而是在赋值操作后计算并保存在一个int变量内的,当通过GetBuffer直接修改CString时,那个int变量并不可能自动更新,于是便有了ReleaseBuffer.

  

CString s = "hello";

LPSTR pf = s.GetBuffer(0);

strcpy(pf,"hi");

LPSTR ps =  (LPSTR)(LPCSTR)s;    字符串缓冲区的首地址

*(ps+2) = 'x';

  则字符串的实际内容为:    "hixlo"

*(ps+6) = 'a';        出错, 因为对象s的实际空间为 6

  

CString s = "hello";

LPSTR pf = s.GetBuffer(10);

strcpy(pf,"hi");

LPSTR ps =  (LPSTR)(LPCSTR)s;    字符串缓冲区的首地址

*(ps+2) = 'x';

*(ps+5)= '\0';

 则字符串的实际内容还是为:    "hixlo"

*(ps+6) = 'a';         可以因为s对象的实际空间为11

  

说白了  ReleaseBuffer就是更新赋值之后的字符串的长度, 而实际空间没有根本的变化, GetBuffer才是使内存空间大小变化的罪魁祸首.

转载:http://blog.sciencenet.cn/blog-481152-427173.html

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值