C++ Primer | 第三章 字符串、向量和数组

除了第2章的内置类型,c++ 还定义了丰富的抽象数据类型库,string和vector是两种重要的标准库类型,前者支持可变长字符,后者表示可变长的集合。内置数组相对于string和vector更加基础。

3.1 命名空间 using 声明

之前我们已经知道了命名空间std,使用他的方法是使用作用域符号(::),如std::cin。本章将会介绍一种更简单的安全的方法:使用using 声明,如:

#include <iostream>
//using 声明,声明形式  using namespace::name
using std::cin;
int main()
{
int i;
cin>>i;
cout<<i;//错误,没有声明
std::cout<<i;
return 0;
}

每个名字都需要独立的using声明,但是要注意,头文件中不应该使用using,防止使用中产生冲突。

# include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main()
{
cout <<"enter two numbers"<<endl;
int v1,v2;
cin>> v1>>v2;
cout << "the sum of "<< v1 <<v2 <<"is"<<v1+v2<<endl;
return 0;

}

3.2 string

#include <string>
using std::string

3.2.1 定义和初始化string


string s1;  //默认,空
string s2(s1);  // s2是s1的副本 copy initialization
string s2=s1;   // 同上 direct initialization
string s3("values");    //s3是字面值“values”的副本,除了字面值最后的那个空字符外
string s3="values"; //同上,注意 单引号是字符,双引号是字符串
string s4(n,'c'); // n 个c

3.2.2 string 对象的操作

<<  //注意,string对象会自动忽略开头的空白(空格,换行,制表等符)直到下一个空白为止
>>  //如输入“   h   ”,输出将是“h”
getline(is,s)   // 从 is 中读取一行赋值给s,返回is ;注意这里会保存空格,以换行符为间隔,如果一开始就是换行符就会得到一个空的string
s.empty()
s.size()
s[n]    // n,需要在合法范围内,否则会产生缓冲区溢出(buffer overflow)
s1+s2   // 注意,s1或者s2其中一个必须是string类型,不能把两个字面值直接相加 如"a"+"b"+s1是错误的!
s1=s2
s1==s2
s1!=s2

关系运算符的比较字典顺序:
1. 字符串长度不同,对应位置相同,短的小于长的
2. 两个字符串在对应位置不一致,那么其比较结果为第一对相异对象的比较结果

3.2.3 处理string 对象中的字符

cctype头文件是从c中继承的标准库,去掉了h,加入了字母c,其中的函数有:

isalnum(c)
isalpha(c)
iscntrl(c)
isdigit(c)
isgraph(c)
islower(c)
isprint(c)
ispunct(c)//标点
isspace(c)
isupper(c)
isxdigit(c)
isxdigit(c)
tolower(c)
toupper(c)

如果要处理每个字符可以使用for(range for )语句:

string str("some string");
for (auto c: str)
cout << c<<endl;

改变字符串中的值
把循环变量定义成引用类型*********************************************

// 将所有字母改变为大写字母
string s("Hello World!!!");
for (auto &c:s)
   c=toupper(c);//注意c是一个引用,改变的是s中的字符的值
   cout<<s<<endl;
// 将第一个词改为大写
//注意,使用下标时,下标不可超出字符串长度范围,空字符不能使用下标,所以,所以,所以,空的string不可以使用下标,使用下标时要注意排除s.empty()
for (decltype(s.size())index=0;//这里可以保证index的类型时string::size_type 
    index!=s.size()&&!isspace(s[index]);++index)
        s(index)=toupper(s[index]);

3.3 标准库类型 vector

vector是一个类模版,使用时需要在后面添加尖括号<>
vector<int>,引用不是对象,不存在包含引用的vector。老式的声明语句中,如果vector的元素还是vector,那么他必须在外层两个尖括号之间加入空格,如vector<vector<int> >//最后两个之间有空格

3.3.1 初始化

vector<T> v1
vector<t> v4(n)//包含了n个重复的元素
vector<T> v5{a,b,c...}

对vector赋值时,可以制定另外一个vector的对象,但是必须是相同类型如:

vector<int> ivec2;
vector<string> svec(ivec2);//错误,类型不一样
vector <int> v1(10);    //v1有10个元素,每个都是0
vector <int> v2{10};    //v2有一个元素10
vector <int> v3(10,1);
vector <int> v4{10,1};
vector<string> v5("hi");//错误!

3.3.2 vector 添加元素

vector<int> v2;
for (int i=0;i!=100;++i)//注意这里不能使用范围for 循环
    v2.push_back(i) // 不能使用下标来添加元素

