admin 管理员组

文章数量: 887039


2024年1月25日发(作者:instron材料万能试验机价格)

CString,string 与Char 的转换

2007-05-17 21:41

//*********************************************************************

g to char pointer

//**********************************************************************

CString mystring = "abcde";

char *szmystring = (char *)(LPCTSTR)mystring;

char *pBuffer =new char[1024];

CString strBuf = "test";

pBuffer = fer(sizeof(pBuffer));

&

pBuffer=fer(gth);

//*************************************************************

pointer to CString

//*******************************************************************

char *mystring = "12345";

CString string = mystring;

("%s",mystring)

//******************************************************************

CString以及char*

//******************************************************************

string是方便的,可以从几乎所有的字符串构造而来,包括CString和char*;

CString次之,可以从基本的一些字符串变量构造而来,包括char*等;

char*没有构造函数,仅可以赋值;

举例:

char* psz = “joise”;

CString cstr( psz );

string str( cstr );

string是最方便的,几乎可以直接用所有的字符串赋值,包括CString和char*;

CString次之,可以直接用些基本的字符串赋值,包括char*等;

char*只能由指针赋值,并且是极危险的操作,建议使用strcpy或者memcpy,而且char*在声明的时候如未赋初值建议先设为NULL,以避免野指针,令你抓狂;

举例:

char *psz = NULL;

psz = new char[10]; //当然,以上的直接写成char *psz = new char[10];也是一样

memset( psz, 0, 10 );

strcpy( psz, “joise” );

CString cstr;

cstr = psz;

string str;

str = psz;

str = cstr;

delete []psz;

string与CString差不多,可以直接与char*进行加法,但不可以相互使用+运算符,即string str = str + cstr是非法的,须转换成char*;

char*没有+运算,只能使用strcat把两个指针连在一起;

举例:

char* psz = “joise”;

CString cstr = psz;

cstr = cstr + psz;

string str = psz;

str = str + str + psz;

strcat( psz, psz );

strcat( psz, cstr );//合法

strcat( psz, str );//非法,由此可见,CString可自动转换为const char*,而string不行

//******************************************************************************************************

//不明白的继续:

//*****************************************************************************************************

CString与char*的转换

CString与char*的转换

参见如下代码:

1 int i=m_gth();

2 char* p;

3 CString hex4="0";

4 CString hex5="0";

5 m_(0,-1);

6 m_eSel("");

7 p=m_fer(i);

8 for(int j=0;j

9 ("%x ",(unsigned char)*p++);

10 hex4+=hex5;

11 }

12 m_eSel(hex4);

其中m_edit3是一个CEdit类型的变量,SetSel,ReplaceSel都是其成员函数,可以参见MSDN。

在这里,m_edit1为一个CString类型的变量,p为字符串

这段代码的主要功能是:

将CString中的字符串转换成为16进制代码,在放置到字符串输出给用户查看。

主要变化流程 CString->char*->CString->CEdit

A.第5、6、12行主要是CEdit中显示CString的操作。

B.第7行主要功能是将CString赋值给字符串,即实现CString->char*的转换。

C.第1行主要是获得CString中字符串的长度,并不包含’0’在内。

D.第9、10行,利用CString的成员函数format将字符串中的数据一个个读取出来,并转换成为16进制数加入到CString中。

E.利用CEdit的成员函数ReplaceSel将CString中数据输出。

一个应用:

基于RC4算法的数据加密:

设置如下:

输入int类型数据,在下面转换成为16进制数据,代码如下:

void CC_R4Dlg::OnChangeEdit1()

{

UpdateData(TRUE);

int i=m_key;

m_("0x%x",i);

UpdateData(FALSE);

}

按钮“加密”的代码实现如下功能:

将明文的字符串变成16进制放置于明文块2中

将密文的字符串放置于密文块2中,16进制放置于密文块2中

void CC_R4Dlg::OnOK()

