珠海做公司网站,wordpress网站定制,中国建工网官网,石家庄网站制作C Primer 第3章 字符串、向量和数组 3.1 命名空间的using声明一、每个名字都需要独立的using声明二、头文件不应包含using声明三、一点注意事项 3.2 标准库类型string3.2.1 定义和初始化string对象一、直接初始化和拷贝初始化 3.2.2 string对象上的操作一、读写string对象二、读… C Primer 第3章 字符串、向量和数组 3.1 命名空间的using声明一、每个名字都需要独立的using声明二、头文件不应包含using声明三、一点注意事项 3.2 标准库类型string3.2.1 定义和初始化string对象一、直接初始化和拷贝初始化 3.2.2 string对象上的操作一、读写string对象二、读取未知数量的string对象三、使用getline读取一整行四、string的empty和size操作五、string::size_type类型六、比较string对象七、为string对象赋值八、两个string对象相加九、字面值和string对象相加十、练习 3.2.3 处理string对象中的字符一、处理每个字符使用基于范围的for语句二、使用范围for语句改变字符串中的字符三、只处理一部分字符四、使用下标执行迭代五、使用下标执行随机访问 3.3 标准库vector3.3.1 定义和初始化vector对象一、列表初始化vector对象二、创建指定数量的元素三、值初始化四、列表初始值还是元素数量 3.3.2 向vector对象中添加元素一、向vector对象添加元素蕴含的编程假定 3.3.3 其他vector操作一、计算vector内对象的索引二、不能用下标形式添加元素 3.4 迭代器介绍3.4.1 使用迭代器一、迭代器运算符二、将迭代器从一个元素移动到另外一个元素三、迭代器类型四、begin和end运算符五、结合解引用和成员访问操作六、某些对vector对象的操作会使迭代器失效七、练习 3.4.2 迭代器运算一、迭代器的算术运算二、使用迭代器运算 3.5 数组3.5.1 定义和初始化内置数组一、显式初始化数组元素二、字符数组的特殊性三、不允许拷贝和赋值四、理解复杂的数组声明 3.5.2 访问数组元素一、检查下标的值 3.5.3 指针和数组一、指针也是迭代器二、标准库函数begin和end三、指针运算四、解引用和指针运算的交互五、下标和指针 3.5.4 C风格字符串一、C标准库String函数二、比较字符串三、目标字符串的大小由调用者指定 3.5.5 与旧代码的接口一、混用string对象和C风格字符串二、使用数组初始化vector对象 3.6 多维数组一、多维数组的初始化二、多维数组的下标引用三、使用范围for语句处理多维数组四、指针和多维数组五、类型别名简化多维数组的指针六、练习 小结 3.1 命名空间的using声明
using naspace::name;
using std::cin;
using std::cout;
using std::endl;一、每个名字都需要独立的using声明
每个using声明引入命名空间中的一个成员。
二、头文件不应包含using声明
位于头文件的代码一般来说不应该使用using声明。这是因为头文件的内容会拷贝到所有引用它的文件中去如果头文件里有某个using声明那么每个使用了该头文件的文件都会有这个声明。对于某些程序来说由于不经意间包含了一些名字反而可能产生始料未及的名字冲突。
三、一点注意事项
3.2 标准库类型string
标准库类型string表示可变长的字符序列使用string类型必须首先包含string头文件string定义在命名空间std中。
# include string
using std::string;3.2.1 定义和初始化string对象 一、直接初始化和拷贝初始化
如果使用等号初始化一个变量实际上执行的是拷贝初始化编译器把等号右侧的初始值拷贝到新创建的对象中去。如果不使用等号则执行的是直接初始化。 拷贝初始化创建临时对象复制构造函数。直接初始化效率更高
string s5 hiya; // 拷贝初始化
string s6(hiya); // 直接初始化
string s7(10, c); // 直接初始化
string s8 string(10, c); // 拷贝初始化需要显式地创建一个临时对象用于拷贝3.2.2 string对象上的操作 一、读写string对象
#include iostream
#include stringusing std::cin;
using std::cout;
using std::endl;
using std::string;int main()
{string s1, s2;cin s1 s2;; // 在执行读取操作时string对象会自动忽略开头的空白空格符、换行符、制表符并从第一个真正的字符开始读起直到遇见下一处空白为止cout s1 s2 endl;return 0;
}二、读取未知数量的string对象
#include iostream
#include stringusing std::cin;
using std::cout;
using std::endl;
using std::string;int main()
{string word;while (cin word) {cout word endl;}return 0;
}三、使用getline读取一整行
getline函数的参数是一个输入流和一个string对象函数从给定的输入流中读入内容直到遇到换行符为止换行符也被读进来了然后把所读的内容存入到那个string对象中去注意不存换行符。getline只要一遇到换行符就结束读取操作并返回结果哪怕输入的一开始就是换行符也是如此。如果输入真的一开始就是换行符那么所得到的结果是个空string。getling也会返回它的流参数。
#include iostream
#include stringusing std::cin;
using std::cout;
using std::endl;
using std::string;int main()
{string line;// getline不忽略开头和结尾的空白while (getline(cin, line)) {cout line endl;}return 0;
}四、string的empty和size操作
empty函数根据string对象是否为空返回一个对应的布尔值。
string line;
while (getline(cin, line)) {if (!line.empty()) {cout line endl;}
}size函数返回string对象的长度即string对象中字符的个数。
string line;
while (getline(cin, line)) {if (line.size() 80) {cout line endl;}
}五、string::size_type类型
size函数返回的是一个string::size_type类型的值。 string类及其他大多数标准库类型都定义了几种配套的类型。这些配套类型体现了标准库类型与机器无关的特性类型size_type即使其中的一种。它是一个无符号类型的值而且能足够存放下任何string对象的大小。 注意由于size函数返回的是一个无符号整数类型因此切记不要在表达式中混用带符号数和无符号数。
六、比较string对象
相等性运算符和!分别检验两个string对象相等或不相等string对象相等意味着他们的长度相同而且所包含的字符也全都相同。关系运算符、、、分别检验一个string对象是否小于、小于等于、大于、大于等于另外一个string对象。
七、为string对象赋值
string st1(10, c), st2;
st1 st2; // 赋值用st2的副本替换st1的内容八、两个string对象相加
string s1 hello, , s2 world\n;
string s3 s1 s2; // s3的内容是hello, world\n
s1 s2; // 等价于s1 s1 s2九、字面值和string对象相加
标准库允许把字符字面值和字符串字面值转换成string对象。
string s1 hello, s2 world;
// 当把string对象和字符字面值及字符串字面值混在一条语句中使用时必须确保每个加法运算符的两侧的运算对象至少有一个是string
string s3 s1 , s2 \n; // 正确
string s4 s1 , ; // 正确
string s5 hello , ; // 错误两个运算对象都不是string双引号的字符串实际是地址两个地址相加无法转换为string对象
string s6 s1 , world; // 正确
string s7 hello , s2; // 错误 cout *Hello world endl; // H十、练习
// 当cin函数输入错误的时候cin里面有个函数可以自动检测到输入错误若想继续输入便要清除掉这个错误
cin.clear();
// 将输入的错误字符清理掉
cin.sync();3.2.3 处理string对象中的字符 C标准库中除了定义C语言特有的功能外也兼容了C语言的标准库。C语言的头文件形如name.hC则将这些文件命名为cname。特别的在cname的头文件中定义的名字从属于命名空间std。
一、处理每个字符使用基于范围的for语句
范围for语句遍历给定序列中的每个元素并对序列中的每个值执行某种操作。
expression部分是一个对象用于表示一个序列
declaration部分负责定义一个变量该变量将被用于访问序列中的基础元素
每次迭代declaration部分的变量会被初始化为expression部分的下一个元素值
for (declaration : expression)statementstring str(some string);
for (auto c : str) {cout c endl;
}string s(Hello World!!!);
decltype(s.size()) punct_cnt 0;
for (auto c : s) {if (ispunct(c)) {punct_cnt;}
}
cout punct_cnt punctuation characters in s endl;二、使用范围for语句改变字符串中的字符
string s(Hello World!!!);
for (auto c : s) {c toupper(c);
}
cout s endl; // HELLO WORLD!!!三、只处理一部分字符
下标运算符[ ]接收的输入参数是string::size_type类型的值这个参数表示要访问的字符的位置返回值是该位置上字符的引用。
if (!s.empty())cout s[0] endl;string s(some string);
if (!s.empty())s[0] toupper(s[0]);四、使用下标执行迭代
逻辑与运算符如果参与运算的两个运算对象都为真则逻辑与结果为真否则结果为假。C语言规定只有当左侧运算对象为真时才会检查右侧运算对象的情况。
五、使用下标执行随机访问
#include iostream
#include stringusing std::cin;
using std::cout;
using std::endl;
using std::string;int main()
{const string hexdigits 0123456789ABCDEF;cout Enter a series of numbers between 0 and 15 separated by spaces. Hit ENTER when finished: endl;string result;string::size_type n;while (cin n) {if (n hexdigits.size()) {result hexdigits[n];}}cout Your hex number is: result endl;return 0;
}3.3 标准库vector
标准库类型vector表示对象的集合其中所有对象的类型都相同。
#include vector
using std::vectorC语言既有类模板也有函数模板其中vector是一个类模板。模板本身不是类或函数可以将模板看作为编译器生成类或函数编写的一份说明。编译器根据模板创建类或函数的过程称为实例化当使用模板时需要指出编译器应把类或函数实例化成何种类型。
vectorint ivec;
vectorSales_item Sales_vec;
vectorvectorstring file;3.3.1 定义和初始化vector对象 vectorstring svec; // 默认初始化svec不含任何元素vectorint ivec; // 初始化状态为空
vectorint ivec2(ivec); // 把ivec的元素拷贝给ivec2
vectorint ivec3 ivec; // 把ivec的元素拷贝给ivec3
vectorstring svec(ivec2); // 错误一、列表初始化vector对象
vectorstring articles {a, an, the}; // 列表初始化
vectorstring v1{a, an, the}; // 列表初始化
vectorstring v2(a, an, the); // 错误二、创建指定数量的元素
vectorint ivec(10, -1); // 10个int类型的元素每个都被初始化为-1
vectorstring svec(10, hi!); // 10个string类型的元素每个都被初始化为hi!三、值初始化
vectorint ivec(10); // 10个int类型的元素每个都被初始化为0
vectorstring svec(10); // 10个string类型的元素每个都是空string对象四、列表初始值还是元素数量
vectorint v1(10); // v1有10个元素每个值都是0
vectorint v2{10}; // v2有1个元素该元素的值10vectorint v3(10, 1); // v3有10个元素每个值都是1
vectorint v4{10, 1}; // v4有2个元素值分别是10和1
// 如果用的是圆括号可以说提供的值是用来构造vector对象的
// 如果用的是花括号可以表述成我们想列表初始化该vector对象初始化过程会尽可能地把花括号内的值当成是元素初始值的列表来处理只有在无法执行列表初始化时才会考虑其他初始化方式
// 如果初始化时使用了花括号的形式但是提供的值又不能用来列表初始化就要考虑用这样的值来构造vector对象了vectorstring v5{hi}; // 列表初始化v5有一个元素
vectorstring v6(hi); // 错误不能使用字符串字面值构建vector对象
vectorstring v7{10}; // v7有10个默认初始化的元素
vectorstring v8{10, hi}; // v8有10个值为“hi”的元素3.3.2 向vector对象中添加元素
push_back负责把一个值当成vector对象的尾元素“压到”vector对象的“尾端”。
vectorint v2;
for(int i 0; i ! 100; i)v2.push_back(i); // 循环结束后v2有100个元素值从0到99string word;
vectorstring text;
while(cin word) text.push_back(word);一、向vector对象添加元素蕴含的编程假定
如果循环体内部包含有向vector对象添加元素的语句则不能使用范围for循环。范围for语句体内不应该改变其所遍历序列的大小
3.3.3 其他vector操作 vectorint v{1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto i : v)i * i;
for (auto i: v)cout i ;
cout endl;empty检查vector对象是否包含元素然后返回一个布尔值。 size返回vector对象中元素的个数返回值的类型是vector定义的size_type类型。
vectorint::size_type // 正确
vector::size_type // 错误一、计算vector内对象的索引
#include iostream
#include string
#include vectorusing std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;int main()
{vectorunsigned scores(11, 0);unsigned grade;while (cin grade) {if (grade 100)scores[grade / 10];}for (auto s : scores)cout s ;return 0;
}二、不能用下标形式添加元素
vector对象以及string对象的下标运算符可用于访问已存在的元素而不能用于添加元素。只能对确知已存在的元素执行下标操作。
vectorint ivec;
for (decltype(ivec.size()) ix 0; ix ! 10; ix)ivec[ix] ix; // 错误ivec是一个空vector根本不包含任何元素当然不能通过下标去访问任何元素vectorint ivec;
cout ivec[0]; // 错误3.4 迭代器介绍
迭代器也提供了对对象的间接访问。使用迭代器可以访问某个元素迭代器也能从一个元素移动到另外一个元素。迭代器有有效和无效之分。有效的迭代器或者指向某个元素或者指向容器中尾元素的下一位置其他所有情况都属于无效。
3.4.1 使用迭代器
auto b v.begin(), e v.end();
// b和e类型相同b表示v的第一个元素e表示v尾元素的下一位置尾后迭代器
// 如果容器为空则begin和end返回的是同一个迭代器都是尾后迭代器一、迭代器运算符
执行解引用的迭代器必须合法并确实指示着某个元素。
string s(sone string);
if (s.begin() ! s.end()) {auto it s.begin();*it toupper(*it);
}二、将迭代器从一个元素移动到另外一个元素
迭代器的递增是将迭代器“向前移动一个位置”。
for (auto it s.begin(); it ! s.end() !isspace(*it); it)*it toupper(*it);三、迭代器类型
迭代器类型iterator可读可写和const_iterator可读不可写
vectorint::iterator it;
string::iterator it2;vectorint::const_iterator it3;
string::const_iterator it4;四、begin和end运算符
begin和end返回的具体类型由对象是否是常量决定如果对象时常量begin和end返回const_iterator如果对象不是常量返回iterator。
vectorint v;
const vectorint cv;
auto it1 v.begin(); // it1的类型是vectorint::iterator
auto it2 cv.begin(); // it2的类型是vectorint::const_iterator
auto it3 v.cbegin(); // it3的类型是vectorint::const_iterator五、结合解引用和成员访问操作
// 对于一个由字符串组成的vector对象令it是该vector对象的迭代器
(*it).empty(); // 解引用it然后调用结果对象的empty成员
*it.empty(); // 错误试图访问it的名为empty的成员但it是个迭代器没有empty成员
it-empty(); // 箭头运算符把解引用和成员访问两个操作结合在一起for (auto it text.cbegin(); it ! text.cend() !it-empty(); it)cout *it endl;六、某些对vector对象的操作会使迭代器失效
限制 1不能在for循环中向vector对象添加元素 2任何一种可能改变vector对象容量的操作比如push_back都会使vector对象的迭代器失效
// 检查非空
s.begin() ! s.end()
// 范围for语句等价为
for (auto beg v.begin(), end v.end(); beg ! end; beg) {auto r *beg;
}七、练习
// 随机数生成
srand((unsigned)time(NULL)); // 生成随机数种子
int n rand() % 1000; // 1000以内的随机数
3.4.2 迭代器运算 一、迭代器的算术运算
可以令迭代器和一个整数值相加或相减其返回值是向前或向后移动了若干个位置的迭代器。 对于string或vector的迭代器来说除了判断是否相等还能使用关系运算符、、、对其进行比较。参与比较的两个迭代器必须合法而且指向的是同一个容器的元素或者尾元素的下一位置。 只要两个迭代器指向的是同一个容器中的元素或者尾元素的下一位置就能将其相减所得的结果是两个迭代器的距离其类型是名为difference_type的带符号整型数。 不支持两迭代器相加。
二、使用迭代器运算
// text必须是有序的
auto beg text.begin(), end text.end();
auto mid text.begin() (end - beg) / 2;
while (mid ! end *mid ! sought) {if (sought *mid)end mid;else beg mid 1;mid beg (end - beg) / 2;
}3.5 数组
数组与vector 相同点数组也是存放类型相同的对象的容器这些对象本身没有名字需要通过其所在位置访问 不同点数组的大小确定不变不能随意向数组中增加元素。数组的维度在定义时已经确定如果我们想更改数组的长度只能创建一个更大的新数组然后把原数组的所有元素赋值到新数组中区。无法像vector那样使用size函数直接获取数组的维度。如果是字符数组可以调用strlen函数得到字符串的长度如果是其他数组只能使用sizeof(array)/sizeof(array[0]) 的方式计算数组的维度。
3.5.1 定义和初始化内置数组
数组是一种复合类型。数组的声明形如a[d]其中a是数组的名字d是数组的维度。维度说明了数组中元素的个数因此必须大于0。数组中元素的个数也属于数组类型的一部分编译的时候维度应该是已知的维度必须是一个常量表达式。默认情况下数组的元素被默认初始化。 定义数组的时候必须制定指定数组的类型不允许用auto关键字由初始化值的列表推断类型。数组的元素应为对象不存在引用的数组。
一、显式初始化数组元素
const unsigned sz 3;
int ia1[sz] {0, 1, 2}; // 含有3个元素的数组元素值分别是0, 1, 2
int a2[] {0, 1, 2}; // 维度是3的数组
int a3[5] {0, 1, 2}; // 等价于a3[] {0, 1, 2, 0, 0}
int a5[2] {0, 1, 2}; // 错误初始值过多
unsigned buf_size 1024;
int ia[buf_size]; // 错误buf_size不是常量
int ia[4 * 7 -14]; // 正确二、字符数组的特殊性
char a1[] {C, , }; // 没有空字符维度是3
char a2[] {C, , , \0}; // 含有显式的空字符维度是4
char a3[] C; // 自动添加表示字符串结束的空字符
const char a4[6] Daniel; // 错误没有空间存放空字符三、不允许拷贝和赋值
int a[] {0, 1, 2};
int a2[] a; // 错误不允许使用一个数组初始化另一个数组
a2 a; // 错误不能把一个数组直接赋值给另一个数组四、理解复杂的数组声明
默认情况下类型修饰符从右向左依次绑定。
int *ptrs[10]; // ptrs是含有10个整型指针的数组
int refs[10] ...; // 错误不存在引用的数组
int (*Parray)[10] arr; // Parray指向一个含有10个整数的数组
int (arrRef)[10] arr; // arrRef引用一个含有10个整数的数组
int *(arry)[10] ptrs; // array是数组引用该数组含有10个指针3.5.2 访问数组元素
在使用数组下标时通常将其定义为size_t类型。size_t是一种机器相关的无符号类型它被设计得足够大以便能表示内存中任意对象的大小在cstddef头文件中
unsigned scores[11] {};
unsigned grade;
while (cin grade) {if (grade 100)scores[grade/10];
}for (auto i : scores)cout i ;一、检查下标的值
3.5.3 指针和数组
string nums {one, two, three};
string *p nums[0]; // p指向nums的第一个元素
// 在用到数组名字的地方编译器会自动将其替换为一个指向数组首元素的指针
string *p2 nums; // 等价于p2 nums[0]// 使用数组作为一个auto变量的初始值时推断得到的类型是指针而非数组而decltype不会发生转换
int ia[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
auto ia2(ia); // ia2是一个整型指针指向ia的第一个元素
decltype(ia) ia3; // ia3是一个数组一、指针也是迭代器
int arr[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int *p arr; // p指向arr的第一个元素
p; // p指向arr[1]
int *e arr[10]; // 指向arr尾元素的下一位置的指针不能执行解引用和递增
for (int *b arr; b ! e; b)cout *b endl;二、标准库函数begin和end
int ia[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int *beg begin(ia); // begin函数返回指向ia首元素的指针
int *last end(ia); // end函数返回指向ia尾元素下一位置的指针
// 这两个函数定义在iterator头文件中命名空间std中三、指针运算
constexpr size_t sz 5;
int arr[sz] {1, 2, 3, 4, 5};
int *ip arr; // 等价于int *ip arr[0]
int *ip2 ip 4; // ip2指向arr[4]
// 给指针加上一个整数得到的新指针仍需指向同一数组的其他元素或者指向同一数组尾元素的下一位置
int *p arr sz; // p指向arr尾元素的下一位置不要解引用
int *p2 arr 10; // 错误arr只有5个元素p2的值未定义两个指针相减的结果是它们之间的距离参与运算的两个指针必须指向同一数组当中的元素两个指针相减的结果的类型是一种名为ptrdiff_t的标准库类型定义在cstddef头文件中。 只要两个指针指向同一个数组的元素或者指向该数组的尾元素的下一位置就能利用关系运算符对其进行比较。如果两个指针分别指向不相关的对象则不能比较它们。 如果p是空指针允许给p加上或减去一个值为0的整型常量表达式。两个空指针也允许彼此相减结果为0。
四、解引用和指针运算的交互
int ia[] {0, 2, 4, 6, 8};
int last *(ia 4); // 把last初始化为ia[4]
last *ia 4; // ia[0] 4五、下标和指针
对数组执行下标运算其实是对指向数组元素的指针执行下标运算
int ia[] {0, 2, 4, 6, 8};
int i ia[2]; // ia转换成指向数组首元素的指针ia[2]得到(ia2)所指的元素
int *p ia;
i *(p 2); // 等价于ia[2]int *p ia[2];
int j p[1]; // p[1]等价于*(p1)即ia[3]
int k p[-2]; // ia[0]虽然标准库类型string和vector也能执行下标运算但是数组与它们相比还是有所不同。标准库类型限定使用的下标必须是无符号类型而内置的下标运算无此要求。
3.5.4 C风格字符串
C风格字符串不是一种类型而是为了表达和使用字符串而形成的一种约定俗成的写法。按此习惯书写的字符串放在字符数组中并以空字符结束。
一、C标准库String函数
头文件cstring 传入此类函数的指针必须指向以空字符作为结束的数组
char ca[] {C, , };
cout strlen(ca) endl; // 严重错误ca没有以空字符结束二、比较字符串
const char ca1[] A string example;
const char ca2[] A different string;
if (ca1 ca2) // 未定义的试图比较两个无关地址
if (strcmp(ca1, ca2) 0) // 和两个string对象的比较s1s2效果一样三、目标字符串的大小由调用者指定
strcpy(largeStr, ca1); // 把cal拷贝给largeStr
strcat(largeStr, ); // 在largeStr的末尾加上一个空格
strcat(largeStr, ca2); // 把ca2连接到largeStr后面3.5.5 与旧代码的接口
一、混用string对象和C风格字符串
1、允许使用字符串字面值来初始化string对象 2、允许使用以空字符结束的字符数组来初始化string对象或为string对象赋值 3、在string对象的加法运算中允许使用以空字符结束的字符数组作为其中一个运算对象不能两个运算对象都是在string对象的复合赋值运算中允许使用以空字符结束的字符数组作为右侧的运算对象
string s(Hello World);
char *str s; // 错误不能用string对象初始化char*
const char *str s.c_str();
// c_str()函数的返回值是一个C风格的字符串函数的返回结果是一个指针该指针指向一个空字符结束的字符数组而这个数组所存的数据恰好与那个string对象的一样
// str指向s的内存单元并未将s的内容进行拷贝二、使用数组初始化vector对象
int int_arr[] {0, 1, 2, 3, 4, 5};
vectorint ivec(begin(int_arr), end(int_arr)); // ivec有6个元素分别是int_arr中对应元素的副本
vectorint subVec(int_arr1, int_arr4); // 拷贝3个元素int_arr[1]、int_arr[2]、int_arr[3]3.6 多维数组
严格来说C语言中没有多维数组通常所说的多维数组其实是数组的数组。
int ia[3][4]; // 大小为3的数组每个元素是含有4个整数的数组
int arr[10][20][30] {0}; // 大小为10的数组它的每个元素都是大小为20的数组这些数组的元素是含有30个整数的数组一、多维数组的初始化
int ia[3][4] {{0, 1, 2, 3},{4, 5, 6, 7},{8, 9, 10, 11}
};
int ia[3][4] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
int ia[3][4] {{0}, {4}, {8}}; // 显式地初始化每行的首元素二、多维数组的下标引用
如果表达式含有的下标运算符数量和数组的维度一样多该表达式的结果将是给定类型的元素反之如果表达式含有的下标运算符数量比数组的维度小则表达式的结果将是给定索引处的一个内层数组。
ia[2][3] arr[0][0][0];
int (row)[4] ia[1]; // 把row绑定到ia的第二个4元素数组上constexpr size_t rowCnt 3, colCnt 4;
int ia[rowCnt][colCnt];
for (size_t i 0; i ! rowCnt; i) {for (size_t j 0; j ! colCnt; j) {ia[i][j] i * colCnt j;}
}三、使用范围for语句处理多维数组
size_t cnt 0;
for (auto row : ia) {for (auto col : row) {col cnt;cnt;}
}// 多维数组使用范围for循环时只能使用引用
for (auto row : ia)for (auto col : row)
// 错误第一个循环遍历ia的所有元素这些元素实际上是大小为4的数组因为row不是引用类型所以编译器初始化row时会自动将这些数组形式的元素转换成指向数组内首元素的指针这样得到的row的类型就是int*显然不合法四、指针和多维数组
// 因为多维数组实际上是数组的数组所以由多维数组名转换得来的指针实际上是指向第一个内层数组的指针
int ia[3][4];
int (*p)[4] ia; // p指向含有4个整数的数组
p ia[2]; // p指向ia的尾元素for (auto p ia; p ! ia 3; p) {for (auto q *p; q ! *p 4; q) { // *p是一个含有4个整数的数组cout *q ;}
}for (auto p begin(ia); p ! end(ia); p) {for (auto q begin(*p); q ! end(*p); q) {cout *q ;}
}五、类型别名简化多维数组的指针
using int_array int[4];
tydefef int int_array[4];
for (int_array *p ia; p ! ia 3; p) {for (int *q *p; q ! *p 4; q) {cout *q ;}
}六、练习
#include iostream
#include iteratorusing std::cin;
using std::cout;
using std::endl;
using std::begin;
using std::end;int main()
{int ia[3][4] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};for (int (p)[4] : ia) {for (int q : p) {cout q ;}cout endl;}for (int i 0; i 3; i) {for (int j 0; j 4; j) {cout ia[i][j] ;}cout endl;}for (int (*p)[4] ia; p ! ia 3; p) {for (int *q *p; q ! *p 4; q) {cout *q ;}cout endl;}return 0;
}小结
string对象和vector是两种最重要的标准库类型。string对象是一个可变长的字符序列vector对象是一组同类型对象的容器。 迭代器允许对容器中的对象进行间接访问对于string对象和vector对象来说可以通过迭代器访问元素或者在元素间移动。 数组和指向数组元素的指针在一个较低的层次上实现了与标准库类型string和vector类似的功能。一般来说应该优先选用标准库提供的类型之后再考虑C语言内置的低层的替代品数组或指针