您好,欢迎来到花图问答。
搜索
您的当前位置:首页C++中字符串的介绍

C++中字符串的介绍

来源:花图问答


C++中字符串的介绍

字符串是个特殊的字符数组。与普通字符数组不同的是,字符串在结尾处有一个字符“\\0”,表示字符串的结束。在C++中字符串有特殊的初始化方式和专门的处理函数。本节将介绍字符串的特性,在下一节中将介绍专门用于处理字符串的函数。

1.1字符串的特性

1.1.1 什么是字符串

在C++语言中,没有专门的字符串类型,一个字符串,其实就是一个字符数组。不过并不是数组中的所有字符都是字符串的一部分,字符串是以字符“\\0”表示字符串的结束的。所以在字符数组中,所有在字符\\0之前的字符才是字符串中的有效字符。

字符串也有字面常量,其形式是用双引号包围起来一串字符。例如: \"Hello World\";

前面讲到的字符,用的是单引号,字符串用的是双引号,这点不要弄反了。\"a\"是一个字符串,而不是一个字符,虽然这个字符串只有一个有效字符。

上面定义了一个字符串,其存储形式如图1.1所示。

图1.1 字符串的存储形式 每一个字符串,后面都有一个不可见的字符“\\0”,这个字符是字符串的结束标志。因此上面的字符串有12个字符。双引号表示其中的内容是一个字符串,字符串中并不包括双引号。

前面讲字符类型的时候讲过转义字符,比如字符“\\n”表示换行。字符串中可以包含转义字符,例如:

\"Hello\\nWorld\";

如果输出上面的字符串,则会分两行输出。\" \"表示只有空格字符的字符串,而\"\"也是一个字符串,这个字符串只有一个结束标志。字符串还可以分多行定义,例如:

\"Hello\" \"World\";

上面的定义相当于\"HelloWorld\",编译器会自动把分行定义的字符串连接起来。需要注意的是,只有在结束的时候才可以有语句结束的分号\";\",前面都不能有。

字符串的结束标志不需要显式地提供,编译器会自动在后面追加。

1.1.2 定义字符串

用双引号包围的字符串是字符串类型的字面常量,不可以修改。而作为变量的字符串,

其实就是字符数组。定义一个字符串其实就是定义一个字符数组,例如:

char name[10]; // 定义一个名字是name的字符串 也可以定义二维的或者多维的字符数组,例如:

char names[10][10]; // 定义一个二维字符数组, 通常称这样的数组为字符串数组

1.1.3 字符串的初始化

同普通数组一样,字符数组也允许在定义的时候直接初始化,例如:

char name[10] = {'J', 'a', 's', 'o', 'n'};

同样,如果为数组的所有元素提供了初始值,则字符数组的长度可以省略,例如:

char name[] = {'J', 'a', 's', 'o', 'n'}; 这时数组长度被自动定义为5。

还可以用字符串来作为字符数组的初始值,因此还可以这么写:

char name[] = \"Jason\";

上面的语句定义了一个长度为6的字符数组,其最后的一个字符为“\\0”。在这种初始化方式下,不需要花括号\"{\"和\。

通常用上面的方法对字符数组进行初始化,而不用单个字符的方式。

1.1.4 操作字符串

字符串作为一个字符数组,同样可以使用下标的方法来操作每一个字符,不过字符串有一些普通数组没有的特性。

前面在介绍数组的时候提到过,cin和cout不可以直接操作数组,但是字符数组是个特例。可以直接用C++的标准输入cin输入整个数组的元素,用标准输出cout输出整个字符数组。下面对一个输入的字符串进行反转,其算法是:第一个字符和最后一个字符交换,第二个字符和倒数第二个字符交换,依此类推。假定字符串为abcdefg,那么其交换过程示意如下:

a < ------> g b < ------> f c < ------> e d 保持不变

交换之后就成了gfedcba。

交换到字符d时,也就是字符串一半的时候,这时的结果已经是gfedcba,交换已经完成了,如果继续再交换下去,则又会恢复成交换之前的样子。

该实例的具体代码如示例代码6.4所示。 示例代码6.4 #include

using namespace std; // 使用名称空间std int main(int argc, char *argv[]) // 主函数 {

char buffer[128]; // 字符数组 cin>>buffer; // 输入字符串 int len = (int)strlen( buffer ); // 取得字符串的长度 for( int i = 0; i < len / 2; i ++ ) // 遍历字符串 {

char temp = buffer[i]; // 交换两个字符 buffer[i] = buffer[len - i - 1]; buffer[len -i - 1] = temp; }

cout <<\"反转之后的字符串为:\" <建立一个控制台工程,并将上述代码复制到源文件中,编译并运行,其结果如图6.10所示。

