C++primer 第 3 章 字符串、向量和数组 3 . 5 数组

3.5数组

  • 数组是一种类似于标准库类型vector(参见3.3节,第86页)的数据结构,但是在性能和灵活性的权衡上又与vector有所不同。与vector相似的地方是,数组也是存放类型相同的对象的容器,这些对象本身没有名字,需要通过其所在位置访问。与vector不同的地方是,数组的大小确定不变,不能随意向数组中增加元素。因为数组的大小固定,
  • 因此对某些特殊的应用来说程序的运行时性能较好,但是相应地也损失了一些灵活性。
  • 如果不清楚元素的确切个薮,请使用vector

3.5.1定义和初始化内置数组

  • 数组是一种复合类型(参见2.3节,第45页)。数组的声明形如a[d],其中a是数组的名字,d是数组的维度。维度说明了数组中元素的个数,因此必须大于0。数组中元素的个数也属于数组类型的一部分,编译的时候维度应该是已知的。也就是说,维度必须是一个常量表达式(参见2.4.4节,第58页):

  • 和内置类型的变量一样,如果在函数内部定义了某种内置类型的数组,那么默认初始化会令数组含有未定义的值,
  • 定义数组的时候必须指定数组的类型,不允许用auto。关键字由初始值的列表推断类型。另外和vector一样,数组的元素应为对象,因此不存在引用的数组

显式初始化数组元素

  • 可以对数组的元素进行列表初始化(参见3.3.1节,第88页),此时允许忽略数组的维度。如果在声明时没有指明维度,编译器会根据初始值的数量计算并推测出来;相反,如果指明了维度,那么初始值的总数量不应该超出指定的大小。如果维度比提供的初始值数量大,则用提供的初始值初始化靠前的元素,剩下的元素被初始化成默认值(参见3.3.1节,第88页):

字符数组的特殊性

  • 字符数组有一种额外的初始化形式,我们可以用字符串字面值(参见2.1.3节,第36页)对此类数组初始化。当使用这种方式时,一定要注意字符串字面值的结尾处还有一个空字符,这个空字符也会像字符串的其他字符一样被拷贝到字符数组中去:

  • al的维度是3,a2和a3的维度都是4,a4的定义是错误的。尽管字符串字面值"Daniel1看起来只有6个字符,但是数组的大小必须至少是7,其中6个位置存放字面值的内容,另外1个存放结尾处的空字符。

理解复杂的数组声明

  • 和vector-样,数组能存放大多数类型的对象。例如,可以定义一个存放指针的数组。又因为数组本身就是对象,所以允许定义数组的指针及数组的引用。在这几种情况中,定义存放指针的数组比较简单和直接,但是定义数组的指针或数组的引用就稍微复杂一点了:

  • 默认情况下,类型修饰符从右向左依次绑定。对于Ptrs来说,从右向左(参见2.3.3节,第52页)理解其含义比较简单:首先知道我们定义的是一个大小为10的数组,它的名字是ptrs,然后知道数组中存放的是指向int的指针。但是对于Parray来说,从右向左理解就不太合理了。因为数组的维度是紧跟着被声明的名字的,所以就数组而言,由内向外阅读要比从右向左好多了。由内向外的顺序可帮助我们更好地理解Parray的含义:首先是圆括号括起来的部分,*Parray意味着Parray是个指针,接下来观察右边,可知道Parray是个指向大小为10的数组的指针,最后观察左边,知道数组中的元素是int。这样最终的含义就明白无误了,Parray是一个指针,它指向一个int数组,数组中包含10个元素。同S,(&arrRef)表示arrRef是一个引用,它引用的对象是一个大小为10的数组,数组中元素的类型是int。当然,对修饰符的数量并没有特殊限制:
  • in t * (&arry) [10] = p tr s ; / / a r r y 是数组的引用,该 数 组含有 1 0 个指针
  • 按照由内向外的顺序阅读上述语句,首先知道arry是一个引用,然后观察右边知道,arry引用的对象是一个大小为10的数组,最后观察左边知道,数组的元素类型是指向int的指针。这样,arry就是一个含有10个int型指针的数组的引用
  • 要想理解数组声明的含义,最好的办法是从数组的名字开始按照由内向外的顺序阅读"

