文章目录
- 1.什么是指针
- 2.为什么学指针
- 3.怎么使用指针
- 4.指针的注意事项
- 5.二级指针
- 6.指针与数组的联系
- 7.NULL指针
- 8.数组指针与指针数组
- 9.函数指针与指针函数
- 10.函数指针数组
- 11.this指针
1.什么是指针
指针就是内存地址,指针变量就是用来存放内存地址的变量。
总而言之,指针变量就是存放地址的变量,其指向的对象必须是变量,数组,函数等占有一定内存空间的实体。
2.为什么学指针
在C++中,指针的使用十分广泛。我们可以使用指针来写出更加高效,简洁的代码。
3.怎么使用指针
指针的定义:
指针的赋值:
指针的解引用:
我们来看一段代码:
#include <iostream>
using namespace std;
int main() {
int var = 6;
int* p_var = &var;
*p_var = 8;
cout<<" p_var ="<<p_var<<'\n'
<<" &var ="<<&var<<'\n'
<<"*p_var ="<<*p_var<<'\n'
<<" var ="<<var;
return 0;
}
运行效果如下:
p_var =005CF714
&var =005CF714
*p_var =8
var =8
由代码输出的内容可知:
我们来逐行分析一下:
4.指针的注意事项
4.1.指针的大小
我们知道,在C++中,存放数据的变量因数据类型不同,导致所占用的存储空间长度也不同。但需要注意的是,不同类型的指针变量所占用的存储单元长度是相同的。
如图所示:
运行结果如下:
char类型的指针大小为:8
int类型的指针大小为:8
double类型的指针大小为:8
4.2.野指针
当出现以下三种情况时,我们称指针为野指针:
野指针的危害很大,如果野指针指向的空间正在被使用,或者指向的地址根本无法访问,这就会导致数据被破坏,程序出错甚至崩溃。因此我们应该避免野指针的出现。
5.二级指针
二级指针就是指针的指针。
嘶,有点绕,这么说吧,二级指针里的存储的是一级指针的地址。也就是说二级指针是一种指向指针的指针。
来看一段代码吧:
#include <iostream>
using namespace std;
int main()
{
int var = 6;
int* p_var = &var;
int** pp_var = &p_var;
cout << "&p_var = " << &p_var << '\n'
<< "pp_var = " << pp_var << '\n'
<< "变量var的值为:" << **pp_var;
return 0;
}
代码运行结果如下:
&p_var = 008FF8AC
pp_var = 008FF8AC
变量var的值为:6
输出语句验证了:
- 二级指针里的存储的是一级指针的地址。
代码分析:
还有一点需要注意:
6.指针与数组的联系
6.1.用指针访问数组
事实上,利用指针操作数组会比使用索引来操作数组更快一些。
来看一段代码:
#include <iostream>
using namespace std;
int main ()
{
int arr[3] = {19,45,37};
int *p;
p = arr;
for (int i = 0; i < 3; i++)
{
cout<< "arr[" << i << "]的内存地址为 "
<< p << endl
<< "arr[" << i << "] 的值为 "
<< *p << endl;
p++;
}
return 0;
}
运行结果如下;
arr[0]的内存地址为 0x6ffdf0
arr[0] 的值为 19
arr[1]的内存地址为 0x6ffdf4
arr[1] 的值为 45
arr[2]的内存地址为 0x6ffdf8
arr[2] 的值为 37
在上述代码中,有三条语句引起我们注意:
我们来分析一下:
再来看一段代码:
#include <iostream>
using namespace std;
int main()
{
int arr[10]={1,2,3,4,5,6,7,8,9};
int* p1 = arr;
int* p2 = &arr[4];
cout<<"p2-p1 = "<<p2-p1;
return 0;
}
输出结果为:
p2-p1 = 4
我们的结论是:
6.2.注意事项
一:避免出现野指针
二:不能修改数组地址
7.NULL指针
NULL指针是一个定义在标准库中的值为零的常量
看代码:
#include <iostream>
using namespace std;
int main ()
{
int* p = NULL;
cout<<"空指针的值是 "<<p;
return 0;
}
运行结果为:
空指针的值是 0
小结:
当我们把未使用的指针都赋值为NULL时,我们就可以使用if语句:if(p!=NULL)
来判断指针是否不为空,如果不为空,再进行指针操作,这能有效地避免使用未初始化的指针。
8.数组指针与指针数组
8.1数组指针
来看一段代码:
#include <iostream>
using namespace std;
int main()
{
int arr[5]={16,75,31,65,82};
int *p = arr;
for(int i=0;i<5;i++)
{
cout<<*(p+i)<<" ";
}
return 0;
}
运行结果如下:
16 75 31 65 82
分析:
现在,我们来看看指向二维数组的数组指针
代码如下:
#include <iostream>
using namespace std;
int main()
{
int arr[3][4]={{11,16,24,28},{36,41,48,53},{66,88,90,98}};
int (*p)[4] = arr;//定义了一个数组指针,且指向了二维数组
for(int i=0;i<3;i++)
{
for(int j=0;j<4;j++){
cout<<*(*(p+i)+j)<<" ";
}
cout<<'\n';
}
return 0;
}
运行结果如下:
11 16 24 28
36 41 48 53
66 88 90 98
分析:
还有一点很有意思:
8.2.指针数组
我们将元素全是指针的数组称为指针数组
并且数组里的指针是指向相同数据类型的指针
来看一段代码:
#include <iostream>
using namespace std;
int main()
{
int a1[3] = {1,2,3};
int a2[3] = {1,2,3};
int a3[3] = {1,2,3};
int *p[3] = {a1,a2,a3};
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++){
cout<<p[i][j]<<" ";
}
cout<<'\n';
}
return 0;
}
运行结果如下:
1 2 3
1 2 3
1 2 3
指针数组本质上是一个数组
指针数组常用于指向若干字符串,这会使字符串处理更加灵活方便,也更加节省内存空间
实例:
#include <iostream>
using namespace std;
int main()
{
char *p[] = {"Hello ","World!"};
for(int i=0;i<2;i++)
{
for(int j=0;j<6;j++)
{
cout<<p[i][j];
//也可以用 *(*(p+i)+j)
}
}
return 0;
}
运行结果如下:
Hello World!
9.函数指针与指针函数
先看定义:
函数指针与指针函数区别在于:
9.1.函数指针
声明语法:
赋值语法(两种):
需要注意的是:
来看段代码:
#include <iostream>
using namespace std;
int sum(int x, int y) { return x + y; };
int main()
{
int (*ptr)(int, int);
ptr = sum;
int a = 3, b = 3;
int c = (*ptr)(a, b);
cout << "c的值为:"<<c;
return 0;
}
运行结果如下:
c的值为:6
分析:
总结:
9.2.指针函数
声明语法:
来看段代码:
#include <iostream>
using namespace std;
float *find(float(*p_func)[3],int n) /*定义指针函数*/
{
float *p_new;
p_new = *(p_func+n);
return p_new;
}
int main(void)
{
static float score[][3]={{96.3,89.7,66.9},{85.1,89.2,87.5},{66.3,59.8,76.4}};
float *p;
int m;
cout<<"您想查找第几位同学的成绩(共三位):\n";
cin>>m;
cout<<"第"<<m<<"位同学的语数英成绩分别为:\n|" ;
p=find(score,m-1);
for(int i=0;i<3;i++)
cout<<*(p+i)<<" |";
return 0;
}
运行结果为:
您想查找第几位同学的成绩(共三位):
1
第1位同学的语数英成绩分别为:
|96.3 |89.7 |66.9 |
分析:
总结:
10.函数指针数组
顾名思义,函数指针数组就是存放函数指针的数组
函数指针数组的用法就有点像点菜单一样,我们在数组里面存放若干个函数指针,然后让用户来选择使用哪些函数,数组中的指针可以用来调用函数。
来看段代码:
#include <iostream>
using namespace std;
int get_sum(int a,int b)
{
return a+b;
}
int get_sub(int a,int b)
{
return a-b;
}
int main()
{
int (*p[2])(int,int)={get_sum,get_sub};
int opt;
cout<<"请选择运算(加法为0,减法为1):\n";
cin>>opt;
int x,y;
cout<<"请输入参与运算的数值:\n";
cin>>x>>y;
cout<<"运算结果为:"<<(*p[opt])(x,y);
return 0;
}
运行结果如下:
请选择运算(加法为0,减法为1):
0
请输入参与运算的数值:
2
4
运算结果为:6
分析:
一:int (*p[2])(int,int)={get_sum,get_sub};
二:cout<<"运算结果为:"<<(*p[opt])(x,y);
11.this指针
在C++中:
注意!:
this指针的某些使用情景:
好了,指针部分的学习就到这了,可能有些晕(我之前也好晕),看不懂就多看几遍,并学会运用,相信指针部分是能够完美搞定。按照惯例,最后再来张思维导图梳理一下吧。