{

// TODO: Add extra validation here

int i=m_gth();

char* p;

rc4_key key;

UpdateData(TRUE);

UpdateData(FALSE);

//m_edit3

p=m_fer(i);

CString hex4="0";

CString hex5="0";

for(int j=0;j

("%x ",(unsigned char)*p++);

hex4+=hex5;

}

m_(0,-1);

m_eSel("");

m_eSel(hex4);

//m_edit2

p=m_fer(i);

prepare_key((unsigned char*)&m_key,sizeof(int),&key);

rc4((unsigned char*)p,i,&key);

CString hex = _T(p);

CString hex2="0";

CString hex3="0";

for(j=0;j

("%2X ",(unsigned char)*p++);

hex2+=hex3;

}

m_(0,-1);

m_eSel("");

m_eSel(hex2);

//m_edit4

m_(0,-1);

m_eSel("");

m_eSel(hex);

CString->TCHAR*的转化可以用函数GetBuff()

函数原型为:LPTSTR GetBuffer( int nMinBufLength );

CString str("CString");

TCHAR* szMsg = new TCHAR[100];

//其参数为CString字符串的长度

szMsg = fer(gth());

eBuffer();

delete []szMsg;

szMsg = NULL;

TCHAR*->CString的转化

TCHAR szTchar[18] = L"TCHAR";

CString str;

(_T("%s"),szTchar);

CString 是对于原来标准c中字符串类型的一种的包装。因为,通过很长时间的编程,我们发现,很多程序的bug多和字符串有关,典型的有:缓冲溢出、内存泄漏等。而 且这些bug都是致命的,会造成系统的瘫痪。因此c++里就专门的做了一个类用来维护字符串指针。标准c++里的字符串类是string,在 microsoft MFC类库中使用的是CString类。通过字符串类,可以大大的避免c中的关于字符串指针的那些问题。

这里我们简单的看看Microsoft MFC中的CString是如何实现的。当然,要看原理,直接把它的代码拿过来分析是最好的。MFC里的关于CString的类的实现大部分在中。

CString 就是对一个用来存放字符串的缓冲区和对施加于这个字符串的操作封装。也就是说,CString里需要有一个用来存放字符串的缓冲区,并且有一个指针指向该 缓冲区,该指针就是LPTSTR m_pchData。但是有些字符串操作会增建或减少字符串的长度,因此为了减少频繁的申请内存或者释放内存,CString会先申请一个大的内存块用来 存放字符串。这样,以后当字符串长度增长时,如果增加的总长度不超过预先申请的内存块的长度,就不用再申请内存。当增加后的字符串长度超过预先申请的内存 时,CString先释放原先的内存,然后再重新申请一个更大的内存块。同样的,当字符串长度减少时,也不释放多出来的内存空间。而是等到积累到一定程度 时,才一次性将多余的内存释放。

还有,当使用一个CString对象a来初始化另一个CString对象b时,为了节省空间,新对象b并不 分配空间,它所要做的只是将自己的指针指向对象a的那块内存空间,只有当需要修改对象a或者b中的字符串时,才会为新对象b申请内存空间,这叫做写入复制 技术(CopyBeforeWrite)。

这样,仅仅通过一个指针就不能完整的描述这块内存的具体情况,需要更多的信息来描述。

首先,需要有一个变量来描述当前内存块的总的大小。

其次,需要一个变量来描述当前内存块已经使用的情况。也就是当前字符串的长度

另外,还需要一个变量来描述该内存块被其他CString引用的情况。有一个对象引用该内存块,就将该数值加一。

CString中专门定义了一个结构体来描述这些信息:

struct CStringData

{

long nRefs; // reference count

int nDataLength; // length of data (including terminator)

int nAllocLength; // length of allocation

// TCHAR data[nAllocLength]

TCHAR* data() // TCHAR* to managed data

{ return (TCHAR*)(this+1); }

};

实际使用时,该结构体的所占用的内存块大小是不固定的,在CString内部的内存块头部,放置的是该结构体。从该内存块头部开始的sizeof(CstringData)个BYTE后才是真正的用于存放字符串的内存空间。这种结构的数据结构的申请方法是这样实现的:

pData = (CStringData*) new BYTE[sizeof(CStringData) +

(nLen+1)*sizeof(TCHAR)];

pData->nAllocLength = nLen;

其中nLen是用于说明需要一次性申请的内存空间的大小的。

从代码中可以很容易的看出,如果想申请一个256个TCHAR的内存块用于存放字符串,实际申请的大小是:

sizeof(CStringData)个BYTE + (nLen+1)个TCHAR

其中前面sizeof(CstringData)个BYTE是用来存放CstringData信息的。后面的nLen+1个TCHAR才是真正用来存放字符串的,多出来的一个用来存放’0’。

CString中所有的operations的都是针对这个缓冲区的。比如LPTSTR

CString::GetBuffer(int nMinBufLength),它的实现方法是:

首先通过CString::GetData()取得CStringData对象的指针。该指针是通过存放字符串的指针m_pchData先后偏移sizeof(CstringData),从而得到了CStringData的地址。

然后根据参数nMinBufLength给定的值重新实例化一个CStringData对象,使得新的对象里的字符串缓冲长度能够满足nMinBufLength。

然后在重新设置一下新的CstringData中的一些描述值。C

最后将新CStringData对象里的字符串缓冲直接返回给调用者。

这些过程用C++代码描述就是:

if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)

