「学习笔记」指针的基础入门

2023-08-17 08:00:14来源:博客园

为啥会突然学这个呢?


【资料图】

因为长链剖分优化 DP 的状态转移用到了指针数组,平时的 STL 使用中也经常碰到指针。

So,就去学了一下,记录一下学习的笔记。我绝对不会告诉你另一个原因是因为最近做DP做累了想来写篇博文水水时间

引入

我们平时用 scanf输入的时候,都会在变量名前加一个 &,但是,字符数组除外。这个 &其实是取地址符,什么是地址呢?(以下为我的理解)你可以把它想象成你家房子的定位,这个就算是一个地址,只不过你家定位指向的是你家房子,而我们程序中的地址指向的是它对应的变量。约等于你住进了一个变量 /dog

这也就引出了指针的意义所在,即是一个指向元素的指向标,但是请注意,指针也是数据,存放这类数据的变量就成为“指针变量”。

我们的 &符号,则就是取出指向这个元素的指向标(指针)。

运行下面这段代码:

int main() {    int a;    cin >> a;    cout << a << "\n";    return 0;}

你输入 \(3\),程序就输出 \(3\),这里我们输出的是 \(a\) 这个变量元素

再运行这段代码:

int main() {    int a;    cin >> a;    cout << &a << "\n";    return 0;}

你再次输入 \(3\),程序却输出了一个你看不懂的东西 0xe71e7ff82c,这个就是变量 \(a\) 的存储地址,没错,已经不是元素了,这串十六进制的数字就是变量 \(a\) 的存储地址。

声明与使用

C++ 中,指针的定义实在变量类型的后面加个 *,例如 int*double*等等,想要获取指针指向的元素,只需要在指针变量前加一个 *即可。

int main() {int a;int* p = &a;cout << a << endl; // 3cout << *p << endl; // 3cout << &a << endl; // 0xe71e7ff82ccout << p << endl; // 0xe71e7ff82c}

对结构体变量也是类似。如果要访问指针指向的结构中的成员,需要先对指针进行解引用,再使用 .成员关系运算符。不过,更推荐使用运算符 ->这一更简便的写法。

struct ThreeInt {  int a;  int b;  int c;};int main() {  ThreeInt x{1, 2, 3}, y{6, 7, 8};  ThreeInt* px = &x;  (*px) = y;    // x: {6,7,8}  (*px).a = 4;  // x: {4,7,8}  px->b = 5;    // x: {4,5,8}}

当然了,也有指向指针的指针,指针的指针被我们称为二级指针,当然了,也会有三级指针、四级指针……

二级指针是在变量类型后面加 **,三级指针是在变量类型后面加 ***

int main() {int i = 30;int *pi = &i;int **ppi = πcout << i << endl; // 30cout << *pi << endl; // 30cout << **ppi << endl; // 30}
指针的偏移、操作

数组是一块连续的存储空间。而在 C++ 中,直接使用数组名,得到的是数组的起始地址,因此,我们在 scanf输入字符数组时不需要加 &,我们常用 []运算符来访问数组中某一指定偏移量处的元素。比如 a[3]或者 p[4]。这种写法和对指针进行运算后再引用是等价的,即 p[4]*(p + 4)是等价的两种写法。

STL 中的指针

在我们常用的 STL 容器,像 vectorset等,还有一些 STL 函数,像 lower_boundupper_boundfind()等等,我们都可以见到指针的身影,像 vector的首指针 begin(),尾指针 end()find()函数最后返回的类型是指针,等等。

指针定义需要一个关键字 iterator,定义 vector的指针如下

vector::iterator it;

下面的代码片段

vector v;int main() {    v.emplace_back(1);    v.emplace_back(2);    vector::iterator it = v.begin();    cout << *it << "\n";    return 0;}

最后输出的是 v的首元素。

当然,C++11 以后,可以直接用 auto在大多数情况下来代替这个关键词。

有了指针,就可以遍历一些 STL 容器了,像 setmap这样我们无法直接用数组下标遍历的容器。

int main() {set s;set::iterator it = s.begin();s.emplace(1);s.emplace(2);for (; it != s.end(); ++ it) {cout << *it << "\n";}}

一些指针可以转化通过减去首指针或数组名转化成数组下标,在 vector中是减去 begin(),在数组中是减去数组名(常见于一些代码中的 lower_boundupper_bound函数),但是,像 set就无法实现这个转化(可能是因为你不能直接用数组下标访问 set中的元素)。

标签:

今日热门
More
供应
返回顶部