3 .5 .2 访问数组元素

  • 与标准库类型vector和string一样,数组的元素也能使用范围for语句或下标运算符来访问。数组的索引从0开始,以一个包含10个元素的数组为例,它的索引从0到9,而非从1到10。
  • 在使用数组下标的时候,通常将其定义为size_t类型。size_t是一种机器相关的无符号类型,它被设计得足够大以便能表示内存中任意对象的大小。在cstdef头文件中定义了sizet类型,这个文件是C标准库stddef.h头文件的C++语言版本。

 

3 .5 .3 指针和数组

  • 在C++语言中,指针和数组有非常紧密的联系。就如即将介绍的,使用数组的时候编译器一般会把它转换成指针。
  • 通常情况下,使用取地址符(参见2.3.2节,第47页)来获取指向某个对象的指针,取地址符可以用于任何对象。数组的元素也是对象,对数组使用下标运算符得到该数组指定位置的元素。因此像其他对象一样,对数组的元素使用取地址符就能得到指向该元素的指针:
  • string nums [] = {"one”, "two", *'threen ; // 数组的元素是 string 对象
  • string *p = &nums [0] ; // p 指向 nums 的第一个元素
  • 然而,数组还有一个特性:在很多用到数组名字的地方,编译器都会自动地将其替换为一个指向数组首元素的指针:
  • string *p2 = nums; // 等价于 p2 = &nums [0]
  • 在大多数表达式中,使用数组类型的对象其实是使用一个指向该数组首元素的指针。
  • 由上可知,在一些情况下数组的操作实际上是指针的操作,这一结论有很多隐含的意思。其中一层意思是当使用数组作为一个auto (参见2.5.2节,第 61页)变量的初始值 时,推断得到的类型是指针而非数组:

指针也是迭代器

  • 与2.3.2节(第47页)介绍的内容相比,指向数组元素的指针拥有更多功能。vector和string的迭代器(参见3.4节,第95页)支持的运算,数组的指针全都支持。例如,允许使用递增运算符将指向数组元素的指针向前移动到下一个位置上:
  • int arr[] = 10,1,2,3,4,5,6,7,8,9};
  • int *p = arr; // p 指 向 arr的第一个元素
  • ++p; // p 指向 arr [1]
  • 就像使用迭代器遍历vector对象中的元素一样,使用指针也能遍历数组中的元素。当然,这样做的前提是先得获取到指向数组第一个元素的指针和指向数组尾元素的下一位置的指针。之前已经介绍过,通过数组名字或者数组中首元素的地址都能得到指向首元素的指针;不过获取尾后指针就要用到数组的另外一个特殊性质了。我们可以设法获取数组尾元素之后的那个并不存在的元素的地址:
  • in t *e = &arr [10] ; / / 指向a r r 尾元素的下一位置的指针
  • 这里显然使用下标运算符索引了一个不存在的元素,arr有 10个元素,尾元素所在位置的索引是9 , 接下来那个不存在的元素唯一的用处就是提供其地址用于初始化e , 就像尾后迭代器(参见3.4.1节,第 95页)一样,尾后指针也不指向具体的元素。因此,不能对尾后指针执行解引用或递增的操作。利用上面得到的指针能重写之前的循环,令其输出arr的全部元素:
  • for ( int *b = arr ; b != e ; ++b)
    cout « *b « endl; // 输出 arr 的元素

标准库函数begin和end

  • 尽管能计算得到尾后指针,但这种用法极易出错。为了让指针的使用更简单、更安全,C++11新标准引入了两个名为begin和end的函数。这两个函数与容器中的两个同名成员(参见3.4.1节,第95页)功能类似,不过数组毕竟不是类类型,因此这两个函数不是成员函数。正确的使用形式是将数组作为它们的参数:

  • begin函数返回指向ia首元素的指针,end函数返回指向ia尾元素下一位置的指针,这两个函数定义在iterator头文件中。使用begin和end可以很容易地写出一个循环并处理数组中的元素。例如,假设arr是一个整型数组,下面的程序负责找到arr中的第一个负数

  • 首先定义了两个名为pbeg和pend的整型指针,其中pbeg指向arr的第一个元素,pend指向arr尾元素的下一位置。while语句的条件部分通过比较pbeg和pend来确保可以安全地对pbeg解引用,如果pbeg确实指向了一个元素,将其解引用并检查元素值是否为负值。如果是,条件失效、退出循环;如果不是,将指针向前移动一位继续考查下一个元素。
  • 一个指针如果指向了某种内置类型数组的尾元素的“下一位置”,则其具备与ivector的end函数返回的与迭代器类似的功能。特别要注意,尾后指针不能执行解引用和递增操作,"