{

// we have to grow the buffer

CStringData* pOldData = GetData();

int nOldLen = GetData()->nDataLength; // AllocBuffer will tromp it

if (nMinBufLength < nOldLen)

nMinBufLength = nOldLen;

AllocBuffer(nMinBufLength);

memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(TCHAR));

GetData()->nDataLength = nOldLen;

CString::Release(pOldData);

}

ASSERT(GetData()->nRefs <= 1);

// return a pointer to the character storage for this string

ASSERT(m_pchData != NULL);

return m_pchData;

Tag:

breadtree2006 @ 21:36:04 | 阅读全文 | 评论 0 | 引用 0 | 编辑

LPCTSTR

2007-06-14 - [数据类型]

L表示long指针

这是为了兼容Windows 3.1等16位操作系统遗留下来的,在win32中以及其他的32为操作系统中, long指针和near指针及far修饰符都是为了兼容的作用。没有实际意义。

P表示这是一个指针

C表示是一个常量

T表示在Win32环境中, 有一个_T宏

这个宏用来表示你的字符是否使用UNICODE, 如果你的程序定义了UNICODE或者其他相关的宏,那么这个字符或者字符串将被作为UNICODE字符串,否则就是标准的ANSI字符串。

STR表示这个变量是一个字符串

所以LPCTSTR就表示一个指向常固定地址的可以根据一些宏定义改变语义的字符串。

同样, LPCSTR就只能是一个ANSI字符串,在程序中我们大部分时间要使用带T的类型定义。

LPCTSTR == const TCHAR *

CString 和 LPCTSTR 可以说通用。 原因在于CString定义的自动类型转换,没什么奇特的,最简单的C++操作符重载而已。

常量字符串ansi和unicode的区分是由宏_T来决定的。但是用_T("abcd")时, 字符串"abcd"就会根据编译时的是否定一_UNICODE来决定是char* 还是 w_char*。 同样,TCHAR 也是相同目的字符宏。 看看定义就明白了。简单起见,下面只介绍 ansi 的情况,unicode 可以类推。

ansi情况下,LPCTSTR 就是 const char*, 是常量字符串(不能修改的)。

而LPTSTR 就是 char*, 即普通字符串(非常量,可修改的)。

这两种都是基本类型, 而CString 是 C++类, 兼容这两种基本类型是最起码的任务了。

由于const char* 最简单(常量,不涉及内存变更,操作迅速), CString 直接定义了一个类型转换函数

operator LPCTSTR() {......}, 直接返回他所维护的字符串。

当你需要一个const char* 而传入了CString时, C++编译器自动调用 CString重载的操作符 LPCTSTR()来进行隐式的类型转换。

当需要CString , 而传入了 const char* 时(其实 char* 也可以),C++编译器则自动调用CString的构造函数来构造临时的 CString对象。

