本 Wiki 开启了 HTTPS。但由于同 IP 的 Blog 也开启了 HTTPS,因此本站必须要支持 SNI 的浏览器才能浏览。为了兼容一部分浏览器,本站保留了 HTTP 作为兼容。如果您的浏览器支持 SNI,请尽量通过 HTTPS 访问本站,谢谢!
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录前一修订版后一修订版 | 前一修订版后一修订版两侧同时换到之后的修订记录 | ||
cs:programming:cpp:courses:cpp_basic_deep:chpt_3 [2024/04/17 02:13] – [数组访问的细节] codinghare | cs:programming:cpp:courses:cpp_basic_deep:chpt_3 [2024/04/18 03:31] – [使用类型别名声明多维数组的指针] codinghare | ||
---|---|---|---|
行 101: | 行 101: | ||
可以使用 decltype 来判断表达式是否是左值。 | 可以使用 decltype 来判断表达式是否是左值。 | ||
</ | </ | ||
+ | ====数组和指针==== | ||
+ | ===数组到指针的隐式转换=== | ||
+ | * 使用数组的时候通常数组会被转化为指针 | ||
+ | * 会丢失一部分信息(比如长度,编译器无法检查,这也是下标越界的原因) | ||
+ | <code cpp> | ||
+ | // decay, b 是 int* 类型 | ||
+ | int a[3]; | ||
+ | auto b = a; | ||
+ | //不会 decay 的范例 | ||
+ | //decltype 返回的是数组的类型 | ||
+ | // int[3] | ||
+ | decltype(a); | ||
+ | // int size * 3 | ||
+ | sizeof(a); | ||
+ | </ | ||
+ | * 可以通过声明避免隐式转换 | ||
+ | <code cpp> | ||
+ | // b 是 Int(& | ||
+ | // 此时长度信息没有丢失 | ||
+ | auto& b = a; | ||
+ | </ | ||
+ | * 不要使用 '' | ||
+ | <code cpp> | ||
+ | // | ||
+ | // | ||
+ | extern int array[4]; | ||
+ | //illegal | ||
+ | //runtime error | ||
+ | extern int* array; | ||
+ | </ | ||
+ | // | ||
+ | 很多情况下,长度信息需要反复的修改。如果在声明的时候带上长度信息,那么每次更改 array 的长度都必须同时去声明中改变 array 的长度。因此很多情况下会使用指针替代数组。但 '' | ||
+ | <code cpp> | ||
+ | // | ||
+ | int array[4] = {1,2,3,4}; | ||
+ | void fun() | ||
+ | { | ||
+ | std::cout << array << std::endl; | ||
+ | } | ||
+ | //main.cpp | ||
+ | extern int* array; | ||
+ | void fun(); | ||
+ | |||
+ | int main() | ||
+ | { | ||
+ | fun(); | ||
+ | std::cout << array << std::endl; | ||
+ | } | ||
+ | |||
+ | // output | ||
+ | // 两个 array 的输出不一样 | ||
+ | 0x7ff718ee3000 | ||
+ | 0x200000001 | ||
+ | </ | ||
+ | // | ||
+ | * 编译阶段没有问题,array 会被翻译为 '' | ||
+ | * 链接过程中:无论是 main.cpp 和 source.cpp 中的 array 是没有类型的,只有名称。这是因为类型只在编译期有效,如果加了更多的类型信息可能会导致不同翻译单元之间的链接问题。 | ||
+ | * 运行过程中: | ||
+ | * source.cpp 中的打印结果是正确的,因为 source.cpp 中的 array 代表的数组可以被编译器识别,此时编译器认为是指向 array 头元素的指针 | ||
+ | * main.cpp 中的 array,实际上不是一个地址: | ||
+ | * '' | ||
+ | * 按小端法,int 会从低地址到高地址保存: '' | ||
+ | * 数组中的数是连续存储的,因此该数组在内存中表现为: '' | ||
+ | * 而此时我们此时以指针的方式来解析该段数据,那么就会将前 8 个子节的内容拼成一个类似地址的内容,也就是 '' | ||
+ | * 该内容并不是 array 的首元素地址,而是 '' | ||
+ | * 可见数组和指针还是存在区别的 | ||
+ | // | ||
+ | <code cpp> | ||
+ | extern int array[]; | ||
+ | </ | ||
+ | 这么写合法。'' | ||
+ | <WRAP center round info 100%> | ||
+ | * 该方式被称为 //Unkonwn Bounded Array Declaration// | ||
+ | * int array[] 被称为 incomplete type,这种类型大多数用于共享定义的场景中 | ||
+ | </ | ||
+ | ==指向数组开头和结尾的指针== | ||
+ | * 开头指针:头元素 | ||
+ | * 结尾指针:尾元素**后一位** | ||
+ | 计算的两种方法: | ||
+ | <code cpp> | ||
+ | int a[3] = {1,2,3}; | ||
+ | // | ||
+ | a; // | ||
+ | &(a[0]) // 取数组首元素的地址(注意括号) | ||
+ | std:: | ||
+ | |||
+ | // | ||
+ | a + 3; | ||
+ | & | ||
+ | std:: | ||
+ | </ | ||
+ | 需要注意的是,'' | ||
+ | <code cpp> | ||
+ | b = a; | ||
+ | //error, begin() & end() are not applicable to a pointer. | ||
+ | std:: | ||
+ | // | ||
+ | extern int array[]; | ||
+ | std:: | ||
+ | </ | ||
+ | 对于 incomplete type 的获取,如需使用 | ||
+ | '' | ||
+ | <code cpp> | ||
+ | //ok | ||
+ | extern int array[4]; | ||
+ | std:: | ||
+ | </ | ||
+ | <WRAP center round box 100%> | ||
+ | std:: | ||
+ | </ | ||
+ | ===指针的其他算术运算=== | ||
+ | <code cpp> | ||
+ | int a[3] = {1,2,3}; | ||
+ | auto ptr = a; | ||
+ | auto ptr2 = a; | ||
+ | // | ||
+ | ptr = ptr + 1; | ||
+ | //比较 | ||
+ | ptr == ptr2; | ||
+ | // | ||
+ | ptr > ptr2; | ||
+ | //求距离 | ||
+ | ptr2 - ptr | ||
+ | </ | ||
+ | ===数组的其他操作=== | ||
+ | ==求数组元素个数== | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | <code cpp> | ||
+ | /* 必须都是对数组类型进行操作 */ | ||
+ | int b[10]; | ||
+ | // | ||
+ | sizeof(b) / sizeof(int); | ||
+ | // | ||
+ | std:: | ||
+ | //end - begin, [run time method],通常使用 const 版本。 | ||
+ | std::end(b) - std:: | ||
+ | </ | ||
+ | ==遍历== | ||
+ | <code cpp> | ||
+ | int c[3] = {1,2,3}; | ||
+ | //使用 std::size() 和 while | ||
+ | size_t index = 0; | ||
+ | while(index < std:: | ||
+ | { | ||
+ | std::cout << c[index] << ' | ||
+ | index++; | ||
+ | } | ||
+ | |||
+ | //cbeign, cend | ||
+ | auto bPtr = std:: | ||
+ | while(bPtr != std:: | ||
+ | { | ||
+ | std::cout << *bPtr << ' | ||
+ | bPtr++; | ||
+ | } | ||
+ | //range for ,语法糖,基于 cbegin / cend 实现 | ||
+ | for (auto elem : c) | ||
+ | { | ||
+ | std::cout << elem << ' | ||
+ | } | ||
+ | </ | ||
+ | ==C 字符串== | ||
+ | * 本质是数组 | ||
+ | * 有额外的函数来支持该数组 ''< | ||
+ | ====多维数组==== | ||
+ | * 本质上是元素为数组的数组 | ||
+ | * 在内存中是连续排列的,但按照元素的个数分组 | ||
+ | * 二位数组类似**行优先**矩阵,左边是行,右边是列 | ||
+ | ===多维数组的理解=== | ||
+ | <code cpp> | ||
+ | // 从左到右看 | ||
+ | // (x[3]) 是元素,元素类型为 Int[4] | ||
+ | int x[3][4]; | ||
+ | // (y[3]) 是元素,元素类型为 int[4][5] | ||
+ | Int y[3][4][5]; | ||
+ | </ | ||
+ | {{ : | ||
+ | ===多维数组的初始化=== | ||
+ | * 默认初始化:遵从C++ 的默认初始化 | ||
+ | * 聚合初始化: | ||
+ | <code cpp> | ||
+ | // | ||
+ | // | ||
+ | // | ||
+ | // | ||
+ | int x[3][4] = {1,2,3,4}; | ||
+ | // | ||
+ | int y[3][4] = {{1, | ||
+ | // | ||
+ | int z[3][4] = {{1,2,3}, {4,5,6,7}, {8, | ||
+ | //输出 0 | ||
+ | std::cout << z[0][3]; | ||
+ | //输出 4 | ||
+ | std::cout << z[1][0]; | ||
+ | // | ||
+ | // | ||
+ | int a[][] = {1,2,3,4}; // error | ||
+ | int a[][] = {{1, | ||
+ | int a[][4] = {1,2,3,4}; // int[1][4] | ||
+ | </ | ||
+ | ===多维数组的遍历=== | ||
+ | * 多维数组遍历需要多重循环 | ||
+ | <code cpp> | ||
+ | int x [3][4] = {{1,2,3,4}, {5,6,7,8}, {9, | ||
+ | |||
+ | //range for | ||
+ | // | ||
+ | // | ||
+ | // | ||
+ | // | ||
+ | for (auto &row : x) | ||
+ | { | ||
+ | for (auto col : row) | ||
+ | { | ||
+ | std::cout << col << " "; | ||
+ | } | ||
+ | std::cout << std::endl; | ||
+ | } | ||
+ | |||
+ | //while loop | ||
+ | //注意 std::size() 的参数不同 | ||
+ | // | ||
+ | // | ||
+ | size_t outter = 0; | ||
+ | while (outter < std:: | ||
+ | { | ||
+ | size_t inner = 0; | ||
+ | while (inner < std:: | ||
+ | { | ||
+ | std::cout << x[outter][inner] <<" | ||
+ | inner++; | ||
+ | } | ||
+ | outter++; | ||
+ | std::cout << std:: | ||
+ | } | ||
+ | // | ||
+ | // | ||
+ | auto OutterP = std:: | ||
+ | while (OutterP != std:: | ||
+ | { | ||
+ | auto InnerP = std:: | ||
+ | { | ||
+ | while(InnerP != std:: | ||
+ | { | ||
+ | std::cout << *InnerP << " "; | ||
+ | InnerP++; | ||
+ | } | ||
+ | std::cout << std::endl; | ||
+ | } | ||
+ | OutterP++; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===多维数组与指针=== | ||
+ | * 多维数组也可以转化为指针,但只有最高维会进行转换 | ||
+ | * 对于外围数组,如果指针要有意义,其指向的单位一定是外围数组的元素 | ||
+ | * 比如下面的例子,外围数组有3个元素,如果移动指针 '' | ||
+ | <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 cpp> | ||
+ | using A2 = Int[4][5]; | ||
+ | int x[3][4][5]; | ||
+ | A2* ptr = x; //x 指向 int[4][5] | ||
+ | </ | ||
+ | 注意类型别名会改变维度的优先级: | ||
+ | <code cpp> | ||
+ | using A = int[4]; | ||
+ | // | ||
+ | A z2[3]; //等价与 int z2[4][3]; | ||
+ | </ | ||
+ | ====Vector==== |