控制台console使用MFC库函数,Cout输出CString的方法
新建工程的时候选择:Win32 Console Application
在向导的地方勾选MFC头文件支持,确认即可
等待初始化文件完成后,VS2010会自动打开 项目名.cpp的文件
其中int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])这个相当于main函数
里面的内容全部可以删除,最后加上一句return 0;即可
MFC常用类:CString类
大家使用VS2010的话,可能会见到CStringT,实际上它是一个操作可变长度字符串的模板类。CStringT模板类有三个实例:CString、CStringA和CStringW,它们分别提供对TCHAR、char和wchar_t字符类型的字符串的操作。
char类型定义的是Ansi字符,wchar_t类型定义的是Unicode字符,而TCHAR取决于MFC工程的属性对话框中的Configuration Properties->General->Character Set属性,如果此属性为Use Multi-Byte Character Set,则TCHAR类型定义的是Ansi字符,而如果为Use Unicode Character Set,则TCHAR类型定义的是Unicode字符。
下面就来看一个例子:
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { CString str1(_T("www.jizhuomi.com")); //wcout << str1.GetString() << endl; cout << str1.GetString() << endl; return 0; }
上述的代码,根据字符串创建了一个CString对象,
因为CString本质上是个指针,而且运算符<<没重载CString的输出,所以用CString自带的GetString()成员函数把CString对象转换成一个字符串。但是前面有说过字符串有三种,TCHAR、char和wchar_t。TCHAR是一个三态模式,所以本质上字符串有两种,分别是:char类型定义的是Ansi字符,wchar_t类型定义的是Unicode字符。同时这两种字符串对应的输出函数是不一样的,char对应cout,wchar_t对应wcout。
所以在项目属性中如果把字符集设置为Unicode,那么CString的GetString()得到的就是wchar_t,所以要用wcout输出;如果在项目中把字符集设置为多字节字符集,那么CString的GetString()得到的就是char,所以要用cout输出。
CString转换为char *的方法
CString::GetBuffer函数
LPTSTR GetBuffer( int nMinBufLength ); throw( CMemoryException );
返回值:一个指向对象的(以null结尾的)字符缓冲区的LPTSTR指针。
参数:nMinBufLength 字符缓冲区的以字符数表示的最小容量。这个值不包括一个结尾的null占用的空间。
说明:
此成员函数返回一个指向CString对象的内部字符缓冲区的指针。返回的LPTSTR不是const,因此可以允许直接修改CString的内容。
如果你使用由GetBuffer返回的指针来改变字符串的内容,你必须在使用其它的CString成员函数之前调用ReleaseBuffer函数。
在调用ReleaseBuffer之后,由GetBuffer返回的地址也许就无效了,因为其它的CString操作可能会导致CString缓冲区被重新分配。
如果你没有改变此CString的长度,则缓冲区不会被重新分配。
当此CString对象被销毁时,其缓冲区内存将被自动释放。
注意:如果你自己知道字符串的长度,则你不应该添加结尾的null字符。但是,当你用ReleaseBuffer来释放该缓冲区时,你必须指定最后的字符串长度。
如果你添加了结尾的空字符,你应该给ReleaseBuffer的长度参数传递-1,ReleaseBuffer将对该缓冲区执行strlen来确定它的长度。
CString对象在内存中用一个计数器来维持可用缓冲区的大小
void ReleaseBuffer( int nNewLength = -1 ) { if( nNewLength == -1 ) { nNewLength = StringLength( m_pszData ); } SetLength( nNewLength ); }
很明显ReleaseBuffer的作用就是更新字符串的长度。 CString内,GetLength获取字符串长度并不是动态计算的,而是在赋值操作后计算并保存在一个int变量内的,当通过GetBuffer直接修改CString时,那个int变量并不可能自动更新,于是便有了ReleaseBuffer.
CString::ReleaseBuffer函数
void ReleaseBuffer( int nNewLength = -1 );
参数介绍:
nNewLength:
The new length of the string in characters, not counting a null terminator. If the string is null-terminated, the -1 default value sets the CString size to the current length of the string.
这个函数就是把CString::GetBuffer中申请的多余的空间释放到,参数nNewLength指明新的CString的长度(这个值的大小不包含null占用的那个空间)。如果这个string是null结束的,那么nNewLength就可以传递-1作为参数,这样的做就能把CString设置为原始的string的大小,后面再加上一个结束符号null。
Use ReleaseBuffer to end use of a buffer allocated by GetBuffer. If you know that the string in the buffer is null-terminated, you can omit the nNewLength argument. If your string is not null-terminated, then use nNewLength to specify its length. The address returned by GetBuffer is invalid after the call to ReleaseBuffer or any other CString operation.
这句话有点难理解,其实是这个样子的,原先用GetBuffer得到的buffer可能比CString中真实的大小要大的多,然后用一个指针指向这个buffer(GetBuffer返回的指针),同时注意这时的buffer指针和CString的起始地址是一样的。调用ReleaseBuffer后,CString后面多余的空间就通过CString中的表示字符长度的成员变量限制访问了,其实并没有释放内存,这时的buffer指针仍然是可以使用的,你仍然可以通过这个buffer指针访问到GetBuffer时设定的大小的空间。但是要注意,对CString的操作不能使用这个buffer的指针,因为再调用ReleaseBuffer之后,由GetBuffer返回的地址也许就无效了,因为其它的CString操作可能会导致CString缓冲区被重新分配。
// example for CString::ReleaseBuffer CString s; s = "abc"; LPTSTR p = s.GetBuffer( 1024 ); strcpy(p, "abc"); // use the buffer directly ASSERT( s.GetLength() == 3 ); // String length = 3 s.ReleaseBuffer(); // Surplus memory released, p is now invalid. ASSERT( s.GetLength() == 3 ); // Length still 3
在ReleaseBuffer调用之后不要使用p,因为CString的地址可能因为其他的操作变化了。
实例分析
CString s("abcd"); //创建一个CString对象s,对象的地址是0x0050b3074 int i = s.GetLength(); //s的长度为4,这个值是从CString类的一个int成员变量读取到的 printf("%s\n", s); printf("s length1 is %d\n", i); LPTSTR p = s.GetBuffer(6); //s的地址发生了变化,0x005b416c,也就是说重新分配了内存,p也指向这片内存,大小为6,里面存的是"abcd",以null结尾 strcpy( p, "123"); //把"123"copy到了这块内存,里面存的是"123",以null结尾 printf("%s\n", s); //打印出来的字符串是"123",以null结尾 int j = s.GetLength(); //虽然新的字符串是"123",但是字符串的长度成员变量没有被更新,所以还是4 printf("s length2 is %d\n", j); s.ReleaseBuffer(); //这里释放多余的空间,同时更新CString的长度成员变量的值为5,这里的释放不是物理上的释放内存,而是用代码控制,这块多余空间仍然是可用的,但是不安全 printf("%s\n", s); int k = s.GetLength(); printf("s length3 is %d\n", k); strcpy( p, "a1b2c3"); // 这里新指定的字串若为"a1b2c3e"则会在此中断,因为这个空间一开始的时候申请为6个大小,超过6个都是越界的。同时ReleaseBuffer把CString限定为了"123",所以这种方式复制会是CString内部一致性破坏。(Length和真实值不对应) printf("%s\n", s); //这里还是能通过p改变CString的内容的,但是不要这么做,因为CString的操作函数会改变CString的内存位置,有可能CString已经搬家了,这是p指向的就是垃圾内存。 //同时造成了CString中实际值和表示个数的成员变量不一致。 int m = s.GetLength(); printf("s length4 is %d\n", m);
通过指针p和字符串s 实行字符串动态增加的效果是完全不一样的,因为字符串s里有很多成员函数为之服务。
CString::GetString函数
这个函数很简单,就是把CString内的字符串转换为const char *,因为这个值是不允许改动的,所以比GetBuffer简单很多。这里就不多说了,只要注意转换后的字符串是char还是wchar_t就可以了。