因此CString 和 LPCTSTR 基本可以通用。

但是 LPTSTR又不同了,他是 char*, 意味着你随时可能修改里面的数据,这就需要内存管理了(如字符串变长,原来的存贮空间就不够了,则需要重新调整分配内存)。

所以 不能随便的将 const char* 强制转换成 char* 使用。

楼主举的例子

LPSTR lpstr = (LPSTR)(LPCTSTR)string;

就是这种不安全的使用方法。

这个地方使用的是强制类型转换,你都强制转换了,C++编译器当然不会拒绝你,但同时他也认为你确实知道自己要做的是什么。因此是不会给出警告的。

强制的任意类型转换是C(++)的一项强大之处,但也是一大弊端。这一问题在 vc6 以后的版本(仅针对vc而言)中得到逐步的改进(你需要更明确的类型转换声明)。

其实在很多地方都可以看到类似

LPSTR lpstr = (LPSTR)(LPCTSTR)string;

地用法,这种情况一般是函数的约束定义不够完善的原因, 比如一个函数接受一个字符串参数的输入,里面对该字符串又没有任何的修改,那么该参数就应该定义成 const char*, 但是很多初学者弄不清const地用法,或者是懒, 总之就是随意写成了 char* 。 这样子传入CString时就需要强制的转换一下。

这种做法是不安全的,也是不被建议的用法,你必须完全明白、确认该字符串没有被修改。

CString 转换到 LPTSTR (char*), 预定的做法是调用CString的GetBuffer函数,使用完毕之后一般都要再调用ReleaseBuffer函数来确认修改 (某些情况下也有不调用

ReleaseBuffer的,同样你需要非常明确为什么这么做时才能这样子处理,一般应用环境可以不考虑这种情况)。

同时需要注意的是, 在GetBuffer 和 ReleaseBuffer之间,CString分配了内存交由你来处理,因此不能再调用其他的CString函数。

CString 转LPCTSTR:

CString cStr;

const char *lpctStr=(LPCTSTR)cStr;

LPCTSTR转CString:

LPCTSTR lpctStr;

CString cStr=lpctStr;

如何将CString类型的变量赋给char*类型的变量

1、GetBuffer函数:

使用CString::GetBuffer函数。

char *p;

CString str="hello";

p=fer(gth());

eBuffer();

将CString转换成char * 时

CString str("aaaaaaa");

strcpy(fer(10),"aa");

eBuffer();

当我们需要字符数组时调用GetBuffer(int n),其中n为我们需要的字符数组的长度.使用完成后一定要马

上调用ReleaseBuffer();

还有很重要的一点就是,在能使用const char *的地方,就不要使用char *

2、memcpy:

CString mCS=_T("cxl");

char mch[20];

memcpy(mch,mCS,20);

3、用LPCTSTR强制转换: 尽量不使用

char *ch;

CString str;

ch=(LPSTR)(LPCTSTR)str;

CString str = "good";

char *tmp;

sprintf(tmp,"%s",(LPTSTR)(LPCTSTR)str);

4、

CString Msg;

Msg=Msg+"abc";

LPTSTR lpsz;

lpsz = new TCHAR[gth()+1];

_tcscpy(lpsz, Msg);

char * psz;

strcpy(psz,lpsz);

CString类向const char *转换

char a[100];

CString str("aaaaaa");

strncpy(a,(LPCTSTR)str,sizeof(a));

或者如下:

strncpy(a,str,sizeof(a));

以上两种用法都是正确地. 因为strncpy的第二个参数类型为const char *.所以编译器会自动将CString类转换成const char *.

CString转LPCTSTR (const char *)

CString cStr;

const char *lpctStr=(LPCTSTR)cStr;

LPCTSTR转CString

LPCTSTR lpctStr;

CString cStr=lpctStr;

将char*类型的变量赋给CString型的变量

可以直接赋值,如:

CString myString = "This is a test";

也可以利用构造函数,如:

CString s1("Tom");

