当前位置: 首页 > news >正文

控制台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字符。

下面就来看一个例子:

1

2

3

4

5

6

7

8

9

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函数

1

2

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对象在内存中用一个计数器来维持可用缓冲区的大小

1

2

3

4

5

6

7

8

void ReleaseBuffer( int nNewLength = -1 )

{

      if( nNewLength == -1 )

      {

           nNewLength = StringLength( m_pszData );

      }

      SetLength( nNewLength );

}

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

 

CString::ReleaseBuffer函数

1

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缓冲区被重新分配

1

2

3

4

5

6

7

8

// 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的地址可能因为其他的操作变化了。

实例分析

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

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就可以了。

相关文章:

  • PDFsharp使用介绍
  • 详解开源免费且稳定实用的.NET PDF打印组件itextSharp
  • 机器人是什么
  • C++中L和_T()之区别
  • 关于 wcout 输出中文的问题
  • 非静态成员必须与特定对象相对
  • 压缩文件修复
  • 循环冗余校验(CRC)算法入门引导
  • C++ getline函数用法详解
  • cout后面输出时加endl和不加endl的区别
  • iostream
  • ChromeNativeMessaging 原生消息通信
  • IT前端开发和后端开发
  • socket原理及实例
  • 关于iostream与using namespace std 的解析
  • CentOS7 安装JDK
  • ComponentOne 2017 V2版本正式发布
  • FastReport在线报表设计器工作原理
  • go语言学习初探(一)
  • JS创建对象模式及其对象原型链探究(一):Object模式
  • Mithril.js 入门介绍
  • Terraform入门 - 1. 安装Terraform
  • Zsh 开发指南(第十四篇 文件读写)
  • 聊一聊前端的监控
  • 如何学习JavaEE,项目又该如何做?
  • 事件委托的小应用
  • 一些关于Rust在2019年的思考
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • RDS-Mysql 物理备份恢复到本地数据库上
  • 阿里云API、SDK和CLI应用实践方案
  • 专访Pony.ai 楼天城:自动驾驶已经走过了“从0到1”,“规模”是行业的分水岭| 自动驾驶这十年 ...
  • #LLM入门|Prompt#3.3_存储_Memory
  • #我与Java虚拟机的故事#连载18:JAVA成长之路
  • #中的引用型是什么意识_Java中四种引用有什么区别以及应用场景
  • (14)学习笔记:动手深度学习(Pytorch神经网络基础)
  • (52)只出现一次的数字III
  • (function(){})()的分步解析
  • (安卓)跳转应用市场APP详情页的方式
  • (二)c52学习之旅-简单了解单片机
  • (二)Linux——Linux常用指令
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (转载)PyTorch代码规范最佳实践和样式指南
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .net core Swagger 过滤部分Api
  • .net mvc部分视图
  • .NET/C# 推荐一个我设计的缓存类型(适合缓存反射等耗性能的操作,附用法)
  • .NET使用HttpClient以multipart/form-data形式post上传文件及其相关参数
  • @test注解_Spring 自定义注解你了解过吗?
  • [Android]如何调试Native memory crash issue
  • [BeginCTF]真龙之力
  • [C# 开发技巧]如何使不符合要求的元素等于离它最近的一个元素
  • [Enterprise Library]调用Enterprise Library时出现的错误事件之关闭办法
  • [hive] posexplode函数
  • [HTML]Web前端开发技术29(HTML5、CSS3、JavaScript )JavaScript基础——喵喵画网页
  • [HTML]Web前端开发技术6(HTML5、CSS3、JavaScript )DIV与SPAN,盒模型,Overflow——喵喵画网页