What & How & Why

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录前一修订版
后一修订版
前一修订版
cs:programming:cpp:courses:cpp_basic_deep:chpt_3 [2024/04/17 09:55] – [指向数组开头和结尾的指针] codingharecs:programming:cpp:courses:cpp_basic_deep:chpt_3 [2024/04/18 04:55] (当前版本) – [string 的使用方法] codinghare
行 213: 行 213:
 std::begin(); std::end(); 是泛型函数,可以应用到各种类型的容器中。 std::begin(); std::end(); 是泛型函数,可以应用到各种类型的容器中。
 </WRAP> </WRAP>
-===指针的算术运算===+===指针的其他算术运算=== 
 +<code cpp> 
 +int a[3] = {1,2,3}; 
 +auto ptr = a; 
 +auto ptr2 = a; 
 +//指针的前进 
 +ptr = ptr + 1; 
 +//比较 
 +ptr == ptr2; 
 +//关系运算(不推荐,除非两个指针在同数组中) 
 +ptr > ptr2; 
 +//求距离 
 +ptr2 - ptr 
 +</code> 
 +===数组的其他操作=== 
 +==求数组元素个数== 
 +  * ''sizeof()'':使用 sizeof 获取数组总大小,再除以元素的宽度 
 +  * ''std::size()'':使用标准库方法 
 +  * ''std::end() - std::begin()'' 
 +<code cpp> 
 +/* 必须都是对数组类型进行操作 */ 
 +int b[10]; 
 +//sizeof,[C method] 
 +sizeof(b) / sizeof(int); 
 +//std::size, [recommand] 
 +std::size(b); 
 +//end - begin, [run time method],通常使用 const 版本。 
 +std::end(b) - std::begin(b); 
 +</code> 
 +==遍历== 
 +<code cpp> 
 +int c[3] = {1,2,3}; 
 +//使用 std::size() 和 while 
 +size_t index = 0; 
 +while(index < std::size(c)) 
 +
 +    std::cout << c[index] << '\n'; 
 +    index++; 
 +
 + 
 +//cbeign, cend 
 +auto bPtr = std::cbegin(c); 
 +while(bPtr != std::cend(c)) 
 +
 +    std::cout << *bPtr << '\n'; 
 +    bPtr++; 
 +
 +//range for ,语法糖,基于 cbegin / cend 实现 
 +for (auto elem : c) 
 +
 +    std::cout << elem << '\n'; 
 +
 +</code> 
 +==C 字符串== 
 +  * 本质是数组 
 +  * 有额外的函数来支持该数组 ''<cstring>'' 
 +====多维数组==== 
 +  * 本质上是元素为数组的数组 
 +  * 在内存中是连续排列的,但按照元素的个数分组 
 +  * 二位数组类似**行优先**矩阵,左边是行,右边是列 
 +===多维数组的理解=== 
 +<code cpp> 
 +// 从左到右看 
 +// (x[3]) 是元素,元素类型为 Int[4] 
 +int x[3][4];  
 +// (y[3]) 是元素,元素类型为 int[4][5] 
 +Int y[3][4][5]; 
 +</code> 
 +{{ :cs:programming:cpp:cpp_primer:mult_array.svg?250 |}} 
 +===多维数组的初始化=== 
 +  * 默认初始化:遵从C++ 的默认初始化 
 +  * 聚合初始化: 
 +<code cpp> 
 +//由于在内存中是连续的,因此可以使用 list 初始化 
 +//初始值不够的所有元素都会进行默认初始化 
 +//按位初始化 
 +//1,2,3,4,0,0,0,0,0,0,0,0,
 +int x[3][4] = {1,2,3,4}; 
 +//分组初始化 
 +int y[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; 
 +//分组初始化的默认初始化处于分组内部 
 +int z[3][4] = {{1,2,3}, {4,5,6,7}, {8,9,10,11}}; 
 +//输出 0 
 +std::cout << z[0][3]; 
 +//输出 4 
 +std::cout << z[1][0]; 
 +//如果需要自动推断,必须指定元素的类型 
 +//只能省略最高位 
 +int a[][] = {1,2,3,4}; // error 
 +int a[][] = {{1,2,3,4}}; // error  
 +int a[][4] = {1,2,3,4}; // int[1][4] 
 +</code> 
 +===多维数组的遍历=== 
 +  * 多维数组遍历需要多重循环 
 +<code cpp> 
 +int x [3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}}; 
 + 
 +//range for 
 +//注意所有外层的 auto 都需要以引用的方式将数组类型传递给内层循环 
 +//否则,内层循环只会得到一个指向外层数组的指针 
 +//内层循环中 range for 需要使用数组的头指针作为起点,头指针 + 内层数组的长度作为终点进行循环 
 +//如果传入的是指针,长度信息丢失,那么将无法进行循环 
 +for (auto &row : x) 
 +
 +    for (auto col : row) 
 +    { 
 +        std::cout << col << " "; 
 +    } 
 +    std::cout << std::endl; 
 +
 + 
 +//while loop 
 +//注意 std::size() 的参数不同 
 +//遍历的顺序:x[0][0-3], x[1][1-3], x[2][1-3]。 
 +//推荐行优先遍历,可以减少 cache miss。 
 +size_t outter = 0; 
 +while (outter < std::size(x)) 
 +
 +    size_t inner = 0; 
 +    while (inner < std::size(x[inner])) 
 +    { 
 +        std::cout << x[outter][inner] <<" "; 
 +        inner++; 
 +    } 
 +    outter++; 
 +    std::cout << std::endl;  
 +
 +//纯指针遍历 
 +//与之前相同,cbegin 和 cend 需要数组而不是指针,因此内循环需要解引用 
 +auto OutterP = std::cbegin(x); 
 +while (OutterP != std::cend(x)) 
 +
 +    auto InnerP = std::cbegin(*OutterP); 
 +    { 
 +        while(InnerP != std::cend(*OutterP)) 
 +        { 
 +            std::cout << *InnerP << " "; 
 +            InnerP++; 
 +        } 
 +        std::cout << std::endl; 
 +    } 
 +    OutterP++; 
 +
 +</code> 
 + 
 +===多维数组与指针=== 
 +  * 多维数组也可以转化为指针,但只有最高维会进行转换 
 +    * 对于外围数组,如果指针要有意义,其指向的单位一定是外围数组的元素 
 +    * 比如下面的例子,外围数组有3个元素,如果移动指针 ''x+1'',则移动的单位实际上是一个包含 4 个 int 的数组 
 +<code cpp> 
 +int x[3][4]; 
 +// ptr int(*)[4] 
 +auto ptr = x; 
 +//ptr2 int(*)[4][5] 
 +int y[3][4][5]; 
 +auto ptr2 = y; 
 +</code> 
 +==使用类型别名声明多维数组的指针== 
 +<code cpp> 
 +using A2 = Int[4][5]; 
 +int x[3][4][5]; 
 +A2* ptr = x; //x 指向 int[4][5] 
 +</code> 
 +注意类型别名会改变维度的优先级: 
 +<code cpp> 
 +using A = int[4]; 
 +//如果这里使用 A 定义数组,那么结果会是 [4][3] 而不是 [3][4] 
 +A z2[3]; //等价与 int z2[4][3]; 
 +</code> 
 +====Vector==== 
 +  * 标准库提供的序列容器(类模板) 
 +  * 可复制,可动态更改个数 
 +<code cpp> 
 +//使用需要包含头文件 vector 
 +#include <vector> 
 +//类型是 vector<int> 
 +std::vector<int> x = {1,2,3}; 
 +//可复制 
 +std::vector<int> y; 
 +y = x; 
 +</code> 
 +===Vector 的初始化=== 
 +  * 默认初始化为 0 个元素 
 +  * 支持各种初始化 
 +<code cpp> 
 +//聚合初始化,x 的元素为 1,2,3 
 +//使用 brace 
 +std::vector<int> x = {1,2,3}; 
 + 
 +//init with default element count 
 +//使用panthesis 
 +//y 是 3个元素的 vector,每个元素都被默认初始化为 0 
 +std::vector<int> y(3); 
 +//count + value 
 +//z 中有 3 个元素 都是 1 
 +std::vector<int> z(3,1); 
 +</code> 
 +===Vector 的常用成员函数=== 
 +<code cpp> 
 +//计算 vector 的大小 
 +x.size(); 
 +// 查看 vector 是否为空 
 +x.empty(); 
 +// 添加元素(运行期) 
 +x.push_back(4); 
 +// 删除元素 
 +x.pop_back(); 
 +// index 访问 
 +x[2]; //无安全保证 
 +x.at(2); //越界访问会抛出异常 
 + 
 +//成员 begin & end,指向第一个元素和最后一个元素 
 +auto beg = x.begin(); 
 +auto e = x.end(); 
 +</code> 
 +===Vector 的遍历=== 
 +<code cpp> 
 +//成员函数 + 迭代器(类指针) 
 +//注意 begin / end 的结果不再是指针,是 iterator 
 +auto vBeg = x.begin(); 
 +auto vEnd = x.end(); 
 +while(vBeg != vEnd) 
 +
 +    std::cout << *vBeg << " "; 
 +    vBeg++; 
 +
 +//range for 
 +for (auto elem : x) 
 +    { 
 +         std::cout << elem << " "; 
 +    } 
 +</code> 
 +===迭代器=== 
 +  * std 容器中,通常使用迭代器模拟代替指针 
 +  * 迭代器可以: 
 +    * 解引用 
 +    * 下标访问会产生 *(x + index) 的行为 
 +    * 可以移动,相减(必须指向同一个 vector) 
 +==Vector 的比较== 
 +  * 位数相同且元素相同,则相等 
 +  * 如果一长一短,短 vector 与长 vector 对应位置内容相同,则长的较大 
 +  * 否则按位比较,找到的第一组不相同元素中,较大元素所在的 vector 较大 
 +===Vector 的其他细节=== 
 +  * 改变 vector 元素数量可能会导致迭代器失效 
 +  * Vector 支持多维 
 +<code cpp> 
 +//元素是 Int vector 的 vector 
 +std::vector<std::vector<int>> x; 
 +</code> 
 +  * 支持取地址并调用运算符(''->'') 
 +<code cpp> 
 +std::vector<int>* ptr = &x; 
 +ptr->size(); //equal *(ptr).size() 
 +</code> 
 +  * size() 返回的是 ''size_type'' 
 +====std::string==== 
 +  * 特化自 ''std::basic_string<char>'' 
 +  * 可复制,可改变字符串长度 
 +===string 的使用方法=== 
 +<code cpp> 
 +//需要引入头文件 
 +#include <string> 
 +//初始化 
 +std::string myStr = "helleworld"; 
 + 
 +//使用多次复制目标字符作为初始值 
 +//结果是 'aaa' 
 +std::string myStr2(3, 'a'); 
 +//拷贝初始化 
 +std::string myStr3 = myStr; 
 +std::string myStr4(myStr); 
 + 
 +//比较尺寸size & empty 
 +//比较 == > <,比较规则与 vector 同,按字符为单位比较 
 +//赋值 
 +std::string newStr; 
 +newStr = myStr; 
 +//拼接 
 +newStr = myStr + myStr2; 
 +newStr = myStr + "hellWorld"; 
 +//string + 的重载左边要求对象类型是 std::string,所以 c-string 不能放到加号左边 
 +//error 
 +newStr = "hello" + myStr; 
 +//索引 
 +myStr[0]; 
 +</code> 
 +==转化 std::string 到 c-string== 
 +<code cpp> 
 +//返回指向一个 Null teminated(\0) 的 const char* 指针 
 +myStr.c_str(); 
 +</code>