将CString类型的变量赋给char []类型(字符串)的变量

1、sprintf()函数

CString str = "good";

char tmp[200] ;

sprintf(tmp, "%s",(LPCSTR)str);

(LPCSTR)str这种强制转换相当于(LPTSTR)(LPCTSTR)str

CString类的变量需要转换为(char*)的时,使用(LPTSTR)(LPCTSTR)str

然而,LPCTSTR是const char *,也就是说,得到的字符串是不可写的!将其强制转换成LPTSTR去掉const,是极为危险的!

一不留神就会完蛋!要得到char *,应该用GetBuffer()或GetBufferSetLength(),用完后再调用ReleaseBuffer()。

2、strcpy()函数

CString str;

char c[256];

strcpy(c, str);

char mychar[1024];

CString source="Hello";

strcpy((char*)&mychar,(LPCTSTR)source);

关于CString的使用

1、指定 CString 形参

对于大多数需要字符串参数的函数,最好将函数原型中的形参指定为一个指向字符 (LPCTSTR) 而非

CString 的 const 指针。

当将形参指定为指向字符的 const 指针时,可将指针传递到 TCHAR 数组(如字符串 ["hi there"])或传递到 CString 对象。

CString 对象将自动转换成 LPCTSTR。任何能够使用 LPCTSTR 的地方也能够使用 CString 对象。

2、如果某个形参将不会被修改,则也将该参数指定为常数字符串引用(即 const CString&)。如果函数要修改该字符串,

则删除 const 修饰符。如果需要默认为空值,则将其初始化为空字符串 [""],如下所示:

void AddCustomer( const CString& name, const CString& address, const CString& comment = "" );

3、对于大多数函数结果,按值返回 CString 对象即可。

串的基本运算

对于串的基本运算,很多高级语言均提供了相应的运算符或标准的库函数来实现。

为叙述方便,先定义几个相关的变量:

char s1[20]="dir/bin/appl",s2[20]="",s3[30],*p;

int result;

下面以C语言中串运算介绍串的基本运算

1、求串长

int strlen(char *s); //求串s的长度

【例】printf("%d",strlen(s1)); //输出s1的串长12

2、串复制

char *strcpy(char *to,*from);//将from串复制到to串中,并返回to开始处指针

【例】strcpy(s3,s1); //s3="dir/bin/appl",s1串不变

3、联接

char *strcat(char *to,char *from);//将from串复制到to串的末尾,

//并返回to串开始处的指针

【例】strcat(s3,"/"); //s3="dir/bin/appl/"

strcat(s3,s2); //s3="dir/bin/appl/"

4、串比较

int strcmp(char *s1,char *s2);//比较s1和s2的大小,

//当s1s2和s1=s2时,分别返回小于0、大于0和等于0的值

【例】result=strcmp("baker","Baker"); //result>0

result=strcmp("12","12"); //result=0

result=strcmp("Joe","joseph") //result<0

5、字符定位

char *strchr(char *s,char c);//找c在字符串s中第一次出现的位置,

//若找到,则返回该位置,否则返回NULL

【例】p=strchr(s2,'.'); //p指向"file"之后的位置

if(p) strcpy(p,".cpp"); //s2=""

注意:

①上述操作是最基本的,其中后 4个操作还有变种形式:strncpy,strncath和strnchr。

②其它的串操作见C的。在不同的高级语言中,对串运算的种类及符号都不尽相同

③其余的串操作一般可由这些基本操作组合而成

【例】求子串的操作可如下实现:

