string对象的操作

s.empty()  如果s为空串,则返回true,否则返回false
s.size()   返回s中字符的个数
s[n]       返回s中位置为n的字符,位置从0开始
s1+s2      把s1和s2连接成一个新字符串,返回新生成的字符串
s1=s2      把s1的内容替换为s2的副本
v1==v2     比较v1与v2的内容,相等则返回true,否则返回false
!=,<,<=,>,>=    保持这些操作符惯有的含义

1.string的size和empty操作

int main()
{
 string st("the expense of spirit/n");
 cout<<"the size of "<<st<<"is "<<st.size()
  <<" characters,including the newline"<<endl;
 return 0;
}

编译并运行,结果为:

the size of the expense of spirit

is 22 characters,including the newline

了解string对象是否为空是有用的.一种方法是将size和0比较:

if(st.size()==0)   // ok: empty

本例中,程序员并不需要知道string对象中有多少字符,只想知道size是否为0.用

string的成员函数empty()可以更直接回答这个问题:

if(st.empty())   //ok: empty

empty()成员函数将返回bool,如果string对象为空则返回true,否则返回false.

2.string::size_type类型

从逻辑上来说,size()成员函数似乎应该返回整型数值,或如前面章节所述的无符

号整数.但事实上,size操作返回的是string::size_type类型的值.我们需要对这

种类型做一些解释.

string类类型和许多其他库类型都定义了一些配套类型(companion type).通过

这些配套类型,库类型的使用就能与机器无关(machine-independent).size_type

就是这些配套类型中的一种.它定义为与unsigned型(unsigned int或unsigned

long)具有相同的含义,而且可以保证足够大能够存储任意string对象的长度.为

了使用由string类型定义的size_type类型,程序员必须加上作用域操作符来说明

所使用的size_type类型是由string类定义的.

实践告诉你:任何存储string的size操作结果的变量必须为string::size_type类

型.特别重要的是,不要把size的返回值赋给一个int变量.

虽然我们不知道string::size_type的确切类型,但可以知道它是unsigned型.对

于任意一种给定的数据类型,它的unsigned型所能表示的最大正数值比对应的

signed型要大一倍.这个事实表明size_type存储的string长度是int所能存储的

两倍.

使用int变量的另一个问题是,有些机器上int变量的表示范围太小,甚至无法存储

实际并不长的string对象.如在有16位int型的机器上,int类型变量最大只能表示

32767个字符的string对象.而能容纳一个文件内容的string对象轻易就会超过这

个数字.因此,为了避免溢出,保存一个string对象size的最安全的办法就是使用

标准库类型string::size_type.

3.string关系操作符

string类定义了几种关系操作符用来比较两个string值的大小.这些操作符实际

上是比较每个string对象的字符.

注解:string对象比较操作是区分大小写的,即同一个字符的大小写形式被认为是

两个不同的字符.在多数计算机上,大写的字母位于小写字母之前,任何一个大写

字母都小于任意的小写字母.

==操作符比较两个string对象,如果他们相等,则返回true.两个string对象相等

是指它们的长度相同,且含有相同的字符.标准库还定义了!=操作符来测试两个

string对象是否不等.

关系操作符<,<=,>,>=分别用于测试一个string对象是否小于、小于或等于、大

于、大于或等于另一个string对象.

string big="big",small="small";
string s1=big;   //s1 is a copy of big
if(big ==small)   ..false
       //...
if(big<=s1)       //true,they're equal,so big is less than or equal to

s1
       //...

关系操作符比较两个string对象时采用了和(大小写敏感的)字典排序相同的策略

:

A.如果两个string对象长度不同,且短的string对象与长的string对象的前面部

分相匹配,则短的string对象小于长的string对象.

B.如果两个string对象的字符不同,则比较第一个不匹配的字符.

举例来说,给定string对象

string substr="Hello";
string phrase="Hello World";
string slang="Hiya";

则substr小于phrase,而slang则大于substr或phrase

4.string对象的赋值

总体上说,标准库类型尽量设计得和基本数据类型一样方便易用.因此,大多数库

类型支持赋值操作.对string对象来说,可以把一个string对象赋值给另一个

string对象:

//st1 is an empty string,st2 is a copy of the literal
string st1,st2="The expense of spirit";
st1=st2;//replace st1 by a copy of st2

赋值操作后,st1就包含了st2串所有字符的一个副本.

大多数string库类型的赋值等操作的实现都会遇到一些效率上的问题,但值得注

意的是,从概念上讲,赋值操作确实需要做一些工作.它必须先把st1占用的相关内

存释放掉,然后再分配给st1足够存放st2副本的内存空间,最后把st2中的所有字

符赋值到新分配的内存空间.

5.两个string对象相加

string对象的加法被定义为连接(concatenation).也就是说,两个(或多个)

string对象可以通过使用加操作符+或者复合赋值操作符+=连接起来.

给定两个string对象:

string s1("hello, ");
string s2("world/n");

下面把两个string对象连接起来产生第三个string对象:

string s3=s1+s2;  //s3 is hello,world/n

如果要把s2直接追加到s1的末尾,可以使用+=操作符;

s1+=s2;   //equivalent to s1=s1+s2

6.和字符串字面值的连接

