数组的引入
#include <iostream>
#include <type_traits>
int main()
{
int a; // int
int b[10]; // int[10]
std::cout << std::is_same_v<decltype(b), int[10]> << std::endl; // 1
}
#include <iostream>
#include <type_traits>
int b[3]; // 3个值在全局域默认初始化为0
int main()
{
int a[3] = {1, 2, 3}; // 聚合初始化
int b[3]; // 3个值在函数内部默认初始化为随机数
int c[3] = {1, 2}; // c = {1, 2, 0}
int d[3] = {}; // d = {0, 0, 0}
}
int main()
{
int b[] = {1, 2, 3}; // 编译器自动推导出中括号里的值为3
int a[3] = {1, 2, 3, 4} // 报错,中括号数值要么不写,要么大于等于{}个数
}
数组为什么不能复制,因为cpp关注性能的,数组的复制非常耗时间的,时间和数组长度相关。来一个数组,需要开辟一大块内存。
int main()
{
char str1[] = "Hello"; // char[6],最后有一个\0,表示字符串的结束
char str2[] = {'H', 'e', 'l' ,'l', 'o'}; // char[5]
}
int main()
{
int* a[3]; // a中3个元素都是指针
int x1 = 1;
int x2 = 2;
int x3 = 3;
int* x[3] = {&x1, &x2, &x3}; // 将x1, x2, x3地址放入指针数组
}
int main()
{
int b[3];
int (&a)[3] = b; // a是一个数组b的引用
int (*c)[3] = &b; // c是一个数组b的指针
}
int main()
{
int x1;
int x2;
int x3;
int& a = {x1, x2, x3}; //cpp没有引用的数组,也就是不能里面元素都是引用
}
为什么不能定义引用的数组,引用表示对象的别名,数组里面的元素一定要是对象,所以不能声明引用的数组。
int main()
{
int a[3] = {1, 2, 3};
std::cout << a[0] << a[1] << a[2] << std::endl;
}
int main()
{
int a[3] = {1, 2, 3};
auto b = a; // b是一个指向数组a第一个元素的指针
std::cout << *b << std::endl; // 1
std::cout << b << std::endl; // 0x7ffee7fd76dc
std::cout << a << std::endl; // 0x7ffee7fd76dc
std::cout << &(a[0]) << std::endl; // 0x7ffee7fd76dc
std::cout << &(a[1]) << std::endl; // 0x7ffee8a106e0
}
中括号不是数组特有的,指针也可以使用:
int main()
{
int a = 3;
int* ptr = &a;
std::cout << *ptr << std::endl; // 3
std::cout << ptr[0] << std::endl; // 3
}
x[y] 会被编译器解析成&(x + y)
超出界限,是非常危险的事,不要越界。
数组的指针
b是引用,就可以包含数组个数3的信息。
类型是在编译中用到的,所以在编译完后,系统文件链接时,类型信息就没有了。我们不知道是数组还是指针,只是知道他们是同名,这时候运行的时候才会报错。
上述的数组声明是可以的。Unknown Bounded Array,不关心数组中元素个数。
#include <iostream>
#include <type_traits>
#include <typeinfo>
using namespace std;
int main()
{
int a[3] = {1, 2, 3};
&(a[0]); // 获取数组开头的指针
a; // 获取数组开头的指针
begin(a); // 获取数组开头的指针
&(a[3]); // 获取数组结尾后一个元素的指针
a + 3; // 获取数组结尾后一个元素的指针
end(a); // 获取数组结尾后一个元素的指针
cout << &(a[0]) << endl;
cout << &(a[3]) << endl;
cout << std::begin(a) << endl;
cout << std::end(a) << endl;
}
#include <iostream>
#include <type_traits>
#include <typeinfo>
using namespace std;
int main()
{
int a[3] = {1, 2, 3};
auto ptr1 = a;
auto ptr2 = a + 2; // 数组增加
cout << (ptr1 == ptr2) << endl; // 数组比较
cout << (ptr2 - ptr1) << endl; // 数组距离
cout << *ptr2 << endl; // ptr解引用
cout << ptr2[0] << endl; // ptr索引
}
其他操作
sizeof c语言比较常用的
int main()
{
int a[3];
cout << sizeof(a) << endl; // 12
cout << sizeof(int) << endl; // 4
cout << sizeof(a) / sizeof(int) << endl; // 3 利用这样的方法求数组a的长度
}
std::size是cpp的库方法。
int main()
{
int a[3];
cout << std::size(a) << endl; // 3
}
因为cpp设定end是数组后一位,所以end-begin就是数组长度。
int main()
{
int a[3];
cout << std::end(a) - std::begin(a) << endl; // 3
}
int main()
{
int a[3];
cout << std::cend(a) - std::cbegin(a) << endl; // 3
}
所以cbegin和cend不作为计算数组长度推荐的方法。
sizeof是c语言的,而且写起来不方便,也不做推荐。
推荐:std::size(a);
int main()
{
int a[4] = {2, 3, 5, 8};
size_t index = 0;
while (index < std::size(a))
{
cout << a[index] << endl;
index += 1;
}
}
用指针遍历
int main()
{
int a[4] = {2, 3, 5, 8};
auto ptr = std::cbegin(a);
while (ptr != std::cend(a))
{
cout << *ptr << endl;
ptr += 1;
}
}
下面是for循环遍历
int main()
{
int a[4] = {2, 3, 5, 8};
for (int x : a)
{
cout << x << endl;
}
}
C的字符串
int main()
{
char str[] = "Hello"; // null-terminated string
auto ptr = str; // ptr 是一个char*,指向第一个字符
cout << strlen(str) << endl; // 5
cout << strlen(ptr) << endl; // 5
}
int main()
{
char str[5] = {'H', 'e', 'l', 'l', 'o'}; // char[5]
auto ptr = str; // ptr 是一个char*,指向第一个字符
cout << strlen(str) << endl; // 11 strlen方法会找到 \0 才会停止,所以不能用这个方法
cout << strlen(ptr) << endl; // 11 strlen方法会找到 \0 才会停止,所以不能用这个方法
}
int main()
{
char str[] = {'H', 'e', 'l', 'l', 'o', '\0'}; // char[5]
auto ptr = str; // ptr 是一个char*,指向第一个字符
cout << strlen(str) << endl; // 5 strlen方法会找到 \0 才会停止,需要手动加\0
cout << strlen(ptr) << endl; // 5 strlen方法会找到 \0 才会停止,需要手动加\0
}
通常来说,字符串数组,都需要\0这个结束符。
多维数组
int main()
{
int a[3][4]; // 多维数组
}
x[0] = 1, 2, 3 ; x[1] = 4, 0, 0;这种写法不推荐
只能省略最高位,但是不建议省略。
int main()
{
int x[3][4]; // 缺省初始化
int b[3][4] = {1, 2, 3, 4, 5};
// (int int int int), (int int int int), (int int int int)
// 1 2 3 4 5 0 0 0 0 0 0 0
int c[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}};
// 1 2 3 4, 5, 6, 7, 8, 0, 0, 0, 0
cout << c[1] << endl;
}
int main()
{
int x[2][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}};
for (auto& p : x)
{
for (auto q : p)
{
cout << q << endl;
}
}
}
int main()
{
int x[2][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}};
size_t index0 = 0;
while (index0 < 2)
{
size_t index1 = 0;
while (index1 < 4)
{
cout << x[index0][index1] << endl;
index1 += 1;
}
index0 += 1;
}
}
int main()
{
int x[2][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}};
size_t index0 = 0;
while (index0 < std::size(x))
{
size_t index1 = 0;
while (index1 < std::size(x[index0]))
{
cout << x[index0][index1] << endl;
index1 += 1;
}
index0 += 1;
}
}
指针的遍历多维数组。
int main()
{
int x[2][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}};
auto ptr1 = std::begin(x);
while (ptr1 != std::end(x))
{
auto ptr2 = std::begin(*ptr1);
while (ptr2 != std::end(*ptr1))
{
cout << *ptr2 << endl;
ptr2 += 1;
}
ptr1 += 1;
}
}