第三章字符串、向量和数组

3.1命名空间的using声明

       ::(域操作符):编译器从操作符左侧名字作用域中,寻找右侧的名字。

using namesapce::name; //注意分号

       头文件不应该包含using声明

 3.2标准库类型string

       使用string类型必须包含string头文件。string 定义在命名空间std中,必须包含命名空间才能使用。 

3.2.1定义和初始化string对象

string s1;                      //默认初始化,为空字符串

string s2= s1;                  //s2 是s1的副本

string s22(s1);

string s3="hiya";               //s3是字符串字面值的副本----只有4个字符,没有编译器加的空字符

string s3("hiya")

string s4(10,'c);               //s4是cccccccccc

string s5={"abc"};              //s5也是可以的

       "="初始化一个变量,执行的是拷贝初始化。把等号右侧的初始值拷贝到新创建的对象中。

       不使用等号则执行直接初始化。

3.2.2string 对象上的操作

       读写string对象

string s; cin>>s;

       读取的时候会自动忽略开头的空白(空格、制表、换行),并从第一个真正的字符开始读取。

       读取未知数量的string对象

       while(cin>>s)  如果流有效,也就是说没有遇到结束标记和非法输入,一直执行 。

       使用getline读取一行

       getline遇到换行符为止

       string的empty和size操作

string ss;

ss.empty();ss.size();

string::size_type类型

       string类和其他大多数标准库类都定义了集中配套类型,这些配套类型体现了标准库类型和机器无关的特性,size_type就是其中之一。size_type是无符号的值。

       基本上用auto和decltype来推断变量类型。注意不能与带符号数混合,如果n是负数,则s.size()<n将会成立,因为负数n将会转化为一个比较大的无符号数。

       比较string对象

       string对象对字符大小写敏感,如果两个string对象长度不同,且短string对象每个字符与长string对应位置字符相同,则短string小于长string

       如果两个string对象在某些位置不匹配,则string对象比对结果为第一个相异字符比较的结果。

string s1="Hello";

string s2 = "Hello,world";

string s3= "Hiya";

s1 <s2 ; s3 <s2

       两个string对象相加,必须确保每个+运算符两侧的运算对象至少有一个为string.

3.2.3处理string对象中的字符

       在cctype中定义了一些标准库函数。

       isalnum(c) 是否字母和数字

       isalpha(c) 是否字母

       iscntrl(c) 是否控制字符

       isdigit(c) 是否数字

       isgraph(c) 是否空格

       islower(c) 是否字母小写

       isprint(c) 是否可以打印

       ispunct(c) 是否标点符号

       isspace(c) 是否空格

       isupper(c) 是否大写字母

       isxdigit(c) 是否大写数字

       tolower(c) 输出小写

       toupper(c) 输出大写

       使用for循环处理字符串

       如果想改变string字符串,必须把循环变量定义为引用类型。

for(auto &c:s)//因为引用被绑定在序列的每个元素上。

       要想访问string对象的单个字符有两种方式,一种是下标([]),输入参数是string::size_type类型,返回该位置上的引用,string对象的下标必须大于等于0且小于s.size(),如果输入是带符号的类型的值,将自动转换为string::size_type表达的无符号的类型。

3.3标准库类型vector

       标准库类型vector表示对象的集合,其中所有对象的类型都相同。使用vector必须使用头文件。vector是模板而非类型,由vector产生的类型必须包含vector中的元素类型,例如vector<int>

       vector能够容纳大多数的类型对象作为其元素,但因为引用不是对象,所以不存在包含引用的vector.

3.3.1定义和初始化vector对象

vector<T> v1

vector<T> v2(v1)

vector<T> v2 = v1

vector<T> v3(n,val)

vector<T> v4(n)

vector<T> v5{a,b,c,...}

vector<T> v5={a,b,c...}

       1.使用拷贝初始化(=)只能提供一个值。

       2.如果提供一个类内初始值,则只能使用拷贝初始化或花括号的形式。

       3.如果提供列表初始化,只能把元素放在花括号里面。

       其中注意一种特殊情况

       vector<string> v8{10,"hi"};//v8有10个值为“hi”的元素

3.3.2 向vector对象添加元素

       push_back;如果循环体内包含vector添加元素,则不用使用for循环。for语句体内不应该改变其所遍历序列的大小。

       v.empty();v.size();v.push_back();v[n];v1=v2;v1={a,b,c....},v1==v2; v1 != v2; < <= > >=

       要给vector中的元素赋值,在for循环中,也是需要用&引用类型。

       vector的size_type 是vector<int>::size_type;不是vector::size_type

       下标的形式和string类似,可以读取操作该元素,但是不能通过下标的形式添加元素。

3.4迭代器

       所有标准库类型都可以使用迭代器,迭代器类似于指针类型,提供了对对象的间接访问。

3.4.1使用迭代器

       有迭代器的类型同时也有返回迭代器的成员。比如都有begin和end成员

auto b = v.begin(),e = v.end()//b 和e的类型相同

       end成员返回指向迭代器“尾巴元素的下一位置”。

       *iter    返回迭代器iter所指元素的引用

       iter->mem 解引用iter并获取该元素的名为mem的成员

       ++iter --iter 上一个和下一个

       iter1 == iter2 判断是否相等,如果两个迭代器指向对象相同。

string s("some thing");

if(s.begin() != s.end())

  auto it = s.begin();

  *it = toupper(*it);

       迭代器类型

       那些拥有迭代器的类库,使用iterator和const_iterator表示迭代器类型。

vector<int>::iterator  it;

string::iterator  is;

vector<int>::const_iterator ict3 //只能读元素,不能写元素

       如果vector或者string 对象是常量,只能用const_iterator,如果vector和string对象不是常量,可以用iterator也可以用const_iterator.

       对应的cbegin 和cend;

(*it).empty() 等价于 it->empty()

       对vector对象操作会让迭代器失效。一个限制是不能再范围for循环向vector添加元素,另外一个是任何一种可能改变vector对象容量的操作,比如push_back都会让迭代器失效。

3.4.2迭代器运算

       迭代器可以跨过多个元素,同时支持关系运算,所有这些都是迭代器运算

       iter +n ; iter -n; iter+=n; iter -=n; iter1-iter2; > >= < <=

       只要两个迭代器指向的统一个容器中的元素,就能相减,所得结果为两个迭代器距离,类型为difference_type的带符号整数。

3.5数组

       与vector 不同数组大小是确定不变的,不能随意向数组中添加元素。如果不清楚元素的确切个数,请使用vector.

       a[d],a是数组的名字,d是数组的维度,必须大于0。数组元素个数也是数组一部分,,编译的时候应该已知,维度必须是一个常量表达式。

       定义数组的时候必须指定数组的类型,不允许用auto,同时与vector一样,不存在引用的数组。

       显式初始化数组元素

       如果对数组进行列表初始化,允许忽略数组的维度,编译器会自动根据初始数量的大小推算出来。如果指明了维度,初始值总数量不应该超过指定的大小。

const unsigned sz = 3;

int ia1[sz]= {0,1,2};

int a2[] = {0,1,2};

int a3[5]= {0,1,2};

string a4[3]= {"hi","bye"};

int a5[2]={0,1,2};//错误,初始值过多

       字符数组的特殊性

       字符串字面值结尾还有一个空字符。

char a1[]={'c','+'}

char a2[]={'c','+','\0'};

char a3[]="c++";       //有空字符

const char a4[6]="Daniel";  //错误,空间不够

       不允许拷贝和赋值

       不能讲数组的内容拷贝给其他数组作为初始值,也不能用数组为其他数组赋值

int a[] = {1,2,3};

int b[] = a;//错误

b = a;      //错误

int *ptr[10] //ptr是含有10个整数指针的数组

int &ref[10] //错误,不存在引用的数组

int (*ptr)[10] = &arry; //ptr是指向一个含有10个整数的数组

int (&ref)[10] =arr; //ref是引用一个含有10个整数的数组。

       默认情况下类型符从右往左依次绑定。对于第一个ptr,从右往左:首先是大小为10的数组,他的名字是ptr,然后存放的内容是int *;

       对于第二个ptr,因为有(),(*ptr)作为一个整体,ptr是一个指针,他指向的是一个大小为10的数组,,数组元素是int;

3.5.2访问数组元素

       数组元素的下标类型为size_t,size_t是一种机器相关的无符号类型。在cstddef头文件定义了size_t,

       数组的下标由程序员检查,编译器可以编译通过

3.5.3指针和数组

       使用数组的时候编译器一般会把它变为指针。

       对数组元素使用取地址符就能得到指向该元素的指针。

string nums[]= {"one","tow","three"};

string *p = &nums[0];

       数组名为指向第一个数组首元素的指针。

       使用数组作为一个auto变量的初始值,推断得到的类型就是指针而非数组。

int ia[] = {0,1,2,3,4}

auto ia2(ia); //ia2是一个指针,指向ia数组的第一个元素 相当于执行 auto ia2(&ia[0]);

ia2 =42;//错误

       使用decltype关键字转换,decltype(ia)返回类型由10个整数构成的数组。

decltype(ia) ia3 = {0,1,2,3};

ia3[3]=1;

       指针也是迭代器,允许++和--  arr有9个元素 int*e = &arr[10]不会报错,但是不可预料

       标准库函数begin和end

       为了让指针使用更简单,C++引入了两个名为begin和end的函数。在iterator头文件中

int ia[] = {0,1,2,3};

int *beg = begin(ia); //指向ia的首元素

int *end = end(ia);  //指向ia尾巴元素的下一个元素

       指针可以进行解引用、递增、比较、与整数相加、两个指针相减。

       auto n = end(arr)- begin(arr) 类型为ptrdiff_t,定义在cstddef头文件中。是带符号的类型。

       两个指针指向不同的对象不能进行比较。

3.5.4C风格字符串

       C风格字符串,不是一种类型,字符串存放在字符数组中并以空字符结束‘\0’

       c标准库string函数

       定义在cstring头文件中,

strlen(p) strcmp(p1,p2) strcat(p1,p2) strcpy(p1,p2)

const char ca1[] = "A string";

const char ca2[] = "B string";

if(ca1 <ca2)//错误不能2个地址比较可以 if(strcmp(ca1,ca2)<0)

3.5.5与旧代码接口

       混用String和C风格字符串

string s("hello world") //s被初始化为“hello world”没有'\0'

       在string中,出现字符串字面值的地方允许可以用空字符结束的字符数组来替代。

       1.允许使用以空字符结束的字符数组来初始化string对象或为string对象赋值。

       2.在string对象的加法加法运算中允许以空字符结束的字符数组作为一个运算对象(不能两个运算对象都是);

         在string对象的复核赋值运算中允许使用以空字符结束的字符数组作为右侧的运算对象。

       上述性质反过来不成立。不能用string对象直接初始化指向字符的数组,为此string专门开发了一个函数,c_str;

       char * str= s//错误

       const char *str = s.c_str();//正确 c_str返回一个c风格字符串。const char 确保不会改变内容

       使用数组初始化vector对象

       不允许用一个数组为另外一个数组初始化,也不允许用vector为数组初始化,相反允许用数组来初始化vector.

       只需要指明数组的首地址和尾巴地址

int aa = {0,1,2,3,4};

vector<int> aa1 (begin(aa),end(aa))

vector<int> aa(aa+1,aa+2)//都可以 

       在现代C++程序中尽量使用vector和迭代器,避免使用内置数组和指针

3.6多维数组

       多维数组其实是数组的数组。

       允许使用花括号括起来的一组值,初始化多维数组

       int ia[3][4]={{0,1,2,3},{3,4,5,6}};

       int ia[3][4]={0,1,2,3}

       多维数组下标引用

       如果表达式含有下标运算符数量和数组维数一样多,该表达式的结果是给定型元素。

       如果表达式含有下标运算符数量比数组维数小,则表达式结果为给定索引处的一个内层数组。

       int (&row)[4] = ia[1];

       int (*p)[4] = ia+1;

       虽然指针不可以赋值和初始化。但是这样可以。

for(const auto &row:ia)

  for(auto col:row)

   cout<< col <<endl;

       必须将外层循环控制声明为引用,避免数组自动转为指针

       要使用范围for语句处理多维数组,除了内层循环外,其他所有循环控制变量都应该为引用。

int ia[3][4];

int (*p)[4] = ia;

for(auto p = ia;p!=ia+3;++p)

  for(auto q = *p;q!=*p +4;++q)
for(auto p = begin(ia);p!=end(ia);++p)

   for(auto q = begin(*p);q!=end(*p);++q)

      cout<<*q<<endl;
using int_array= int[4];

typedef int int_array[4]; //和typedef int *p;一样。表示int_array是含有4个元素的数组,每个元素是int

for(int_array *p= ia;p!=ia+3;++p)

  for(int *q = *p;q!=*p+4; ++q)

    cout<<*q<<endl;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值