上面的字符串对象s1和s2直接包含了标点符号.也可以通过将string对象和字符

串字面值混合连接得到同样的结果:

string s1("hello");
string s2("world");
string s3=s1+","+s2+"/n";

当进行string对象的字符串字面值混合连接操作时,+操作符的左右操作数必须至

少有一个是string类型的:

string s1="hello";
string s2="world";
string s3=s1+",";
string s4="hello"+",";
string s5=s1+","+"world";
string s6="hello"+","+s2;

s3和s4的初始化只用了一个单独的操作.s3把一个string对象和一个字符串字面

值连接起来.是合法的.s4却试图将两个字符串字面值相加,因此是非法的.s5的初

始化显得有点不可思议.但这种用法和标准输入输出的串联效果是一样的.本例中

,string标准库定义加操作返回一个string对象.这样,在对s5进行初始化时,子表

达式s1+","将返回一个新string对象,后者再和字面值"world/n"连接.整个初始

化过程可以改写成:

string tmp =s1+","

s5=tmp+"world";

而s6的初始化显然是非法的.依次来看每个字表达式,则第一个子表达式试图把两

个字符串字面值连接起来,这是不允许的.

7.从string对象获取字符

string类型通过下标操作符([])来访问string对象中的单个字符.下标操作符需

要取一个size_type类型的值,来标明要访问字符的位置.这个下标中的值通常被

称为"下标"或"索引(index)".

注解:string对象的下标从0开始.如果s是一个string对象且s不空,则s[0]就是字

符串的第一个字符,s[1]就表示第二个字符(如果有的话),而s[s.size()-1]则表

示s的最后一个字符.引用下标时如果超出下标作用范围就会引起溢出错误.

可用下标操作符分别取出string对象的每个字符,分行输出:

string str("some string");

for(string::size_type ix=0; ix !=str.size();++ix)

cout<<str[ix]<<endl;

每次通过循环,就从str对象中读取下一个字符,输出该字符并换行.

8.下标操作可用作左值.

前面说过,变量是左值,且赋值操作的左操作数必须是左值.和变量一样,string对

象的下标操作返回值也是左值.因此,下标操作可以放于赋值操作符的左边或右边

.通过下面循环把str对象的每一个字符置为'*';

for(string::size_type ix=0;ix!=str.size();++ix)

str[ix]='*';

9.计算下标值

任何可产生整型值的表达式都可用作下标操作符的索引.例如,假设someval和

someotherval是两个整型对象,可以这样写:

str[someotherval*someval]-someval;

虽然任何整型数值都可作为索引,但索引的实际数据类型却是unsigned类型

string::size_type

实践告诉你:前面讲过,应该用string::size_type类型的变量接受size函数的返

回值.在定义用作索引的变量时,处于同样的道理,string对象的索引变量最好也

用string::size_type类型.

在使用下标索引string对象时,必须保证索引值"在上下界范围内"."在上下界范

围内"就是指索引值是一个赋值为size_type类型的值,其取值范围在0到string对

象长度减1之间.使用string::size_type类型或其他unsigned类型作为索引,就可

以保证索引值不小于0.只要索引值是unsigned类型,就只需要检测它是否小于

string对象的长度.

小心:标准库不要求检查索引值,所用索引的下标越界是没有定义的,这样往往会

导致严重的运行时错误.
 

String a="hello world"; //在java中有一个常量池,当创建String 类型的引用变量给它赋值时,java会到它的常量池中找"hello world"是不是在常量池中已存在。如果已经存在则返回这个常量池中的"hello world"的地址(在java中叫引用)给变量a 。注意a并不是一个对象,而是一个引用类型的变量。它里面存的实际上是一个地址值,而这个值是指向一个字符串对象的。在程序中凡是以"hello world"这种常量似的形式给出的都被放在常量池中。 String b=new String("hello world"); //这种用new关键字定义的字符串,是在堆中分配空间的。而分配空间就是由new去完成的,由new去决定分配多大空间,并对空间初始化为字符串"hello world" 返回其在堆上的地址。 通过上面的原理,可以做如下实验: String a="hello world"; String b="hello world"; String c=new String("hello world"); String d=new String("hello world"); if(a==b) System.out.println("a==b"); else System.out.println("a!=b"); if(c==d) System.out.println("c==d"); else System.out.println("c!=d"); //输出结果: a==b c!=d 为什么会出现上面的情况呢? String a="hello world"; String b="hello world"; 通过上面的讲解可以知道,a和b都是指向常量池的同一个常量字符串"hello world"的,因此它们返回的地址是相同的。a和b都是引用类型,相当于c语言里面的指针。java里面没有指针的概念,但是实际上引用变量里面放的确实是地址值,只是java为了安全不允许我们对想c语言中的那样对指针进行操作(如++ 、--)等。这样就有效的防止了指针在内存中的游离。 而对于 String c=new String("hello world"); String d=new String("hello world"); 来说是不相等的,他们是有new在堆中开辟了两块内存空间,返回的地址当然是不相等的了。如果我们要比较这两个字符串的内容怎么办呢?可以用下面的语句: if(c.equals(d)) System.out.println("c==d"); else System.out.println("c!=d"); //输出 c==d
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值