指针–指针变量
指针变量用于存放指针(或者可以理解成指针),这个关系就和int类型的变量用力啊存放int类型的常量相同. 可以把地址当作常量,然后专门定义了一种指针变量来存放它.但是指针变量的定义和普通变量的定义有所区别,它在某种数据类型后面加*来表示这是个指针变量,例如:
1
2
3
int *p;
double *p;
char *p;
注意:星号”“的位置是在数据类型之后或者变量之前都可以,编译器不会对此进行区分.C程序习惯将星号放在变量名之前, 即” int p ” 的写法,C++程序员习惯将星号放在数据类型之后 “int *p” 的写法.
但如果一次有好几个同种类型的指针变量要同时定义,星号只会结合于第一个变量名.也就是说,下面的定义中,只有p1是int* 型的, 而p2仍然为int类型的:
1
int *p1, p2;
如果要然后么定义的变量也变为指针变量,需要在后面的每个变量名之前都加上星号:
1
int *p1, *p2, *p3;
而此时为了美观往往将第一个星号放在p1前面
1
int *p1, *p2, *p3;
指针变量存放的是地址,&为取地址符号,因此,给指针变量赋值的方式一般是将变量的地址取出来,然后赋给相应的指针变量
1
2
int a;
int *p = &a;
或
1
2
3
int a;
int *p;
p = &a;
如果需要对多个指针变量初始化,方法也是一样的
1
2
int a, b;
int *p1 = &a, *p2 = &b;
需要注意的是,int*是指针变量的类型,后面的p才是变量名,用于存储地址,因此地址&a是赋值给p不是*p的。多个指针变量赋值时,由于写法上允许把星号放在所有变量名前,因此容易混淆,其实弄明白,星号只是类型的一部分就不会弄错。
那么,对一个指针变量存放的地址,如何得到这个地址所指的元素?其实还是使用。假设定义了int p = &a,那么指针变量p就存放了a的地址。为了通过p来获取变量a,*可以将星号视为一把开启房间的钥匙,将其加在p前面*,这样p就打开了房间,然后获得了a的值。
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
int main()
{
int a;
int *p = &a;
printf("%d\n", p);
a = 2333;
printf("%d\n", *p);
printf("%d\n", p);
*p = 6666;
printf("%d\n", *p);
}
输出:
```plain text 6356776 2333 6356776 6666
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
可以看出第一个输出p 输出的是a的地址%a 6356776
而输出*p为取到的变量a的值 2333
在上述代码中首先定义了a的类型为int 但是没有对其进行初始化.然后定义了指针变量p,并将a的地址赋值给了p.这个时候,指针变量p存放了a的地址.之后a被赋值为2333. a所在地址的房间内的东西改变了,但是a的地址并没有收到影响.而在后面的输出中使用* 作为开启房间的钥匙,放在p之前,*p就取到了房间内的东西,当数据改变时,地址不改变但房间内部的内容被改变.
由此,我们也可以想到,既然p保存的是地址,p为这个地址中存放的元素,那么直接对*p进行赋值,也可以起到改变那个保存元素的功能
例如:
在上述代码中,指针被令为p存放a的地址,直接对*p赋值,最后输出的时候,*p的a的值都输出一样
另外,指针变量也可以进行加减法,减法的结果就是两个地址的偏移距离,对与一个int*的指针变量p,p+1就是指针p的int型变量的下一个int型变量地址,这个所谓的”下一个”就是相邻地址的int,跨越了整个int型(4Byte)
```c
#include <stdio.h>
int main()
{
int a;
int *p = &a;
*p = 2333;
printf("%d %d", p, p + 1);
return 0;
}
输出:
plain text 6356776 6356780
可以看出地址是跨越了4Byte即4个字节,通常第一个字节存储的地方为代表这个变量地址。因此下一个int变量地址为+4。由此类推p+i个,则说明跨越到当前int型变量后面的第i个int型变量。除此之外,指针变量支持自增和自减操作。因此p++等同于p=p+1.指针变量加减法常用于数组的操作。
指针变量来说,其存储的地址类型被称为基类型,例如定义int* p的指针变量,int为其基类型,基类型必须和指针变量存储的地址类型相同,也就是说,上面定义的指针变量p不能存放double或者char型的数据的地址。(由此可见,数据地址也是分不同类型依据的是基地址的类型),必须是int类型的数据地址。