3.3.3 vector的其他操作

vector的其他操作与string的操作相似,如empty等,此时不用加尖括号
但是size_type 需要制定类型,如:

vector <int>::size_type //正确
vector :: size_type //错误

3.4 迭代器

迭代器的运算符

*iter ;// 返回iter所指元素的引用,使用解引用要注意和()结合,如(*iter).empty()正确但是*iter.empty() 错误
iter->men,解引用iter并获取该元素名为men的成员,等价于(*iter).men
++iter
--iter
==
!=
//利用迭代器将第一个单词大写
for (auto it=s.begin();it !=s.end()&&!isspace(*it);++it)//it!=s.end确保不是空
    *it=toupper(it);

迭代器类型

vector<int>::iteartor it;//it 能读写vector<int>的元素
vector<int>::const_iterator it3;//只能读不能写元素
//const_iterator 类似于常量指针,能读取但是不能修改他所指向的元素,
//如果其对象是一个常量 只能使用const_iterator不能使用iterator
//如果不是常量两者都可以
//另外还有cbegin();cend();
//在使用迭代器的循环体时不可以向其容器添加元素

3.5 数组

数组在初始化时必须知道其元素个数,其其维度必须是一个常量

unsigned cnt =42;//尽管cnt本身是一个常量但是他的数据类型不是const unsigned
constexpr unsigned sz=42;
string bad[cnt];//错误,cnt不是常量表达式
int *parr[sz];//正确含有42个整形指针的数组
//定义数组时不可以使用AUTO类型
// 如果使用列表初始化{},可以不用制定纬度
int a2[]={1,2};
//字符数组可以使用字符串字面值赋值,但是要注意此时会将空字符拷贝进去
char a4[6]="asdfgh";//错误,没有空间放空字符
//不允许拷贝和赋值
int a[]={1,2};
int a2[]=a;//错误
a3=a;//错误
int *ptrs[10];//含有10个整形指针的数组,从右往左:定了一个大小为10的数组,名字时ptrs,存放的是int的指针
int (*parray)[10];//由内向外,*parray意味着parray 是一个指针,看右边,parray是一个纸箱大小为10的数组的指针,接下来看左边,可知道parray数组中的元素是int
int *(&array)[10];//array是一个数组的引用,该数组含有10个指针
//使用vector统计分数段数量
vector <unsigned> scores(11,0);
unsigned grade;
while (cin>>grade){
    if (grade<=100)
        ++scores[grade/10];}
//---------------------------------
//使用数组
unsigned scores[11]={};
unsigned grade;
while (cin>>grade){
    if (grade<=100)
        ++scores[grade/10];}

3.5.3 指针与数组

//大多数表达式中,使用数组名字的地方是使用指向它首个元素的指针
string nums[]={"one","two"};
string *p2=nums;//等价于p2=&nums[0]


int ia[]={1,2};
auto ia2(ia);//ia2是一个整形指针
ia2=42;//错误,指针不能这样赋值

数组的尾后指针

int arr[]={0,1};
int *e=&arr[2];//这样正确,但是比较容易出错
//使用beginend
int *last=end(arr);
int *beg=begin(arr);

下标与指针

int ia[]={0,2,4,6,8};
int *p=&ia[2];
int j=p[1];// p[1]等价于*(p+1),即ia[3]
int k=p[-2];//p[-2]是ia[0]那个位置

3.5.4 c风格字符串

尽量不要使用

3.5.5 旧代码接口

使用数组初始化vector对象

int ia[]={0,2,4,6,8};
vector<int> ivec(begin(ia),end(ia));//ivec 里面的元素是ia的备份

使用指针和数组容易出错,应该尽量使用vector和迭代器,应该尽量使用string,避免使用基于数组的C风格的字符串

3.6 多维数组

数组的数组就是多维数组
初始化

int ia[3][4]={{0,1,2,3},
            {0,1,2,3},
            {0,1,2,3}}
//也可以没有中间的花括号
int ia[3][4]={0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3}
ia[2][3]=arr[0][0][0];
int (&row)[4]=ia[1];//表示ia[1][:]

使用范围for语句处理多维数组

size_t cnt=0;
for (auto &row:ia)//这里使用引用类型也是为了防止row自动变为首元素的指针
    for (auto &col :row){
        col=cnt;
        ++cnt;
        }
int *ip[4];//整形指针的数组
int (*ip)[4];//指向含有4个整数的数组的指针
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值