指针的基础用法
指针的类型
指针是一个4或8byte(取决于编译器)的变量,它能保存内存中某一个byte的地址。
变量或者对象在内存中存放时会占用多个byte,所以指针指向的是变量或者对象起始的那个byte的位置。
指针也是有类型的。
要操作指针所指向的内容时,会同时操作一片的内存。而指针的类型决定了要操作的内存的大小。
可以用<类型名> *描述指针的类型,指向<type>类型的变量或数组的指针类型都为<type> *
指针也是有地址的。
指针是一种特殊的变量,它首先是个变量,所以它本身是有地址的。
变量和类型.md中有查看指针类型的代码
定义指针
<type> * <name>
这样就能定义一个<type> *类型的指针
假设T是一种类型,可以这么定义一个类型为T *的指针
|
|
取值/取址符
当对一个指针使用取值符号(例如*p)时,读取内存中从p开始的若干个字节作为类型T。
取的字节数取决于指针类型的大小sizeof(T)
|
|
| 名称 | 类型 | 大小 |
|---|---|---|
p(指针)0 |
T * |
4或8 byte |
&data(取址符) |
T * |
4或8 byte |
*p(取值符) |
T |
sizeof(T) |
p[n],等同于*(p+n) |
T |
sizeof(T) |
arr(数组) |
T [N] |
sizeof(T)*N(特殊!) |
&arr |
T (*) [N] |
4或8 byte |
arr+0(对数组整数操作) |
T * |
4或8 byte |
如果指针指向的供使用的内存空间大小和指针类型大小相同,则能正常工作。若不同,则操作指针时会改变其它位置的内存,可能改动其它变量或直接崩溃。
注意区分:
- 在定义变量时,"
*“跟着后面的变量名表示后面的变量为指针- 在表示类型时,"
*“表示这是一个指针- 在表达式中,"
*“用作取值运算符- 在
变量和类型.md中有进一步的描述
总结:
*取值符号:取指针指向的变量,能被赋值(等号左右都能放)&取址符号:取变量的内存地址[]下标运算符:根据指针和下标取变量
运算
不同类型的指针虽然存放的都是内存地址,但不能互相赋值和比较,必须经过强制类型转换。
NULL可以被赋值给所有指针,其值=0,表示空指针
指针p加减整数n,表示将指针p向前或向后移动n * sizeof(T)。可以用自增或者自减。

指针特殊的用法
void类型指针
可以定义void类型的指针。void表示无类型,下面的语句意思是定义一个没有说明类型的指针。
void指针可以被任何类型的指针赋值,不能直接赋值给其它类型的指针。
|
|
此时,sizeof(p)=4,由于void不表示具体类型,sizeof(void)未定义,对p取值时不知道要操作多大的内存空间,读取值后也不知道转换为声明类型。所以对于void类型的指针类似于下面的操作是不合法的:
|
|
指针的嵌套
可以有int **p;这样的语句,表示指向指针的指针。甚至可以有int *****p这种东西。
|
|
以上程序可以输出233。
|
|
函数指针
函数的代码在程序运行的时候被放在了内存的某个位置。可以定义函数指针并将其指向某个函数,然后通过函数指针调用被指向的函数。
|
|
变量和类型.md中详细描述了“复杂类型声明”问题。
对象的指针
|
|
若要读取p指向的class内的元素的值,有两种方法:
|
|
const与指针
|
|
前面两个表示p指向的是一个int类型的常量,即*p无法被赋值。
最后一个表示p是一个常量,即p存放的地址无法被修改。
数组和指针
疑问
arr==&arr编译错误,提示:
1[Error] comparison between distinct pointer types `int*' and `int (*)[100]' lacks a cast`感觉数组和指针还是有一点区别的?
运行以下代码:
1 2 3 4arr[1]=1; cout<<arr[1]<<endl; cout<<(&arr)[1]<<endl; cout<<p[1]<<endl;输出:
1 2 31 0x64ff20 1再运行以下代码
1 2 3cout<<(&arr)[0]<<endl; cout<<(&arr)[1]<<endl; cout<<(&arr)[2]<<endl;输出:
1 2 30x64fd90 0x64ff20 0x6500b0根据编译器提示,
1 2 3// arr int* // &arr int(*)[100] // *p int*
int(*)[100]是什么?为什么对arr取地址会得到这个?怎么方便的获得一个东西的类型?
*与&到底修饰的是什么东西?指针++又是什么意思?对指针加减是按字节修改还是按类型大小修改?
指针也有类型?指针的类型有什么用?怎么做类型转换?
对一个数组,指针的类型包不包括那个
[100]?
sizeof()对变量、数组、指针的区别?
过了一年我意识到,产生这些疑问,本质上是对C/C++的类型描述不清楚。
有关类型
变量和类型.md中详细描述了“复杂类型声明”问题。这里举几个简单的例子:
nxm的二维数组a,元素类型为T:T [n][m]- 对数组
a取址T (*) [n][m] - 直接对
a进行指针操作T * [m] nxm的二维数组b,元素类型为T *:T * [n][m]- 对数组
b取址T * (*) [n][m] - 直接对
b进行指针操作T * * [m]
对数组名的几种操作
<name>:直接对数组名进行sizeof等操作,求的是数组实际的大小<name>:对数组名进行任何指针操作,将进行自动类型转换,等同于操作指向数组首元素的指针(&<name>[0]),同时维度-1- 一位数组:数组类型
<type> [n]=>自动转换为<type> *(首元素为单个变量,指向首元素的为普通指针) - 多维数组:数组类型
<type> [n1][n2][nk]=>自动转换为<type> (*) [n2][nk](首元素为数组,指向首元素的为数组指针)
- 一位数组:数组类型
<name>[k]:取数组第k位,实际为指针后移k位取值(*(<name>+k)),同时维度-1- 一维数组:
<type> [n]=><type> - 多维数组:
<type> [n1][n2][nk]=><type> [n2][nk]
- 一维数组:
&<name>:取指向数组的指针(<type> (*) [n1][n2][nk])
数组作为函数参数
要向函数传递数组,可以有以下等价写法
|
|
这三种方式是等价的,编译器认为这都是int *类型的指针。
调用函数时只会将arr作为指针传递给func。函数内只能将arr参数作为指针来处理
函数声明中数组大小完全没有作用。
可以通过
sizeof(arr)来验证,其值为4或8。
引用
概念
引用相当于变量的别名,是指针的语法糖。
在初始化之后不能修改引用的指向。
定义引用:<类型名称> & <变量名>
|
|
例子:
|
|
作为函数类型
|
|
输出40
在上面的例子中,由于函数返回n,可以将setvalue()整个看作n的引用,也就是n=40。
引用作为函数类型时不能返回函数内的局部变量。因为函数返回后,函数内的局部变量已经失效,其引用指向不确定的内存,会造成错误。
同理,指针也是这样,返回指针的时候,不能指向局部临时变量,否则指针将变为野指针