目录
指针就是地址,口语中说的指针通常指的是指针变量
指针的定义以及指针类型
例如:int* p;
p的类型并不是int,而是int*
当然的,除了int类型的指针还有short*的float*,double*等等的类型的
当然这里值得一提的是,这里的3个printf,都是打印4.
在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以
一个指针变量的大小就应该是4个字节。
那这样指针的类型不一样但都是4个字节,那指针的类型有什么用呢?答案在下面
由图中可以知道,第一个图int类型的a的地址由int*来存储
第二个图int的a的地址由char*来存储。可以看到第一个图更改了4个字节的地址,但第二个图只更改了1个字节的地址。
所以要用相同类型的指针变量来存储相同类型的变量地址,就像第一个图一样。
其实:
char* 类型的指针是为了存放 char 类型变量的地址。
short* 类型的指针是为了存放 short 类型变量的地址。
int* 类型的指针是为了存放 int 类型变量的地址。
而指针类型的例外一个作用:指针的类型决定了指针向前或者向后走一步有多大(距离)。
野指针
定义:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
比较常见的成因是:指针未定义,以及数组越界访问,形参或者其他原因造成的指针指向的空间释放
我们在编写代码时,需要努力的规避野指针,来避免程序出错
指针运算
a.指针+/-整数
例如:
int arr[10]={1,2,3,4,5,6,7,8,9,10}; int *p=arr; *p+1;
这里*p+1访问的是arr[1];
这里,++的运算级别比*高,所以先进行vp++,再加*,因为是后置++所以*vp++是访问的是*vp,然后再进行++,进入到下一个。
下图红色区域为数组地址的位置。
这里当数组减到values[0]的时候,因为判断条件是vp>=values[0],所以还会进行一次循环判断,这里就会超出数组的范围啦。
这样的话,能不能成功运行取决于编译器,所以最好不要这样写。
标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与
指向第一个元素之前的那个内存位置的指针进行比较。
这里我给翻译一下,就是可以跟数组后面的指针作比较,但不可以跟数组前面的的指针作比较。
b.指针只能-指针,不能+指针
指针与数组
当数组的首地址(数组名)定义给了指针的话。
.p+i 其实计算的是数组 arr 下标为i的地址。(p为指针)
二级指针
二级指针其实就是将一个指针的地址再将其放在一个指针中,类似于套娃。.
**ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a .
指针数组
int arr[10]其实就是存有int类型数据的数组
同理可得,指针数组也是一个数组,是一个存有指针的数组.
例如:int* arr[10];
指针的大小是固定的4/8个字节(32位平台/64位平台)
字符指针
字符指针简单来说就是存放字符变量的指针。
我们来研究一下这个代码:
从这里我们可以看到,p2存放的是一个字符串,所以字符指针不止可以存放字符还可以存放字符串
我们将p2解引用打印出来发现打印出a,所以如果存放的是字符串,字符串存到p2(指针)中存放的是字符串首元素的地址
我们要打印首元素的话需要解引用,也就是*p2
如果我们要打印字符串的时候,我们只要给字符串首元素的地址就好,也就是p2
这里p2存放的是常量字符串,常量字符串不允许修改
而如果我们想要修改的话,就得利用可以修改的空间,用数组来存储的时候就可以修改了