图1.2 字符串反转结果 对于buffer[0],其对应的要交换的为buffer[len-1],对于第i个字符buffer[i],其需要交换的为buffer[len -i -1]。最后来看循环结束的条件:如果字符串的长度len为偶数,最后一对需要交换的是buffer[len/2-1]和buffer[len/2];如果字符串的长度len为奇数,buffer[len/2]是中间字符,不需要交换,最后一对需要交换的字符是buffer[len/2-1]和buffer[len/2+1]。因此用条件i1.1.5 字符串的数组

也可以定义二维的字符数组,也就是字符串的数组。例如下面定义可以存储多个人名的数组:

char names[10][40];

同普通的二维数组一样,字符串数组在定义的时候也可以初始化: char names[10][40] = { \"Tom\ \"Mary\ \"Jacky\ \"Jason\"

};

上面定义了一个长度为10的字符串数组,并给前4个进行了初始化,剩余部分用空字符串来填充。

不能遗忘两个字符串中间的\。

1.2字符串处理函数

虽然可以对字符数组用字符串进行初始化,可以直接输入、输出字符串,但是在使用字符数组的时候还是有很多不便,比如不能直接对字符数组进行赋值、不能比较两个字符数组的大小等。因此C++提供了一些函数来处理字符串,下面介绍几个常用的函数。

1.2.1 字符串复制函数strcpy

字符串是一个字符数组,因此它就有数组的局限性,不能用一个字符串给另外一个字符串赋值,例如:

char name[10];

name = \"Jason\"; // 错误,不可以这样直接赋值

为了方便实现上面的功能,C++标准库中提供了strcpy函数,其定义格式为:

strcpy( 字符数组名1, 字符数组名2 )

函数把字符数组2中的字符串复制到字符数组1中,串结束标志\\0也一同复制。使用例子如下:

char str1[128],str2[] = \"Hello World\"; strcpy( str1, str2 ); // 把str2复制到str1

程序员需要自己保证str1的长度足够容纳str2的内容,如果str2的长度超过了str1的长度,可能会导致系统崩溃。

其中第二个参数可以直接是一个字符串,因此也可以这样使用: char str[128];

