VC++ 字符串操作学习总结

vc++中各种字符串(转载)

http://www.cnblogs.com/tomin/archive/2008/12/28/1364097.html

CString ,BSTR ,LPCTSTR之间关系和区别

CString是一个动态TCHAR数组,BSTR是一种专有格式的字符串(需要用系统提供的函数来操纵,LPCTSTR只是一个常

量的TCHAR指针。

CString 是一个完全独立的类,动态的TCHAR数组,封装了 + 等操作符和字符串操作方法。

typedef OLECHAR FAR* BSTR;

typedef const char * LPCTSTR;

vc++中各种字符串的表示法

首先char* 是指向ANSI字符数组的指针,其中每个字符占据8位(有效数据是除掉最高位的其他7位),这里保持了与传

统的C,C++的兼容。

LP的含义是长指针(long pointer)。LPSTR是一个指向以‘\0’结尾的ANSI字符数组的指针,与char*可以互换使用,在

win32中较多地使用LPSTR。

而LPCSTR中增加的‘C’的含义是“CONSTANT”(常量),表明这种数据类型的实例不能被使用它的API函数改变,

除此之外,它与LPSTR是等同的。

1.LP表示长指针,在win16下有长指针(LP)和短指针(P)的区别,而在win32下是没有区别的,都是32位.所以这里的LP和P是等

价的.

2.C表示const

3.T是什么东西呢,我们知道TCHAR在采用Unicode方式编译时是wchar_t,在普通时编译成char.

为了满足程序代码国际化的需要,业界推出了Unicode标准,它提供了一种简单和一致的表达字符串的方法,所有字符

中的字节都是16位的值,其数量也可以满足差不多世界上所有书面语言字符的编码需求,开发程序时使用Unicode(类

型为wchar_t)是一种被鼓励的做法。

LPWSTR与LPCWSTR由此产生,它们的含义类似于LPSTR与LPCSTR,只是字符数据是16位的wchar_t而不是char。

然后为了实现两种编码的通用,提出了TCHAR的定义:

如果定义_UNICODE,声明如下:

typedef wchar_t TCHAR;

如果没有定义_UNICODE,则声明如下:

typedef char TCHAR;

LPTSTR和LPCTSTR中的含义就是每个字符是这样的TCHAR。

CString类中的字符就是被声明为TCHAR类型的,它提供了一个封装好的类供用户方便地使用。

LPCTSTR:

        #ifdef _UNICODE

           typedef const wchar_t * LPCTSTR;

        #else

           typedef const char * LPCTSTR;

        #endif

VC常用数据类型使用转换详解

先定义一些常见类型变量借以说明

int i = 100;

long l = 2001;

float f=300.2;

double d=12345.119;

char username[]=”女侠程佩君”;

char temp[200];

char *buf;

CString str;

_variant_t v1;

_bstr_t v2;

一、其它数据类型转换为字符串

短整型(int)

          itoa(i,temp,10);        //将i转换为字符串放入temp中,最后一个数字表示十进制

          itoa(i,temp,2);         //按二进制方式转换 

长整型(long)

          ltoa(l,temp,10);

二、从其它包含字符串的变量中获取指向该字符串的指针

CString变量

str = “2008北京奥运”;

buf = (LPSTR)(LPCTSTR)str; 

BSTR类型的_variant_t变量

v1 = (_bstr_t)”程序员”;

buf = _com_util::ConvertBSTRToString((_bstr_t)v1);

三、字符串转换为其它数据类型

strcpy(temp,”123″); 

短整型(int)

         i = atoi(temp); 

长整型(long)

         l = atol(temp); 

浮点(double)

         d = atof(temp);

四、其它数据类型转换到CString

使用CString的成员函数Format来转换,例如:

整数(int)

         str.Format(“%d”,i); 

浮点数(float)

         str.Format(“%f”,i); 

字符串指针(char *)等已经被CString构造函数支持的数据类型可以直接赋值

         str = username;

五、BSTR、_bstr_t与CComBSTR

CComBSTR、_bstr_t是对BSTR的封装,BSTR是指向字符串的32位指针。

char *转换到BSTR可以这样: BSTR b=_com_util::ConvertStringToBSTR(“数据”);        //使用前需要加上头文件

comutil.h

反之可以使用char *p=_com_util::ConvertBSTRToString(b);

六、VARIANT 、_variant_t 与 COleVariant

VARIANT的结构可以参考头文件VC98\Include\OAIDL.H中关于结构体tagVARIANT的定义。

对于VARIANT变量的赋值:首先给vt成员赋值,指明数据类型,再对联合结构中相同数据类型的变量赋值,举个例子:

VARIANT va;

int a=2001;

va.vt=VT_I4;       //指明整型数据

va.lVal=a;         //赋值

对于不马上赋值的VARIANT,最好先用Void VariantInit(VARIANTARG FAR* pvarg);进行初始化,其本质是将vt设置为

VT_EMPTY,下表我们列举vt与常用数据的对应关系:

unsigned char bVal; VT_UI1 

short iVal; VT_I2 

long lVal;     VT_I4  

float fltVal;     VT_R4 

double dblVal;     VT_R8  

VARIANT_BOOL boolVal;     VT_BOOL 

SCODE scode;     VT_ERROR 

CY cyVal;     VT_CY 

DATE date;     VT_DATE 

BSTR bstrVal;     VT_BSTR 

IUnknown FAR* punkVal;     VT_UNKNOWN 

IDispatch FAR* pdispVal;     VT_DISPATCH 

SAFEARRAY FAR* parray;     VT_ARRAY|* 

unsigned char FAR* pbVal;     VT_BYREF|VT_UI1 

short FAR* piVal;     VT_BYREF|VT_I2 

long FAR* plVal;     VT_BYREF|VT_I4 

float FAR* pfltVal;     VT_BYREF|VT_R4 

double FAR* pdblVal; VT_BYREF|VT_R8 

VARIANT_BOOL FAR* pboolVal; VT_BYREF|VT_BOOL 

SCODE FAR* pscode;     VT_BYREF|VT_ERROR 

CY FAR* pcyVal;     VT_BYREF|VT_CY 

DATE FAR* pdate; VT_BYREF|VT_DATE 

BSTR FAR* pbstrVal;     VT_BYREF|VT_BSTR 

IUnknown FAR* FAR* ppunkVal;     VT_BYREF|VT_UNKNOWN 

IDispatch FAR* FAR* ppdispVal; VT_BYREF|VT_DISPATCH 

SAFEARRAY FAR* FAR* pparray;     VT_ARRAY|* 

VARIANT FAR* pvarVal;     VT_BYREF|VT_VARIANT 

void FAR* byref;     VT_BYREF 

_variant_t是VARIANT的封装类,其赋值可以使用强制类型转换,其构造函数会自动处理这些数据类型。

例如:

long l=222;

ing i=100;

_variant_t lVal(l);

lVal = (long)i;

COleVariant的使用与_variant_t的方法基本一样,请参考如下例子:

COleVariant v3 = “字符串”, v4 = (long)1999;

CString str =(BSTR)v3.pbstrVal;

long i = v4.lVal;

七、其它

对消息的处理中我们经常需要将WPARAM或LPARAM等32位数据(DWORD)分解成两个16位数据(WORD),例如:

LPARAM lParam;

WORD loValue = LOWORD(lParam);        //取低16位

WORD hiValue = HIWORD(lParam);        //取高16位 

对于16位的数据(WORD)我们可以用同样的方法分解成高低两个8位数据(BYTE),例如:

WORD wValue;

BYTE loValue = LOBYTE(wValue);        //取低8位

BYTE hiValue = HIBYTE(wValue);        //取高8位 

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

1、GetBuffer函数:

使用CString::GetBuffer函数。

char *p; 

CString str=”hello”; 

p=str.GetBuffer(str.GetLength()); 

str.ReleaseBuffer();

将CString转换成char * 时

CString str(“aaaaaaa”);

strcpy(str.GetBuffer(10),”aa”);

str.ReleaseBuffer();

当我们需要字符数组时调用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[Msg.GetLength()+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]=”file.asm”,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/file.asm”

4、串比较

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

        //当s1<s2、s1>s2和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=”file.cpp” 

     注意:

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

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

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

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

       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

========

vc++中各种字符串的表示法

http://blog.csdn.net/kybd2006/article/details/1566827

        首先char* 是指向ANSI字符数组的指针,其中每个字符占据8位(有效数据是除掉最高位的其他7位);

        LP的含义是长指针(long pointer)。LPSTR是一个指向以‘/0’结尾的ANSI字符数组的指针,与char*可以互换使

用,在win32中较多地使用LPSTR(并且长指针(LP)和短指针(P)是等价的)。而LPCSTR中增加的‘C’的含义

是“CONSTANT”(常量),表明这种数据类型的实例不能被使用它的API函数改变,除此之外,它与LPSTR是等同的

        我们知道TCHAR在采用Unicode方式编译时是wchar_t,在普通时编译成char,业界推出的Unicode标准,它提供

了一种简单和一致的表达字符串的方法,所有字符中的字节都是16位的值,其数量也可以满足差不多世界上所有书面语

言字符的编码需求,开发程序时使用Unicode(类型为wchar_t)是一种被鼓励的做法。LPWSTR与LPCWSTR由此产生,

它们的含义类似于LPSTR与LPCSTR,只是字符数据是16位的wchar_t而不是char。

        然后为了实现两种编码的通用,提出了TCHAR的定义:

       如果定义_UNICODE,声明如下:

               typedef wchar_t TCHAR;

       如果没有定义_UNICODE,则声明如下:

               typedef char TCHAR;

       LPTSTR和LPCTSTR中的含义就是每个字符是这样的TCHAR。

      CString类中的字符就是被声明为TCHAR类型的,它提供了一个封装好的类供用户方便地使用。

     LPCTSTR:

     #ifdef _UNICODE

        typedef const wchar_t * LPCTSTR;

     #else

        typedef const char * LPCTSTR;

     #endif

========

vc++下的字符串处理

http://blog.chinaunix.net/uid-192452-id-3182259.html

07年在启明做个专题的讲座,现在提炼升华一下。

vc工程中考虑到UNICODE的设置问题,尽可能使用三种字符串,ATL的CString,不是mfc的CString,使用com 就使用

CComBSTR,使用api的话,尽可能用TCHAR,字符串操作尽可能用_tcs函数。

除非考虑跨平台,否则不要使用stl的string,应该使用CString,虽然可以使用如下设置

#include 

using namespace std;

#ifndef UNICODE

typedef string TSTRING;

#else

typedef wstring TSTRING;

#endif

使用stl的string 以后的字符串操作会很复杂,

例如得到程序当前的路径

TCHAR buffer[MAX_PATH+1];

DWORD iNombreChars = GetCurrentDirectory(MAX_PATH, buffer);

string strPath;

strPath.assign(&buffer[0], &buffer[iNombreChars]);

这是闲的蛋疼

也有简单的,

std::string str(MAX_PATH+1, 0);

GetCurrentDirectory(MAX_PATH, &str[0]);

将string转为TCHAR

TCHAR *param=new TCHAR[tsDir.size()+1];

param[tsDir.size()]=_T(‘\0’);

//As much as we’d love to, we can’t use memcpy() because

//sizeof(TCHAR)==sizeof(char) may not be true:

std::copy(tsDir.begin(),tsDir.end(),param);

如果经常转换,最后会抓狂的。

========

返璞归真vc++之字符类型

http://www.cnblogs.com/lichaoxyz/p/3636906.html

  在今天,大量使用java与.net的程序员已经很少去真实了解字符的底层表达,但是使用VC++编程,对字符的处理却

非常慎重,刚学习vc++肯定会为其中的字符类型给晕头转向,今天本人学习第一节,从字符开始

  特别说明:本文章所有开发环境选用vs2012开发

  在计算机系统中所有的数据与程序指令都是二进制的形式存在的,CPU处理器给特定序列的二进制序列包含有特殊

的意义,及我们常说的计算机指令,计算机指令目前流行的X86指令集,以及目前流行android平台下arm指令集,同时

所有的数据也是以二进制的形式表达在计算机中,主要表达在计算机体系中的内存,寄存器,以及CPU缓存。所以计算

机认识到的字符也就是一串二进制格式的数据,计算机的首要任务就是给这些二进制进行字符的映射,但是在不同的指

令集与CPU下,对这些二进制进行翻译的过程中又产生了高位与低位只说,这个只是CPU级别的二进制读取顺序,如何

给这些特定的二进制翻译成我们熟悉的人类语言,于是就产生了我们经常所说的字符串编码,常用的有ASCII编码,以及

Unicode,

  asccii编码,及单个字节编码,1个字节8个位,也就是说,在计算机内存中,8个连续的位能代码一个字符,那么如

何映射成字符呢,那么就是通过我们的assicc表来实现,如下

八进制
十六进制
十进制
字符
八进制
十六进制
十进制
字符

00
00
0
nul
100
40
64
@

01
01
1
soh
101
41
65
A

02
02
2
stx
102
42
66
B

03
03
3
etx
103
43
67
C

04
04
4
eot
104
44
68
D

05
05
5
enq
105
45
69
E

06
06
6
ack
106
46
70
F

07
07
7
bel
107
47
71
G

10
08
8
bs
110
48
72
H

11
09
9
ht
111
49
73
I

12
0a
10
nl
112
4a
74
J

13
0b
11
vt
113
4b
75
K

14
0c
12
ff
114
4c
76
L

15
0d
13
cr
115
4d
77
M

16
0e
14
so
116
4e
78
N

17
0f
15
si
117
4f
79
O

20
10
16
dle
120
50
80
P

21
11
17
dc1
121
51
81
Q

22
12
18
dc2
122
52
82
R

23
13
19
dc3
123
53
83
S

24
14
20
dc4
124
54
84
T

25
15
21
nak
125
55
85
U

26
16
22
syn
126
56
86
V

27
17
23
etb
127
57
87
W

30
18
24
can
130
58
88
X

31
19
25
em
131
59
89
Y

32
1a
26
sub
132
5a
90
Z

33
1b
27
esc
133
5b
91
[

34
1c
28
fs
134
5c
92
\

35
1d
29
gs
135
5d
93
]

36
1e
30
re
136
5e
94
^

37
1f
31
us
137
5f
95
_

40
20
32
sp
140
60
96

41
21
33
!
141
61
97
a

42
22
34

142
62
98
b

43
23
35
#
143
63
99
c

44
24
36
$
144
64
100
d

45
25
37
%
145
65
101
e

46
26
38
&
146
66
102
f

47
27
39
`
147
67
103
g

50
28
40
(
150
68
104
h

51
29
41
)
151
69
105
i

52
2a
42
*
152
6a
106
j

53
2b
43
+
153
6b
107
k

54
2c
44
,
154
6c
108
l

55
2d
45

155
6d
109
m

56
2e
46
.
156
6e
110
n

57
2f
47
/
157
6f
111
o

60
30
48
0
160
70
112
p

61
31
49
1
161
71
113
q

62
32
50
2
162
72
114
r

63
33
51
3
163
73
115
s

64
34
52
4
164
74
116
t

65
35
53
5
165
75
117
u

66
36
54
6
166
76
118
v

67
37
55
7
167
77
119
w

70
38
56
8
170
78
120
x

71
39
57
9
171
79
121
y

72
3a
58
:
172
7a
122
z

73
3b
59
;
173
7b
123
{

74
3c
60
<
174
7c
124
|

75
3d
61
=
175
7d
125
}

76
3e
62
>
176
7e
126
~

77
3f
63
?
177
7f
127
del

其中,每一个二进制序列对应这一个英文与数字字符,例如常说的十进制数65的二进制表达是1000001,对应的十六进制

为0x41;

我们都知道c语言中,字符是用char类型表示,同时默认的编码格式为asccii编码,也就是说当0x41这个十六进制数在转

换成整形值是65,在进行asccii字符转换时,如上表所示,即我们常说的大写字母A,

下面我们做一个实验,即可证明以上观点是否正确

#include “stdafx.h”

int _tmain(int argc, _TCHAR* argv[])

{

    //数值数据

    int i=0x41;

    //内存数据按整形值翻译打印出来

    printf(“this is int%d\n”,i);

    //内存数据按照asccii翻译打印出来

    printf(“this is char%c\n”,i);

    //打印出内存数据的十六进制格式

    printf(“this is binary 0x%x\n”,i);

    return 0;

}

复制代码

打印结果如下

由此可见,数据的表达都是二进制,只是人为的定义了一些一些含义,你认为是字符的时候,就转换成字符,你认为是

数字的时候就变成了数字,你认为是指令的时候,就编程了是指令,只是指令已经被CPU确定了含义。

那么同理得出Unicode也是类似的结构,只是有点不同

1、Unicode为双字节编码,也就是说一个字符需要两个字节的容量才能保存

所以需要特别注意的地方到了,那么以上这些函数printf能处理Unicode字符串吗?

答案显然是不能的,我们依然写一个程序去验证我们的结果

#include “stdafx.h”

#include <Windows.h>

int _tmain(int argc, _TCHAR* argv[])

{

    WCHAR unicodeChar=’很’;

    printf(“this is unicode Char%c\n”,unicodeChar);

    return 0;

}

 打印的结论:

可以看到,最终被一个问号代替了,也就是说,printf函数并没有把他解析出来,它依然按照asccii标准去解析,所以变

成了问号,那么疑问出来了

WCHAR到底是一个什么类型呢,怎么在c++标准中并不存在这样一个类型呢?

答案马上揭晓,我们找到了下面的宏定义

#ifndef _MAC //非苹果硬件平台

typedef wchar_t WCHAR;  //实际值是wchar_t  // wc,   16-bit UNICODE character

#else

// some Macintosh compilers don’t define wchar_t in a convenient location, or define it as a char

typedef unsigned short WCHAR; //苹果硬件平台实际上是unsigned short

// wc, 16-bit UNICODE character #endif

 也就是如上所述:

所以在我们常用的电脑下,都是wchar_t类型,那么这又是一个什么类型呢?

百度百科给出的定义如下,http://baike.baidu.com/link?

url=s9f5p8uJEuzVarbu0ilC2XTNRSEQHmxMM0pAHJE5w-Iysq2KFAmRXQUqSuYbbIF-AwmC0e_-

Rtsy9NUKP6QVYK

char是8位字符类型,最多只能包含256种字符,许多外文字符集所含的字符数目超过256个,char型无法表示。

wchar_t数据类型一般为16位或32位,但不同的C或C++库有不同的规定,如GNU Libc规定wchar_t为32位[1],总之,

wchar_t所能表示的字符数远超char型。

标准C++中的wprintf()函数以及iostream类库中的类和对象能提供wchar_t宽字符类型的相关操作。

所以是一个宽字符,也就是比char类型大,支持多种语言,比如东南亚国家的语言等,所以我认为在后续的编程中,应

该尽可能的使用宽字符类型,同时对于宽字符类型,c++标准也提供了wprintf一系列类来操作

今天就是以上学习的内容啦,大概就这么多了,通过理解原理,然后去看vc++对这些类型的宏包装,其中不同类型的相

互转换应该也是有所理解的。

========

    原文作者:bcbobo21cn
    原文地址: https://blog.csdn.net/bcbobo21cn/article/details/69258612
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