指针运算

  • 指向数组元素的指针可以执行表3.6 (第96页 )和 表 3.7 (第 99页)列出的所有迭代器运算。这些运算,包括解引用、递增、比较、与整数相加、两个指针相减等,用在指针和用在迭代器上意义完全一致。给(从)一个指针加上(减去)某整数值,结果仍是指针。新指针指向的元素与原来的指针相比前进了(后退了)该整数值个位置

  • ip加上4所得的结果仍是一个指针,该指针所指的元素与ip原来所指的元素相比前进了 4个位置。给指针加上一个整数,得到的新指针仍需指向同一数组的其他元素,或者指向同一数组的尾元素的下一位置:
  • / / 正确:arr转换成指向它首元素的指针;p 指向arr尾元素的下一位置
  • int *p = arr + sz; / / 使用警告:不要解引用!
  • int *p2 = arr + 10; / / 错误:arr只 有 5 个元素,p2的值未定义
  • 当给arr加上sz时,编译器自动地将arr转换成指向数组arr中首元素的指针。执行加法后,指针从首元素开始向前移动了sz(这里是5)个位置,指向新位置的元素。也就是说,它指向了数组arr尾元素的下一位置。如果计算所得的指针超出了上述范围就将产生错误,而且这种错误编译器一般发现不了。
  • 和迭代器一样,两个指针相减的结果是它们之间的距离。参与运算的两个指针必须指向同一个数组当中的元素:
  • auto n=end(arr)-begin(arr);//n的值是5,也就是arr中元素的数量
  • 两个指针相减的结果的类型是一种名为ptrdiff_t的标准库类型,和size_t一样,ptrdiff_t也是一种定义在cstddef头文件中的机器相关的类型。因为差值可能为负值,所以ptrdiff_t是一种带符号类型。只要两个指针指向同一个数组的元素,或者指向该数组的尾元素的下一位置,就能利用关系运算符对其进行比较。例如,可以按照如下的方式遍历数组中的元素:

  • 尽管作用可能不是特别明显,但必须说明的是,上述指针运算同样适用于空指针(参见2.3.2节,第48页)和所指对象并非数组的指针。在后一种情况下,两个指针必须指向同一个对象或该对象的下一位置。如果p是空指针,允许给p加上或减去一个值为0的整型常量表达式(参见2.4.4节,第58页)。两个空指针也允许彼此相减,结果当然是0。

解引用和指针运算的交互

  • 指针加上一个整数所得的结果还是一个指针。假设结果指针指向了一个元素,则允许解引用该结果指针:
  • int ia[] = (0,2,4,6,8}; / / 含 有 5个整数的数组
  • int last = * (ia + 4 ); / / 正确:把 last初始化成8,也 就 是 ia [4]的值
  • 表达式*(ia+4)计算ia前进4个元素后的新地址,解引用该结果指针的效果等价于表达式 ia[4]
  • 回忆一下在3.4.1节 (第98页)中介绍过如果表达式含有解引用运算符和点运算符,最好在必要的地方加上圆括号。类似的,此例中指针加法的圆括号也不可缺少。如果写成下面的形式:last = *ia + 4; // 正确: last =4 等价于 ia [0] + 4含义就与之前完全不同了,此时先解引用ia,然后给解引用的结果再加上4。4.1.2节 (第 121页)将对这一问题做进一步分析。

  • 虽然标准库类型string和vector也能执行下标运算,但是数组与它们相比还是有所不同。标准库类型限定使用的下标必须是无符号类型,而内置的下标运算无此要求,上面的最后一个例子很好地说明了这一点。内置的下标运算符可以处理负值,当然,结果地址必须指向原来的指针所指同一数组中的元素(或是同一数组尾元素的下一位置)。
  • 内置的下标运算符所用的索引值不是无符号类型,这一点与vector和string 不一样。

3.5.4 C 风格字符串

  • 字符串字面值是一种通用结构的实例,这种结构即是C++由C继承而来的C风格字符串(C-stylecharacterstring)oC风格字符串不是一种类型,而是为了表达和使用字符串而形成的一种约定俗成的写法。按此习惯书写的字符串存放在字符数组中并以空字符结束。以空字符结束的意思是在字符串最后一个字符后面跟着一个空字符。一般利用指针来操作这些字符串。

