一:复习
首先先回顾一下之前对于指针概念的理解.
计算机在存储数据的时候必须跟踪3种基本属性
- 存储位置
- 存储的值
- 存储的信息类型
在之前的文章说已经说到了,这里再说一遍,指针是一个变量,存储的是地址。 所以指针本质是一个地址!看到指针条件反射想到地址。
对于一个常规变量,&
运算符就能够取得他的地址。所以一个变量var
,那么&var
就是一个地址。
#include <iostream>
int main()
{
int a=3;
std::cout<<"the address of a:"<<&a<<std::endl;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
运行结果:
the address of a:0x61ff18
- 1
输出地址是以十六进制来输出的。
对于一个指针变量pointer
,*pointer
表示解除引用,将其应用于指针,可以得到该地址存储的值。且这个值就是常规的值。
#include <iostream> int main() { int a=3; std::cout<<"the address of a:"<<&a<<std::endl;
<span class="token keyword">int</span><span class="token operator">*</span> p_a<span class="token operator">=</span><span class="token operator">&</span>a<span class="token punctuation">;</span> std<span class="token punctuation">:</span><span class="token punctuation">:</span>cout<span class="token operator"><<</span><span class="token string">"the value of p_a is:"</span><span class="token operator"><<</span>p_a<span class="token operator"><<</span>std<span class="token punctuation">:</span><span class="token punctuation">:</span>endl<span class="token punctuation">;</span> std<span class="token punctuation">:</span><span class="token punctuation">:</span>cout<span class="token operator"><<</span><span class="token string">"*p_a:"</span><span class="token operator"><<</span><span class="token operator">*</span>p_a<span class="token operator"><<</span>std<span class="token punctuation">:</span><span class="token punctuation">:</span>endl<span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
运行结果:
the address of a:0x61ff18
the value of p_a is:0x61ff18
*p_a:3
- 1
- 2
- 3
可以知道,这里的int变量和指针变量就像同一个硬币的正反面。变量表示值,可以使用&
来得到地址。 指针变量表示地址,并且可以使用*
来得到值 .
*p_a
和a
就是等价的。这个一定要知道,是后面修改的基础。
声明和初始化指针
typename* name;
- 1
-
声明的时候必须带有
*
号来表示这个时候声明的是一个指针。同时必须类型要明确。 -
*
号旁边的空格是可选的,但是为了不和解除应用的*
号相混淆,很多人喜欢让*
号紧挨着typename(比如int* p_a
,表示现在正在声明的是int类型的指针变量)。同时,在解除引用的时候紧挨着变量,表示是对这个变量的解除引用(*p_a
) -
应该注意:指针指向的地址存储的值可能有不同的长度,但是指针本身的长度都是一样长的!(地址是需要2个字节还是需要4个字节,取决于系统的实现)
-
可以在声明指针的时候初始化指针。要注意,指针初始化时是初始化它指向的地址.要是暂时不知道要初始化为什么样子怎么办? 这里推荐一种做法,就是把指针初始化为
nullptr
,然后对指针进行判断,这样能够有效减少之后可能出现的错误.
必须背下来的经验:一定要在对指针解除引用(*p_a
)之前,将指针初始化为一个确定的适当的地址。因为,要是初始化的时候没有指定地址,那么解引用的地址要么没有,要么有可能是随机的,这样风险非常大.这也是为什么推荐将指针初始化为nullptr
的原因,那么解引用的时候可以先判断是否为nullptr
,要是不是的话,说明这个指针我们曾经手动赋值过,可以放心解引用.
二.指针和数组
说到指针和数组,这里直接说三个最基本的规则,这三个规则基本上能够概括指针和数组的常见关系了.
- 一看到数组,就要知道数组名可以当做这个数组的第一个地址。(
a=&a[0]
) - 对于指向数组的指针,指针+n表示往后移动n个位置
- 指针也可以像数组那样用
p_a[n]
这种形式直接取元素,本质是*(p_a+n)
三.指针和字符串
指针和字符串相信是很多人一直弄混淆的地方了.其中确实有些地方需要理一理. 指针和字符串主要是指针用于c风格的字符串.
这里首先把重要的几个规则列出来,这几个规则足够弄清楚指针和字符串之间的关系了.
- 已经知道,c风格的字符串本质就是一个字符数组,所以,数组名就是第一个元素的地址。同样,一个指向char的指针变量也能够实现字符串的一些东西.
- C++中,对于引号引起来的字符串,也代表第一个元素的地址。
cout
对象认为,char的地址是字符串的地址,因此它打印该处的地址处的字符, 然后继续打印后面的字符。直到遇到空字符’\0’
之后才停止。
这里举一个例子来详细说明.
#include <iostream>
#include <cstring>
int main()
{
char animal[20]=“bear”;
const char bird=“wren”;
char p_s;
<span class="token comment">//数组名也是指针</span>
std<span class="token punctuation">:</span><span class="token punctuation">:</span>cout<span class="token operator"><<</span>animal<span class="token operator"><<</span><span class="token string">" and "</span><span class="token operator"><<</span>bird<span class="token operator"><<</span>std<span class="token punctuation">:</span><span class="token punctuation">:</span>endl<span class="token punctuation">;</span>
<span class="token comment">//直接输出指针</span>
p_s<span class="token operator">=</span>animal<span class="token punctuation">;</span>
std<span class="token punctuation">:</span><span class="token punctuation">:</span>cout<span class="token operator"><<</span><span class="token string">"p_s:"</span><span class="token operator"><<</span>p_s<span class="token operator"><<</span>std<span class="token punctuation">:</span><span class="token punctuation">:</span>endl<span class="token punctuation">;</span>
<span class="token comment">//想要输出真的地址怎么办?</span>
std<span class="token punctuation">:</span><span class="token punctuation">:</span>cout<span class="token operator"><<</span><span class="token string">"address of animal:"</span><span class="token operator"><<</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token operator">*</span><span class="token punctuation">)</span>animal<span class="token operator"><<</span>std<span class="token punctuation">:</span><span class="token punctuation">:</span>endl<span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 永远应该记住,双引号引起来的C风格的字符串常量,字符数组,字符指针变量这几个是相通等价的。
- 注意
const char* bird="wren"
;要是不使用const会有警告,因为不能够用可变的指针来修改常量. - 当cout后面是其他的指针的时候,会输出该指针的值也就是一个地址,但是cout遇到char* 的时候,就会输出当前char*指向的值,同时也会输出后面的值,直到遇到空字符为止。
- 所以在上面程序的20和21行有一个(
int*
)强制转化为整形指针,不然就没得输出了。