void substr(char *sub,char *s,int pos,int len){

//s和sub是字符数组,用sub返回串s的第pos个字符起长度为len的子串

//其中0<=pos<=strlen(s)-1,且数组sub至少可容纳len+1个字符。

if (pos<0||pos>strlen(s)-1||len<0)

Error("parameter error!");

strncpy(sub,&s[pos],len); //从s[pos]起复制至多len个字符到sub

直接修改 CString 的内容

在大多数情况下,应使用 CString 成员函数来修改 CString 对象的内容或将 CString 转换为一个 C 样式的字符串。

但是,在某些情况下,比如使用需要字符缓冲区的操作系统函数,直接修改 CString 内容是较为有利的。

GetBuffer 和 ReleaseBuffer 成员函数使您能够访问 CString 对象的内部字符缓冲区,并直接进行修改。以下步骤显示如何使用这些函数来达到这一目的:

1. 为 CString 对象调用 GetBuffer,并指定所需缓冲区的长度。

2. 使用由 GetBuffer 返回的指针来直接将字符写入 CString 对象中。

3. 调用 CString 对象的 ReleaseBuffer 来更新所有的内部 CString 状态信息,如字符串的长度。直接修改完 CString 对象的内容之后,在调用任何其他 CString 成员函数之前必须调用 ReleaseBuffer。

对 CString 对象使用变量参数函数

C类型字符变量与CString类及其相互转换- -

C类型字符变量与CString类及其相互转换

下述变量属于c内嵌数据类型。

char 8位字符变量

wchar_t 16位字符变量

下述变量属于Windows Data Type.详见MSDN.

CHAR 8-bit Windows (ANSI) character.

WCHAR 16-bit Unicode character.

TCHAR A WCHAR if Unicode is defined, a CHAR otherwise.

TBYTE A WCHAR if Unicode is defined, a CHAR otherwise.

LPSTR Pointer to a null-terminated string of 8-bit Windows (ANSI) characters.

LPCSTR Pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters.

LPTSTR An LPWSTR if UNICODE is defined, an LPSTR otherwise.

LPCTSTR An LPCWSTR if UNICODE is defined, an LPCSTR otherwise.

LPWSTR Pointer to a null-terminated string of 16-bit Unicode characters.

LPCWSTR Pointer to a constant null-terminated string of 16-bit Unicode characters.

上述变量的首字母L可去掉,指的是该地址的低字节的意思。W意即宽字符(UNICODE),C意即const,T意即可变的,如果定义了UNICODE,为

UNICODE字符,否则为ANSI字符。

ANSI字符与UNICODE字符的区别:说白了发明UNICODE字符就是为了表示汉字之类的东方文字。一个是8位字符,一个是16位字符。

String类:MFC类

1,怎样把String转换成 C 样式空终止字符串

请考虑以下两种情况:

1,在最简单的情况下,可以将 CString 对象转换成 LPCTSTR。LPCTSTR 类型转换运算符从 CString 对象返回指向只读的

C 样式空终止字符串的指针。

由 LPCTSTR 返回的指针指入由 CString 使用的数据区域。如果 CString 离开了这个范围并且被自动删除,

或其他原因更改了 CString 的内容,那么 LPCTSTR 指针将不再有效。请将该指针指向的字符串视为临时的。

可使用 CString 函数(如 SetAt)来修改字符串对象中的单个字符。但是,如果需要可直接修改的 CString 对象字符的副本,

那么请使用 strcpy(或可移植 Unicode/MBCS 的 _tcscpy)来将 CString

对象复制到单独的缓冲区,在那里可安全地修改字符串,

如以下示例中所示:

CString theString( "This is a test" );

LPTSTR lpsz = new TCHAR[gth()+1];

_tcscpy(lpsz, theString);

//... modify lpsz as much as you want

注意 strcpy(或可移值 Unicode/MBCS 的 _tcscpy)的第二个参数是 const wchar_t* (Unicode) 或 const char* (ANSI)。

以上示例为该参数传递一个 CString。C++ 编译器自动将为应用转换函数,该转换函数是为将 CString 转换为 LPCTSTR 的

CString 类定义的。定义从一种类型到另一种类型的转换操作的能力是 C++

最为有用的功能之一。

2,可显式的将CString转换LPCTSTR.

某些函数参数接受LPCTSTR类型,此时可以显式的将CString转换LPCTSTR。

CString kindOfFruit = "bananas";

int howmany = 25;

printf( "You have %d %sn", howmany, (LPCTSTR)kindOfFruit );


本文标签: 字符串 函数 使用 内存 对象