C标准库String函数

  • 表 3.8列举了 C 语言标准库提供的一组函数,这些函数可用于操作C 风格字符串,它们定义在cstring头文件中,cstring是 C 语言头文件string.h 的 C++版本

  • 表 3.8所列的函数不负责验证其字符串参数:
  • 传入此类函数的指针必须指向以空字符作为结束的数组:不遇到 '\0' 不结束

比较字符串

  • 比较两个C风格字符串的方法和之前学习过的比较标准库string对象的方法大相径庭。比较标准库string对象的时候,用的是普通的关系运算符和相等性运算符:

  • 谨记之前介绍过的,当使用数组的时候其实真正用的是指向数组首元素的指针(参见3.5.3节,第 105页)。因此,上面的if 条件实际上比较的是两个const char*的值。这两个指针指向的并非同一对象,所以将得到未定义的结果。
  • 比较两个C风格字符串需要调用strcmp函数,此时比较的就不再是指针了。如果两个字符串相等,strcmp返回0;如果前面的字符串较大,返回正值;如果后面的字符串较大,返回负值:
  • if (strcmp (cal, ca2) < 0) // 和两个 string 对象的比较 si < s2 效果一样

  • -个潜在的问题是,我们在估算largeStr所需的空间时不容易估准,而且largeStr所存的内容一旦改变,就必须重新检查其空间是否足够。不幸的是,这样的代码到处都是,程序员根本没法照顾周全。这类代码充满了风险而且经常导致严重的安全泄漏。
  • 对大多数应用来说,使用标准库string要比使用C 风格字符串更安全、更高效

3.5.5与旧代码的接口

  • 很多C++程序在标准库出现之前就已经写成了,它们肯定没用到string和vector类型。而且,有一些C程序实际上是与C语言或其他语言的接口程序,当然也无法使用C++标准库。因此,现代的C++程序不得不与那些充满了数组和/或C风格字符串的代码衔接,为了使这一工作简单易行,C++专门提供了一组功能。

混用string对象和C风格字符串

  • 3.2.1节(第76页)介绍过允许使用字符串字面值来初始化string对象
  • string s ("Hello World") ; // s 的内容是 Hello World
  • 更一般的情况是,任何出现字符串字面值的地方都可以用以空字符结束的字符数组来替代:
  • 允许使用以空字符结束的字符数组来初始化string对象或为string对象赋值。
  • 在string对象的加法运算中允许使用以空字符结束的字符数组作为其中一个运算对象(不能两个运算对象都是);在string对象的复合赋值运算中允许使用以空字符结束的字符数组作为右侧的运算对象。
  • 上述性质反过来就不成立了:如果程序的某处需要一个C风格字符串,无法直接用string对象来代替它。例如,不能用string对象直接初始化指向字符的指针。为了完成该功能,string专门提供了一个名为c_str的成员函数:
  • char* str=s;//错误:不能用string对象初始化char*
  • const char* str=s.cstr();//正确 
  • 顾名思义,c_str函数的返回值是一个C风格的字符串。也就是说,函数的返回结果是一个指针,该指针指向一个以空字符结束的字符数组,而这个数组所存的数据恰好与那个string对象的一样。结果指针的类型是const char*,从而确保我们不会改变字符数组的内容。
  • 我们无法保证c_str函数返回的数组一直有效,事实上,如果后续的操作改变了 s 的值就可能让之前返向的数组失去效用。
  • 如果执行完c_str ()函数后程序想一直都能使用其返回的数组,最好将该数 组重新拷贝一份

使用数组初始化vector对象

  • 3.5.1节(第102页)介绍过不允许使用一个数组为另一个内置类型的数组赋初值,也不允许使用vector对象初始化数组。相反的,允许使用数组来初始化vector对象。要实现这一目的,只需指明要拷贝区域的首元素地址和尾后地址就可以了:

  • 在上述代码中,用于创建ivec的两个指针实际上指明了用来初始化的值在数组int_arr中的位置,其中第二个指针应指向待拷贝区域尾元素的下一位置。此例中,使用标准库函数begin和end(参见3.5.3节,第106页)来分别计算int_arr的首指针和尾后指针。在最终的结果中,ivec将包含6个元素,它们的次序和值与数组int arr完全相同