strcpy( str, \"Hello World\" ); // 直接给str赋值

在下面的例子中需要用户输入两个字符串,然后把这两个字符串的内容互换,程序如示例代码2.1所示。

#include

using namespace std; // 使用名称空间std int main(int argc, char *argv[]) // 主函数 {

cout<<\"请依次输入两个字符串:\"<>str1; // 输入 cin>>str2;

cout<<\"第一个字符串为:\"<cout<cout<<\"交换之后的字符串为:\"<建立一个控制台工程,并将上述代码复制到源文件中,编译并运行,其结果如图2.1所示。

图2. 1 交换字符串结果 strcpy函数复制的是字符\\0之前的内容(包括这个结束标志),不是整个字符数组的内容。

1.2.2 计算字符串长度函数strlen

对于字符数组,可以通过sizeof来得到其定义的长度,但是这个长度对于字符串是没有意义的。因为通常想要得到的是其有效内容的长度,也就是在字符\\0之前的字符的个数。在C++标准库中提供了函数strlen,可以实现这个功能。strlen函数的格式如下:

strlen( 字符数组名 )

strlen将字符串的实际长度作为函数的返回值。使用例子如下: char str[128] = \"Hello World\";

int len = strlen( str ); // 取得字符串的长度

上面的len值为11,包括里面的空格,但是不包括里面的字符串结束标志。下例中需要用户输入一个字符串,然后用strlen函数计算其长度,程序如示例代码2.2所示。

#include using namespace std;

int main() {

cout<<\"请输入一个字符串:\"<>str;

cout<<\"字符串的长度为:\"<建立一个控制台工程,并将上述代码复制到源文件中,编译并运行,其结果如图2.2所示。

图2. 2 使用strlen函数示例结果 1.2.3 字符串连接函数strcat

对于两个整数a和b,下面的代码结果是把两个整数相加:

int a = 3; int b = 5; int c = a + b;

对于字符串,其加法的意义应该是把两个字符串连接起来,对于下面两个定义:

char str1[128] = \"Hello World\"; char str2[128] = \"C++ Programming\";

如果想把两个字符串连接起来,直接用+是不可以的,在C++标准库中提供了一个可以实现这个功能的函数,这个函数就是strcat。函数格式如下:

strcat ( 字符数组名1, 字符数组名2 )

函数把字符数组2中的字符串连接到字符数组1 中字符串的后面,并删去字符串1后的串标志\\0。本函数返回值是字符数组1的首地址。使用例子如下:

char str1[128] = \"Hello World\"; char str2[128] = \"C++ Programming\"; strcat( str1, str2 ); // 连接字符串

上面的代码把str2连接到str1的后面,现在str1为\"Hello WorldC++ Programming\"。下例需要用户输入两个字符串,然后把它们连接起来,程序如示例代码2.3所示。

#include

using namespace std; // 使用名称空间std int main(int argc, char *argv[]) // 主函数

{

cout<<\"请输入两个字符串:\"<cin>>str1>>str2; // 输入字符串 strcpy( buffer, str1 ); // 复制 strcat( buffer, str2 ); // 连接

cout<<\"新生成的字符串为:\"<建立一个控制台工程,并将上述代码复制到源文件中,编译并运行,其结果如图2.3所示。

图2. 3 strcat函数使用示例结果 1.2.4 字符串比较函数strcmp

对于两个字符串,其比较是有意义的,但是字符数组不能直接进行比较,因此在C++标准库中提供了对字符串进行比较的函数,函数格式如下:

strcmp( 字符数组名1,字符数组名2 )

函数按照ASCII码顺序比较两个数组中的字符串,并由函数返回值返回比较结果: 字符串1=字符串2,返回值=0。 字符串2>字符串2,返回值>0。 字符串1<字符串2,返回值<0。

当两个字符串相等的时候,返回值为0,因此,在比较两个字符串是否相等的时候,应当像下面的代码这么写:

if( strcmp( str1, str2 ) == 0 ) // 判断 两个字符串是否相同

而不能这么写:

if( strcmp( str1, str2 ) ) // 错误的写 法,结果跟希望正好相反

下例需要用户输入两个字符串,然后对它们进行比较,程序如示例代码2.4所示。

#include

using namespace std; // 使用名称空间std int main(int argc, char *argv[]) // 主函数 {

cout<<\"请输入两个字符串:\"<cin>>str1>>str2; // 输入字符串 int res = strcmp( str1, str2 ); // 比较

cout<<\"比较的结果:\"<if( res == 0 ) cout<<\"==\"; if( res > 0 ) cout<<\">\"; if( res < 0 ) cout<<\"<\"; cout<system(\"PAUSE\"); // 等待用户反应

return EXIT_SUCCESS; // 主函数返回 }

建立一个控制台工程,并将上述代码复制到源文件中,编译并运行,其结果如图2. 4所示。

图2. 4 使用strcmp函数示例结果 在C++的标准库中提供了一个string类。使用这个类,可以直接进行赋值、比较、计算长度和连接等操作。

1.3 汉字的编码方式及在C++中的处理

1.3.1 汉字编码方式的介绍

对英文字符的处理,7位ASCII码字符集中的字符即可满足使用需求,且英文字符在计算机上的输入及输出也非常简单,因此,英文字符的输入、存储、内部处理和输出都可以只用同一个编码(如ASCII码)。

而汉字是一种象形文字,字数极多(现代汉字中仅常用字就有六、七千个,总字数高达5万个以上),且字形复杂,每一个汉字都有“音、形、义”三要素,同音字、异体字也很多,这些都给汉字的的计算机处理带来了很大的困难。要在计算机中处理汉字,必须解决以下几个问题:首先是汉字的输入,即如何把结构复杂的方块汉字输入到计算机中去,这是汉字处理的关键;其次,汉字在计算机内如何表示和存储?如何与西文兼容?最后,如何将汉字的处理结果从计算机内输出?

为此,必须将汉字代码化,即对汉字进行编码。对应于上述汉字处理过程中的输入、内部处理及输出这三个主要环节,每一个汉字的编码都包括输入码、交换码、内部码和字形码。在计算机的汉字信息处理系统中,处理汉字时要进行如下的代码转换:输入码→交换码→内部码→字形码。

(1)输入码: 作用是利用它和现有的标准西文键盘结合来输入汉字。输入码也称为外码。主要归为四类:

a) 数字编码:数字编码是用等长的数字串为汉字逐一编号,以这个编号作为汉字的输入码。例如,区位码、电报码等都属于数字编码。

b) 拼音码:拼音码是以汉字的读音为基础的输入办法。

c) 字形码:字形码是以汉字的字形结构为基础的输入编码。例如,五笔字型码(王码)。 d) 音形码:音形码是兼顾汉字的读音和字形的输入编码。

(2)交换码:用于汉字外码和内部码的交换。交换码的国家标准代号为GB2312-80。 (3)内部码:内部码是汉字在计算机内的基本表示形式,是计算机对汉字进行识别、存储、处理和传输所用的编码。内部码也是双字节编码,将国标码两个字节的最高位都置为“1”,即转换成汉字的内部码。

(4)字形码:字形码是表示汉字字形信息(汉字的结构、形状、笔划等)的编码,用来实现计算机对汉字的输出(显示、打印)。

