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

北慕城南 提交于 2019-11-27 03:01:36

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++对这些类型的宏包装,其中不同类型的相


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!