3.6多维数组

  • 严格来说,C++语言中没有多维数组,通常所说的多维数组其实是数组的数组。谨记这一点,对今后理解和使用多维数组大有益处。当一个数组的元素仍然是数组时,通常使用两个维度来定义它:一个维度表示数组本身大小,另外-个维度表示其元素(也是数组)大小:

  • 如3.5.1节(第103页)所介绍的,按照由内而外的顺序阅读此类定义有助于更好地理解其真实含义。在第一条语句中,我们定义的名字是ia,显然ia是一个含有3个元素的数组。接着观察右边发现,ia的元素也有自己的维度,所以ia的元素本身又都是含有4个元素的数组。再观察左边知道,真正存储的元素是整数。因此最后可以明确第一条语句的含义:它定义了一个大小为3的数组,该数组的每个元素都是含有4个整数的数组。
  • 使用同样的方式理解arr的定义。首先arr是一个大小为10的数组,它的每个元素都是大小为20的数组,这些数组的元素又都是含有30个整数的数组。实际上,定义数组时对下标运算符的数量并没有限制,因此只要愿意就可以定义这样一个数组:它的元素还是数组,下一级数组的元素还是数组,再下一级数组的元素还是数组,以此类推。
  • 对于二维数组来说,常把第一个维度称作行,第二个维度称作列。

多维数组的下标引用

  • 可以使用下标运算符来访问多维数组的元素,此时数组的每个维度对应一个下标运算符。如果表达式含有的下标运算符数量和数组的维度一样多,该表达式的结果将是给定类型的元素;反之,如果表达式含有的下标运算符数量比数组的维度小,则表达式的结果将是给定索引处的一个内层数组:

  • 在第一个例子中,对于用到的两个数组来说,表达式提供的下标运算符数量都和它们各自的维度相同。在等号左侧,ia[2]得到数组ia的最后一行,此时返回的是表示ia最后一行的那个一维数组而非任何实际元素;对这个一维数组再取下标,得到编号为[3]的元素,也就是这一行的最后一个元素。类似的,等号右侧的运算对象包含3个维度。首先通过索引0得到最外层的数组,它是一个大小为20的(多维)数组;接着获取这20个元素数组的第一个元素,得到一个大小为30的一维数组;最后再取出其中的第一个元素。
  • 在第二个例子中,把row定义成一个含有4个整数的数组的引用,然后将其绑定到ia的第2行。
  • 再举一个例子,程序中经常会用到两层嵌套的for循环来处理多维数组的元素:
  • constexpr size_t rowCnt = 3, colCnt = 4;

  • 外层的for循环遍历ia的所有元素,注意这里的元素是一维数组:内层的for循环则遍历那些一维数组的整数元素。此例中,我们将元素的值设为该元素在整个数组中的序号。

指针和多维数组

  • 当程序使用多维数组的名字时,也会自动将其转换成指向数组首元素的指针。
  • 定义指向多维数蛆的指针时,千万别忘了这个多维数组实际上是数组的数组
  • 因为多维数组实际上是数组的数组,所以由多维数组名转换得来的指针实际上是指向第一个内层数组的指针:

  • 根据3.5.1节 (第 103页)提出的策略,我们首先明确(*p)意味着p 是一个指针。接着观 察右边发现,指针P 所指的是一个维度为4 的数组;再观察左边知道,数组中的元素是整数。因此,p 就是指向含有4个整数的数组的指针。

  • 外层的for循环首先声明一个指针p并令其指向ia的第一个内层数组,然后依次迭代直到ia的全部3行都处理完为止。其中递增运算++p负责将指针p移动到ia的下一行。内层的for循环负责输出内层数组所包含的值。它首先令指针q指向p当前所在行的第一个元素。*p是一个含有4个整数的数组,像往常一样,数组名被自动地转换成指向该数组首元素的指针。内层for循环不断迭代直到我们处理完了当前内层数组的所有元素为止。为了获取内层for循环的终止条件,再一次解引用p得到指向内层数组首元素的指针,给它加上4就得到了终止条件。
  • 当然,使用标准库函数begin和end(参见3.5.3节,第106页)也能实现同样的功能,而且看起来更简洁一些:

  • 在这一版本的程序中,循环终止条件由end函数负责判断。虽然我们也能推断出p的类型是指向含有4个整数的数组的指针,q的类型是指向整数的指针,但是使用auto。关键字我们就不必再烦心这些类型到底是什么了

