命名空间的using声明和标准库类型string
命名空间的using声明
using声明的形式
using namespace::name;
Code Example:
#include<iostream>
using std::cin;
int main()
{
int i;
cin >> i;
cout << i;//错误:没有对应的using声明,必须使用完整的名字 std::cout
std::cout << i;//正确:显式地从std中使用cout
return 0;
}
每个名字都需要独立的using声明
每个using声明引入命名空间中的一个成员
Code Example:
#include<iostream>
using std::cin;
//每个using声明引入命名空间中的一个成员
using std::cout; using std::endl;
int main()
{
cout << "Enter two number:" << endl;
int v1, v2;
cin >> v1 >> v2;
cout << "The sum of " << v1 << " and " << v2
<< " is " << v1 + v2 << endl;
return 0;
}
头文件不应包含using声明
位于头文件的代码一般来说不应该使用using声明。因为头文件里包含了using声明,那么使用该头文件的文件就都会有这个声明,可能会产生名字冲突
标准库类型string
标准库类型string —可变长的字符序列,使用string类型需包含string头文件,作为标准库的一部分,string定义在命名空间std中
#include<string>
using std::string;
定义和初始化string对象
初始化String对象的方式
语句 | 功能 |
---|---|
string s1 | 默认初始化,s1是一个空串 |
string s2(s1) | s2是s1的副本 |
string s2 = s1 | 等价于s2(s1) , s2是s1的副本 |
string s3(“value”) | s3是字面值”value“的副本,除了字面值最后的那个空字符外 |
string s3 = “value” | 等价于s3(“value”), s3是字面值”value“的副本 |
string s4(n,‘c’) | 把s4初始化为由连续n个字符c组成的串 |
拷贝初始化:使用=
来初始化一个变量,编译器把等号右侧的初始值拷贝到新创建的对象中。
直接初始化:不使用等号
初始值只有一个时,拷贝初始化和直接初始化都可以,当初始化要用到的值有多个,一般只能使用直接初始化
string s5 = "hiya";//拷贝初始化
string s6("hiya");//直接初始化
string s7(10,'c');//直接初始化,s7的内容是cccccccccc
多值进行初始化的时候,也可以用拷贝初始化但需显式的创建一个(临时)对象用于拷贝:
(不建议麻烦,可读性差,无任何补偿优势)
string s8 = string(10,'c');//拷贝初始化
//相当于以下代码
string temp(10,'c');
string s8 = temp;
string对象上的操作
string的操作
语句 | 功能 |
---|---|
os<<s | 将s写到输出流os当中,返回os |
is>>s | 从is中读取字符串赋给s,字符串以空白分隔,返回is |
getline(is,s) | 从is中读取一行赋给s,返回is |
s.empty() | s为空返回true,否则返回false |
s.size() | 返回s中字符的个数 |
s[n] | 返回s中的n个字符的引用,位置n从0计起 |
s1+s2 | 返回s1和s2连接后的结果 |
s1=s2 | 用s2的副本代替s1中原来的字符 |
s1==s2 | 若s1和s2中所含的字符完全一样,则它们相等;大小写敏感 |
s1!=s2 | 若s1和s2中所含的字符完全一样,则它们相等;大小写敏感 |
<、<=、>、>= | 利用字符在字典中的顺序进行比较,且对字母的大小写敏感 |
读写string对象
可以使用IO操作符读写string对象
string s;//空字符串
cin>>s;//将string对象读入s,遇到空白停止
cout<<s<<endl;//输出s
读取操作时,string对象自动忽略开头的空白(即空格符、换行符、制表符等)并从第一个真正的字符开始读起,直到遇见下一处空白为止
读取未知数量的string对象
string word;
while (cin>>word)//反复读取,直至到达文件末尾
{
cout << word << endl;//逐个输出单词,每个单词后面紧跟一个换行
}
while语句的条件部分负责在读取时检测流的情况,若流有效,即没遇到文件结束标记或非法输入,则执行while语句内部的操作。一旦遇到文件结束标记或非法输入,循环结束
使用getline读取一整行
希望保留输入时的空白符则应该使用getline
函数 ,getline()
的参数是一个输入流和一个string对象。
从给定的输入流中读入内容,直到遇到换行符为止(换行符也被读入了),把所读的内容存入到string对象中(不存换行符)。
一遇到换行符就结束读取操作并返回结果,即使是一开始就是换行符。若输入一开始就是换行符,则所得结果是个空string
和输入运算符一样,getline
也会返回它的流参数,故getline
的结果也可作为条件
string line;
//每次读入一整行,直至到达文件末尾
while(getline(cin,line))
cout<<line<<endl;
endl结束当前行并刷新显示缓冲区
Note:
触发getline函数返回的那个换行符实际上被丢弃了,得到的string对象中不包含换行符
string的emty和size操作
empty
函数根据string对象是否为空返回一个对应的布尔值,是string的一个成员函数,使用点操作符调用
string line1;
while (getline(cin,line1))
{
if (!line1.empty())
{
cout << line1 << endl;
}
}
!
为逻辑非运算符,返回与其运算对象相反的结果
size
函数返回string对象的长度(即string对象中字符的个数)
string line2;
while (getline(cin, line2))//只输出长度超过80个字符的长度
{
if (line2.size()>80)
{
cout << line2 << endl;
}
}
string::size_type类型
size()函数返回的是一个string::size_type类型的值,
string::size_type是一个无符号类型的值,而且能够存下任何string对象的大小。
通过作用域操作符表明size_type是在类string中定义的
所有用于存放string类的size函数返回值的变量都应该是string::size_type类型的
C++11中,允许编译器通过auto或者decltype来推断变量的类型
auto len = line.size();//len的类型是string::size_type
size函数返回的是一个无符号整型数,如果一条表达式中已经有了size()函数就不要在使用int了(表达式中混用了带符号数和无符号数将可能产生意想不到的结果)
比较string对象
比较运算符逐一比较string对象中的字符,并且对大小写敏感
==和!=
相等性运算符检验两个string对象相等或不相等,string对象相等:长度相同且所包含的字符也全都相同。
<、<=、>、>=
关系运算符分别检验一个string对象是否小于、小于等于、大于、大于等于另一个string对象 依照(大小写敏感)字典顺序
- 两个string对象长度不同,且较短string对象的每个字符都与较长string对象对应位置上的字符相同,则较短string对象小于较长string对象
- 两个string对象在某些对应位置上不一致,则string对象比较的结果其实是string对象中第一对相异字符比较的结果
string str = "Hello";
string phrase = "Hello World";
string slang = "Hiya";
结果:str小于phrase (规则1判断),slang比str、phrase都大(规则2判断)
为string对象赋值
允许把一个对象的值赋给另一个对象:
string st1(10,'c'), st2;
st2 = st1;//赋值:用st2的副本替换st1的内容
//both st1 and st2 are null string
两个string对象相加
对string对象使用加号运算符 +
的结果是一个新的string对象。它由加号左侧string所含的字符与右侧string所含的字符拼接而成。
复合运算符+=
负责把右侧string对象的内容追加到左侧string对象的后面
string s1 = "hello, ", s2 = "world\n";
string s3 = s1 + s2;//s3的内容是hello, world\n
s1 += s2;//等价于s1 = s1 + s2
字面值和string对象相加
标准库允许把字符字面值和字符串字面值转换成string对象,
故在需要string对象的地方可以使用它们来替代
string sss1 = "hello", sss2 = "world";
string sss3 = sss1 + "," + sss2 + '\n';
必须确保每个加法运算符的两侧的运算对象至少有一个是string
string s4 = s1 + ",";//正确,存在至少一个string
string s5 = "hello" + ",";//错误:两个运算对象都不是string
string s6 = s1 + "," + "world";
//正确:相当于string s6=(s1+",")+"world";
string s7 = "hello" + "," + s2;
//error,相当于s7=("hello"+",")+s2; 不能字面值直接相加
字符串字面值与string是不同的类型
处理string中的字符
cctype头文件中的函数
函数 | 作用 |
---|---|
isalnum( c ) | 当c是字母或数字是为真 |
isalpha( c ) | 当c是字母时为真 |
iscntrl( c ) | 当c是控制字符时为真 |
isdigit( c ) | 当c是数字时为真 |
isgraph( c ) | 当c不是空格但可打印时为真 |
islower( c ) | 当c是小写字母时为真 |
isprint( c ) | 当c是可打印字符时为真(即c是空格或c具有可视形式) |
ispunct( c ) | 当c是标点符号时为真(即c不是字母、数字、字母、可打印空白中的一种) |
isspace( c ) | 当c时空白时为真(即c时空格、横向制表符,纵向制表符、回车符、换行符、进纸符中的一种) |
issupper ( c ) | 当c是大写字母时为真 |
isxdigit( c ) | 当c是十六进制数字时为真 |
tolower( c ) | 如果c是大写字母,输出对应的小写字母:否则原样输出c |
toupper( c ) | 如果c是小写字母,输出对应的大写字母:否则原样输出c |
C语言中的头文件形如:name.h,C++则将这些文件命名为cname
特别的,cname的头文件中定义的文字从属于std,而定义在名为.h的头文件的则不然
标准库中的名字总能在std中找到
处理每个字符 使用基于范围的for语句
范围for(range for)语句(C++11):遍历给定序列中的每个元素并对序列中的每个值执行某种操作
for(declaration:expression)
statement
expression是一个对象,表示一个序列
declaration负责定义一个变量,被用于访问序列中的基础元素。每次迭代,declaration部分的变量会被初始化为expression部分的下一个元素值
一个string对象表示一个字符的序列,故string对象可作为范围for语句中的expression部分
string str("some string");
for (auto c : str)
cout << c << endl;
此处通过auto让编译器决定c的类型,此处c的类型是char
范围for语句和ispunct()统计标点符号数
string s("Hello World!!!");
//punct_cnt类型和s.size的返回类型一样即string::size_type,是一个无符号类型的值
decltype(s.size()) punct_cnt = 0;//标点符号计数值
for(auto c:s)
if (ispunct(c))
{
++punct_cnt;
}
cout << punct_cnt << " punctuation characters in " << s << endl;
此处使用decltype声明punct_cnt,类型为string::size_type
使用范围for语句改变字符串中的字符
若想改变string对象中字符的值,必须把循环变量定义成引用类型,当使用引用作为循环控制变量时,这个变量实际上被依次绑定到了序列的每个元素上。使用这个引用,就能改变它绑定的字符
把字符串改写为大写字母的形式
string s("Hello World!!!");
for (auto& c : s)
c = toupper(c);
cout << s << endl;
只处理一部分字符
访问string对象中的单个字符有两个方式:
- 使用下标
- 使用迭代器
下标运算符[]
接收的输入参数是string::size_type类型的值,这个参数表示要访问的字符的位置:返回值是该位置上字符的引用
string对象的下标从0计起 ,s[s.size()-1]是最后一个字符
string对象的下标必须大于等于0而小于s.size()
使用下标访问空string会引发不可预知的结果
下标的值称:“下标” 或 “索引” ,任何表达式只要它的值是一个整型值就能作为索引,若某个索引是带符号类型的值将自动转换成由string::size_type表达的无符号类型
//判空操作
if (!s.empty())
{
cout << s[0] << endl;
}
只要对string对象使用了下标,都要确定在那个位置上确实有值,s为空,则s[0]的结果将是未定义的
只要字符串不是常量,就能为下标运算符返回的字符赋新值
//判空并对第一个字符改为大写形式
string s1("some string");
if (!s1.empty())
{
s[0] = toupper(s[0]);
}
cout << s1 << endl;
输出结果:
Some string
使用下标执行迭代
//把s1的第一个词改成大写形式
//依次处理s1中的字符直至我们处理完全部字符或遇到一个空白
for (decltype(s1.size()) index = 0; index!=s1.size()&&!isspace(s1[index]); ++index)
{
s1[index] = toupper(s1[index]);//将当前字符改成大写形式
}
cout << s1 << endl;
逻辑与运算符&&
规则:参与运算的两个运算对象都为真,则逻辑与结果为真,否则为假
只有当左侧运算对象为真时才会检查右侧运算对象
Tip:
下标必须大于等于0而小于字符串的 size() 的值,
简便易行的方法是:总是设下标的类型为 string::size_type。
因为此类型是无符号数,可确保下标不会小于 0,
此时只需保证下标小于 size() 的值
使用下标执行随机访问
例:把0~15之间的十进制数转换成对应的十六进制数,只需初始化一个字符串令其存放16个十六进制"数字"
const string hexdigits = "0123456789ABCDEF";
cout << "Enter a series of number between 0 and 15" << endl;
string result;//此时还是空字符串
string::size_type n;//用于保存从输入流读取的数
while (cin>>n)
{
if (n<hexdigits.size())
{
result += hexdigits[n];//得到相应的十六进制数字
}
}
cout << result << endl;