1.3.2 VC/C++中汉字的编码方式

VC/C++正是采用了GB2312内部码作为汉字的编码方式,因此VC/C++中的各种输入输出方法,如cin/wcin,cout/wcout,scanf/wsanf,printf/wprintf……都是基于GB2312的,如果汉字的内码不是这种编码方式,那么利用上述各种方法就不会正确的解析汉字。

仔细观察ASCII字符表,从第161个字符开始,后面的字符并不经常为用户所使用,负值也未使用。GB2312编码方式充分利用这一特性,将161-255(-95~-1)之间的数值空间作为汉字的标识码。既然255-161 = 94不能满足汉字容量的要求,就将每两个字符并在一块(即一个汉字占两个字节),显然,94* 94 =8836基本上已经满足了常用汉字个数的要求。计算机处理字符时,当连续处理到两个大与160(或-95~-1)的字节时,就认为这两个字节存放了一个汉字字符。可以用下面的Demo程序来模拟VC/C++中输出汉字字符的过程: unsigned char input[50]; cin>>input; int flag=0;

for(int i =0 ;i < 50 ;i++) {

if(input[i] > 0xa0 && input[i] != 0) {

if(flag == 1) {

cout<<\"chinese character\"< flag = 0; } else {

flag++;

} }

else if(input[i] == 0) { break; } else {

cout<<\"english character\"< } }

输入:Hello中国 (“中国”对应的GB2312内码为:214 208,185 250) 输出:english character english character english character english character english character chinese character chinese character

VC/C++中的英文字符仍然采用ASCII编码方式。可以设想,其他国家程序员利用VC/C++编写程序输入本国字符时,VC/C+++则会采用该国的字符编码方式来处理这些字符。 问题又产生了,韩国的VC/C++程序在中国的VC/C++上运行时,如果没有相应的内码库,则对韩语字符的显示有可能出现乱码。我个人猜测,VC安装程序中应该带有不同国家的内码库,这样一来肯定会占用很大的空间。如果所有的国家使用统一的编码方式,且所有的程序设计语言和开发工具都支持这种编码方式该多好!而现实中,确实已经有这种编码方式了,且许多新的语言也都支持这种编码方式,如Java、C#等,它就是下面的Unicode编码

1.3.3 新的内码标准——Unicode

Unicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。1990年开始研发,1994年正式公布。随着计算机工作能力的增强,Unicode也在面世以来的十多年里得到普及。最新版本的 Unicode 是 2005年3月31日推出的Unicode 4.1.0 。

Unicode 编码系统可分为编码方式和实现方式两个层次。

编码方式:Unicode 的编码方式与 ISO 10646 的通用字符集(Universal Character Set,UCS)概念相对应,目前的用于实用的 Unicode 版本对应于 UCS-2,使用16位的编码空间。也就是每个字符占用2个字节。这样理论上一共最多可以表示 216 个字符。基本满足各种语言的使用。实际上目前版本的 Unicode 尚未填充满这16位编码,保留了大量空间作为特殊使用或将来扩展。

实现方式:Unicode 的实现方式不同于编码方式。一个字符的 Unicode 编码是确定的。但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对 Unicode 编码的实现方式有所不同。Unicode 的实现方式称为Unicode转换格式(Unicode Translation Format,简称为 UTF)。如,UTF-8 编码,这是一种变长编码,它将基本7位ASCII字符仍用7位编码表示,占用一个字节(首位补0)。而遇到与其他 Unicode 字符混合的情况,将按一定算法转换,每个字符使用1-3个字节编码,并利用首位为0或1进行识别。

Java与C#语言都是采用Unicode编码方式,在这两种语言中定义一个字符,在内存中存放的就是这个字符的两字节Unicode码。如下所示: char a='我'; => 内存中存放的Unicode码为:25105

1.3.4内码的相互转换

(1)VC中的实现方法

利用Windows系统提供的API:::MultiByteToWideChar和::WideCharToMultiByte ::MultiByteToWideChar:实现当前码到Unicode码的转换; ::WideCharToMultiByte:实现Unicode码到当前码的转换; (2)Java中的实现方法

String vcString=new String(JavaString.getBytes(\"UTF-8\"),\"gb2312\"); Java的编码应该是UTF-8 VC中的MutiByte Charater Set

这种方式以按字节为单位存放字符,即如果一个字符码为两字节,则在内存中占两字节,字符码为一字节,就占一字节。例如,字符串“中国abc”的编码为:中(0xd6、0xd0)、国(0xb9、0xfa)、a(0x61)、b(0x62)、c(0x63)、(0x00),就存为如下方式

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- huatuowenda.com 版权所有 湘ICP备2023022495号-1

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务