小结

  • string和vector是两种最重要的标准库类型。string对象是一个可变长的字符序列,vector对象是一组同类型对象的容器。迭代器允许对容器中的对象进行间接访问,对于string对象和vector对象来说,可以通过迭代器访问元素或者在元素间移动。
  • 数组和指向数组元素的指针在一个较低的层次上实现了与标准库类型string和vector类似的功能。一般来说,应该优先选用标准库提供的类型,之后再考虑C++语言内置的低层的替代品数组或指针。

术语表

  • begin是string和vector的成员,返回指向第一个元素的迭代器。也是一个标准库函数,输入一个数组,返回指向该数组首元素的指针。
  • 缓冲区溢出(bufferoverflow)一种严重的程序故障,主要的原因是试图通过一个越界的索引访问容器内容,容器类型包括string、vector和数组等。
  • C风格字符串(C-stylestring)以空字符结束的字符数组。字符串字面值是C风格字符串,C风格字符串容易出错。
  • 类模板用于创建具体类类型的模板。要想使用类模板,必须提供关于类型的辅助信息。例如,要定义一个vector对象需要指定元素的类型:vector<int>包含int类型的元素。
  • 编译器扩展(compilerextension)某个特定的编译器为C++语言额外增加的特性。基于编译器扩展编写的程序不易移植到其他编译器上。
  • 容器(container)是一种类型,其对象容纳了一组给定类型的对象。vector是一种容器类型。
  • 拷贝初始化(copyinitialization)使用赋值号(=)的初始化形式。新创建的对象是初始值的一个副本
  • difference_type由string和vector定义的一种带符号整数类型,表示两个迭代器之间的距离。
  • 直接初始化(directinitialization)不使用赋值号(=)的初始化形式。
  • empty是string和vector的成员,返回一个布尔值。当对象的大小为0时返回真,否则返回假.
  • end是string和vector的成员,返回一个尾后迭代器。也是一个标准库函数,输入一个数组,返回指向该数组尾元素的下-位置的指针。
  • getline在string头文件中定义的一个函数,以一个istream对象利--个string对象为输入参数。该函数首先读取输入流的内容直到遇到换行符停止,然后将读入的数据存入string对象,最后返回istream对象。其中换行符读入但是不保留。
  • 索引(index)是下标运算符使用的值。表示要在string对象、vector对象或者数组中访问的一个位置。
  • 实例化(instantiation)编译器生成一个指定的模板类或函数的过程。
  • 迭代器(iterator)是一种类型,用于访问容器中的元素或者在元素之间移动。
  • 迭代器运算(iteratorarithmetic)是string或vector的迭代器的运算:迭代器与整数相加或相减得到一个新的迭代器,与原来的迭代器相比,新迭代器向前或向后移动了若干个位置。两个迭代器相减得到它们之间的距离,此时它们必须指向同一个容器的元素或该容器尾元素的下一位置。
  • 以空字符结束的字符串(null-terminatedstring)是一个字符串,它的最后一个字符后而还跟着一个空字符("\0")。
  • 尾后迭代器(off-the-enditerator)end函数返I可的迭代器,指向一个并不存在的元素,该元素位于容器尾元素的下一位置。
  • 指针运算(pointerarithmetic)是指针类型支持的算术运算。指向数组的指针所支持的运算种类与迭代器近算一样。
  • prtdiff_t是cstddef头文件中定义的一种与机器实现有关的带符号整数类型,它的空间足够大,能够表示数组中任意两个指针之间的距离。
  • pushback是vector的成员,向vector对象的木尾添加元素。
  • 范围for语句(rangefor)-种控制语句,可以在值的一个特定集合内迭代。
  • size是string和vector的成员,分别返回字符的数量或元素的数量。返回值的类型是size_type。size_t是cstddef头文件中定义的一种与机器实现有关的无符号整数类型,它的空间足够大,能够表示任意数组的大小。
  • size_type是string和vector定义的类型的名字,能存放下任意string对象或vector对象的大小。在标准中,size_type被定义为无符号类型。string是一种标准库类型,表示字符的序列。
  • using声明(usingdeclaration)令命名空间中的某个名字可被程序直接使用。using命名空间::名字;L述语句的作用是令程序可以直接使用名字,而无须写它的前缀部分命名空间
  • 值初始化(valueinitialization)是一种初始化过程。内置类型初始化为0,类类型由类的默认构造函数初始化。只有当类包含默认构造函数时,该类的对象才会被值初始化。对于容器的初始化来说,如果只说明了容器的大小而没有指定初始值的话,就会执行值初始化。此时编译器会生成一个值,而容器的元素被初始化为该值。
  • vector是-种标准库类型,容纳某指定类型的一组元素。
  • ++运算符(++operator)是迭代器和指针定义的递增运算符。执行“加1”操作使得迭代器指向下一个元素
  • []运算符([]operator)下标运算符Oobj[j]得到容器对象。bj中位置j的那个元素。索引从0开始,第一个元素的索引是0,
  • 尾元素的索引是。bj.size()-1.下'标运算符的返回值是一个对象。如果p是指针、n是整数,则p[n]与*(p+n)等价。->运算符(->operator)箭头运算符,该运算符综合了解引用操作和点操作.a->b等价于(*a).b。
  • <<运算符(《operator)标准库类型string定义的输出运算符,负责输出string对象中的字符。
  • >>运算符(>>operator)标准库类型string定义的输入运算符,负责读入一组字符,遇到空白停止,读入的内容赋给运算符右侧的运算对象,该运算对象应该是一个string对象。
  • !运算符^operator)逻辑非运算符,将它的运算对象的布尔值取反。如果运算对象是假,则结果为真,如果运算对象是真:,则结果为假。
  • &&运算符(&&operator)逻辑与运算符,如果两个运算对象都是真,结果为真。只有当左侧运算对象为真时才会检查右侧运算对象。
  • II运算符(||operator)逻辑或运算符,任何一个运算对象是真,结果就为真。只有里左侧运算对象为假时才会检查右侧运算对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/446661.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++primer 第 4 章 表达式 4.1基础 4 . 2 算术运算符 4 .3 逻辑和关系运算符 4 . 4 赋值运算符 4 .5 递增和递减运算符 4.6成员访问运算符

