1 指针是什么
指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。 本质上, 指针和普通的变量没有什么区别, 只是它的值稍微特殊一点, 是一个地址, 通过这个地址我们就可以访问到实际的值。
指针即地址,指针即地址, 指针即地址, 记住这句话, 就能非常容易理解指针。
2 指针的定义及操作
2.1 一级指针
指针的一般定义为:指针类型 *指针变量名;
其中指针的类型是指指针所指向的地址中存放的值的类型, 因为指针本身是个地址值,数据类型是固定的; *
是指针的标识符, 指针变量名是指针变量的名字。
例如:
int *pt1; //定义了一个int型的指针pt1, 它指向的地址中存放的值是int型
double *pt2; //定义了一个double型的指针pt2, 它指向的地址中存放的值是double型
上面定义的指针没有初始化, 一个没有初始化的指针用起来是比较危险的, 因为不知道指向了哪里。所以用指针之前一定要初始化。 可以初始化为NULL值, 编译器会特殊处理。
下面是一个初始化的例子, 其中&
是取地址运算符。
int val=1;
int *pt1 = &val; //pt1指向val
int *pt2 = NULL
数组的名字就是地址, 所以可以把数组名赋值给一个指针。 那么指针就指向了数组的首元素地址。 但是字符串或者字符数组比较特殊,数组名不仅是地址, 而且也是字符串的值(实际上, 字符串或字符数组没有特殊之处, 名字也和普通数组名一样是个地址, 只是cout输出时做了特殊处理, 名字可以直接输出字符串的值)。
#include <iostream>
using namespace std;
int main()
{
int arr[3] ={1, 2, 3};
char chs[4]={'a','b','c', '\0'}; // "abc"
int *pt = arr;
char *pt_s = chs;
cout<<"the arr is :"<<arr<<endl;
cout<<"the pointer is :"<<pt<<endl;
cout<<"the value of pointer is :"<<*pt<<endl;
cout<<"the string is:"<<chs<<endl;
cout<<"the pointer of string is:"<<pt_s<<endl;
cout<<"the value of the string pointer is:"<<*pt_s<<endl;
return 0;
}
输出:
the arr is :0x72fdf0
the pointer is :0x72fdf0
the value of pointer is :1
the string is:abc
the pointer of string is:abc
the value of the string pointer is:a
2.2 二级指针
所谓二级指针就是指向指针的指针, 也就是指针中存放的是另一个指针的地址。 一个形象的比喻就是套娃。
只要理解了指针即地址这句话, 多级指针理解起来也没有难度。
二级指针定义时需要2个*
。
例如:
int **pt; //定义了一个指向int型指针的指针
3 指针的操作
3.1 访问指针的值
访问指针的值是指针最常见的操作了。指针本身只是个地址, 我i们一般不关心这个地址本身, 我们关心的是这个地址位置上存放的实际值。
通过*
可以访问指针的值。
例如:
#include <iostream>
using namespace std;
int main()
{
int val=1;
int *pt1=&val;
cout<<"the point is:"<<pt1<<endl;
cout<<"the value of the point is:"<<*pt1<<endl;
return 0;
}
输出
the point is:0x72fe04
the value of the point is:1
可以看到, 如果直接输出指针本身, 它就是个地址, 这也印证了我一直强调的指针即地址这句话。 用*
就可以访问指针所存放的实际值。
3.2 指针的数学运算
指针既然也是个值, 就支持基本的数学运算, 像++, --, +, -这些操作。
需要注意的是, 指针加1并不是地址值加1, 取决于指针的类型, 如int型指针, 指针加1实际上指针的值是加了4。 因为一个int型占4个字节。 要理解这一点,核心还是指针即地址这句话。 我们关心的是地址中存放的实际值, 而不是关心地址本身。 那么指针加1, 我们实际要想的是指向下一个值, 所以得加4。 如果指针只是加1的话, 实际上指向了一个int型值的中间一些bit位, 显然不是我们想要的。
例如:
#include <iostream>
using namespace std;
int main()
{
int val=1;
double val2 = 2;
int *pt1=&val;
double *pt2=&val2;
cout<<"the int point is:"<<pt1<<endl;
cout<<"the int point +1 is:"<<pt1+1<<endl;
cout<<"the int point + 2 is:"<<pt1+2<<endl;
pt1++;
cout<<"the int point ++ is:"<<pt1<<endl;
cout<<"the double point is:"<<pt2<<endl;
cout<<"the double point +1 is:"<<pt2+1<<endl;
return 0;
}
输出:
the int point is:0x72fdfc
the int point +1 is:0x72fe00
the int point + 2 is:0x72fe04
the int point ++ is:0x72fe00
the double point is:0x72fdf0
the double point +1 is:0x72fdf8
3.3 把指针作为参数传递给函数
C++函数可以接受指针作为参数, 只需要在定义函数时把形参声明为指针类型即可。
#include <iostream>
using namespace std;
void func1(int *pt)
{
*pt = 1;
}
int main()
{
int val=2;
int *pt = &val;
cout <<"the value before func1:"<<val<<endl;
func1(&val); //与func1(pt)是等价的, 因为指针实际上就是个地址
cout <<"the value after func1:"<<val<<endl;
}
the value before func1:2
the value after func1:1
需要注意的是, 由于传递的是地址, 所以对形参值的改变是影响到实参值的。
3.4 把指针作为函数的返回值
C++可以把指针作为函数的返回值, 只需要在定义函数时声明返回值是指针类型即可。
#include <iostream>
using namespace std;
int * func1()
{
static int val=1;
return &val;
}
int main()
{
cout <<"the value of the return is:"<<func1()<<endl;
cout<<"the value is:"<<*func1()<<endl;
}
输出:
the value of the return is:0x4a7010
the value is:1
如结果所示,函数返回了一个指针。