表达式由一个或多个运算对象(operand)组成&#xff0c;对表达式求值将得到一个结果(result)字面值和变量是最简单的表达式(expression),其结果就是字面值和变量的值。把一个运算符(operator)和一个或多个运算对象组合起来可以生成较复杂的表达式 4.1基础 有几个基础概念对表达…

codeforces 266B-C语言解题报告

266B题目网址 题目解析 输入n,t,排队情况s,输出第t次循环后,排队情况 举例: 输入: 5 1 BGGBG 输出: GBGGB 2.输入的n代表排队的人数,t代表整个循环t次之后再输出结果 3.注意点: 使用while()大循环去控制t次的循环,使用for()内层循环去遍历整个字符串 如果if(s[j]‘B’&…

英语口语-文章朗读Week9 Wednesday

英语文章 Birds of the same species flock together&#xff0c; People tend to look for someone like themselves to be friends. But having the same interests is not the only standard when we are seeking friends. In most cases, especially for adults, people l…

C++primer 第 4 章 表达式 4.7条件运算符 4.8位运算符 4.9 sizeof运算符 4.10逗号运算符 4.11类型转换 4 . 1 2 运算符优先级表

4.7条件运算符 条件运算符(?&#xff1a;)允许我们把简单的if else逻辑嵌入到单个表达式当中&#xff0c;条件运算符按照如下形式使用&#xff1a;cond ? expr1 : expr2;其中cond是判断条件的表达式&#xff0c;而expr1和expr2是两个类型相同或可能转换为某个公共类型的表达…

Git 之 git tag标签使用

目录一、简介二、本地tag操作1、创建tag标签&#xff08;1&#xff09;创建轻量标签&#xff08;2&#xff09;创建附注标签2、查看tag标签&#xff08;1&#xff09;查看标签列表&#xff08;2&#xff09;查看标签提交信息&#xff08;3&#xff09;在提交历史中查看标签3、删…

C++primer 第 5 章语句 5.2语句作用域 5.3条件语句 5 . 4 迭代语句 5.5跳转语句 5.6 try语句块和异常处理

5 . 1 简单语句 C语言中的大多数语句都以分号结束&#xff0c;一个表达式&#xff0c;比如ival 5 , 末尾加上分号就变成了表达式语句(expression statement)。表达式语句的作用是执行表达式并丢弃掉求值结果&#xff1a;ival 5&#xff1b; // 一条没什么实际用处的表达式语…

英语口语-文章朗读Week9Thursday

英语文章 Everyone has his or her own dreams. Some people wants to be millionaires so they can give many generous donations later; some people want to be scientists so they can bring many conveniences to the world; some people only want to be bus-drivers s…

操作系统 内存管理相关知识

cpu执行程序的基本过程 译码器 输入为n管脚&#xff0c;输出为2^n根管脚&#xff0c;编号为从0到2^(n-1)&#xff0c;用少的输入端控制更多的输出端最常用的是三八译码器AD(Address bus)地址总线: 选中一行数据每一行 8bit 组成8吧B cpu输入端32根线&#xff0c;输出端就可以控…

Chrome浏览器必装插件!尤其程序猿!

Chrome 浏览器有一个好处&#xff0c;就是插件极其丰富&#xff0c;只有你想不到的&#xff0c;没有你找不到的&#xff0c;这恐怕是 Chrome 浏览器被众多爱好者钟爱的原因吧。 言归正传&#xff0c;今天来给大家推荐 10 款我自己珍藏的 Chrome 浏览器插件。 1、crxMouse Ch…

英语口语-文章朗读Week10 Monday

英语文章 Here are some valuable suggestions which may assist you in landing good job First, make your resume clear and associate it with the position you are applying for. Try to add details like your temporary jobs at college or your former jobs Second, …

英语口语-文章朗读Week10 Wednesday

英语文章 Everyone needs sleep for survival, but how much? It is said that eight hours of sleep is fundamental to a healthy person. But today, many people are sacrificing their sleep time。 Modern people have so many alternatives: cell phones, PCs, TVs, g…

嵌入式Linux多任务编程 进程 管道 命名管道

进程 进程是一个可并发执行的具有独立功能的程序关于某个数据集合的一次执行过程&#xff0c;也是操作系统执行资源分配和保护的基本单位。程序的一次执行就是一个进程一个程序可以派生多个进程多个不同程序运行的时候&#xff0c;也会有多个相对应的进程与其相互对应进程是动…

英语口语-文章朗读Week10 Thursday

英语文章 There are many customs and traditions in Chinese civilization. Here, we will talk about the development of the way people greet each other: In ancient times, people had to kneel to those who were superior to them. This custom remained until the …

Linux进程之间通信 信号

2) SIGINT 程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出&#xff0c;用于通知前台进程组终止进程。 3) SIGQUIT 和SIGINT类似, 但由QUIT字符(通常是Ctrl-\)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号。 15)…

Linux进程之间通信 消息队列

使用命令 ipcs -q 查看对应的消息队列代码 文件接收者 #include <sys/types.h> #include <stdio.h> #include <unistd.h> #include <string> #include <signal.h> #include <wait.h> #include <sys/msg.h> #include <cstring&g…

c++面向对象高级编程 学习二 带指针的类

带指针的类&#xff0c;必须要自己写拷贝构造和赋值构造 拷贝构造&#xff1a;参数和类的类型一样的构造函数 赋值构造&#xff1a;重写操作符&#xff0c;且其参数和类的类型一样 class String { public: String(const char* cstr 0); String(const String& str); Strin…

英语口语 week11 Tuesday

英语文章 It was a cold and gloomy winter afternoon, people with their chilled hands tucked into their pockets or hidden in their sleeves. Fred was in a depressed mood, just like the weather,for he failed to get any award in the debate competition When he …

进程之间通信 共享内存

命令 ipcs 命令查看共享内存、消息队列、管道等相关信息ipcs -m 查看共享内存的信息代码 创建共享内存共享内存 关联 进程分离共享内存删除共享内存 #include <sys/shm.h> #include <iostream>#define BUF_SIZE 1024int main() {int share_id 0;//创建共享内存i…

c++面向对象高级编程 学习三 堆、栈和内存泄漏

栈&#xff0c;是存在于某作用域的一块内存空间。在函数体内声明的任何变量&#xff0c;其所使用的内存空间均来自于栈。 堆&#xff0c;是指由操作系统提供的一块global内存空间&#xff0c;程序可动态分配获得若干内存空间块。 new操作符生成的对象所占用的内存空间即是从堆中…