什么是指针:
指针是一种数据类型(无符号整数,这种整数代表了内存的编号),使用它可以定义的变量叫指针变量(简称指针,这种变量占用4|8字节内存大小)。
为什么使用指针:
1、函数之间共享变量:全局变量可能会名字冲突不可过多使用。 函数之间传参是值传递的,因此不能共享变量。函数之间的命名空间是独立的,但是存储空间是统一,可以把存储的地址在函数之间传递,达到共享的目的。
2、堆内存无法取名字(标识符无法与内存建立映射关系),只能与指针配合使用。
3、由于函数之间采用值传递进行传参(内存拷贝),当传递字节数较多的变量时效率会很低,如果只传递变量的地址只需要4字节(64系统8字节);
如何使用指针:
定义指针变量:类型* 指针变量名;
1、指针变量的用法与普通变量不同,为了区分它一般以p结尾
2、指针变量不能连续定义,一个只能定义出一个指针变量。
short p1,p2,p3; // p1是指针,p2,p3是short变量
short *p1,*p2,*p3; // p1,p2,p3都是指针变量
3、指针的类型决定了通过指针访问内存读取几个字节,int类型读取4字节,double类型读取8字节,char类型读取1字节。
4、指针变量的默认值是随机的,为了安全一定要初始化,一般初始化为NULL(空指针)。
赋值:变量名_p =地址编号;
指针变量必须存储一个有意义的内存编号,否则可能会造成段错误(非法访问内存)。
p = & num; // 将num的内存地址赋值给p
p = malloc(4); // 从堆内存分配两个字节,并把首地址赋值给p
取值:*p;
根据指针变量中存储的值访问内存(解引用)。
具体访问多少个字节由指针的类型决定。
使用指针要注意的问题
空指针:在C语言一旦对空指针进行解引用就会出现段错误。
在大多数系统下NULL就是0地址,由于操作系统把这个地址当作了复位地址(当操作系统重启时,会跳转到这个地址执行,所以它里面存储的是操作系统用来重启的数据),所以操作系统禁止访问这块内存,一旦解引用就会出现段错误。
如何杜绝空指针造成的段错误:使用来历不明的指针前要先判断是否是空指针。
if(NULL == p)
野指针:指向的内存不明确,这种指针叫野指针(野指针不代表就是错的,也有可能是正确的)。
使用野指针不一定会出错,但这也正是它危险的地方,因为无法证明,也无法判定,而且危险是潜在的。
使用野指针的后果:
1、一切正常
2、段错误
3、脏数据
如何避免使用野指针:由于无法判断是否是野指针,因此只能从源着手,不制造野指针是每个程序员应尽的职责。
如何避免产生野指针:
1、定义指针时初始化。
2、不获取局部变量的地址(在函数执行完后局部变量就会被释放)。
3、指针指向的资源被释放后,指针要及时赋值为空。
指针的运算:
指针变量里存储的就是整数,所以整型变量能够使用的运算符,指针变量都能使用,但对指针变量的所有运算不是都有意义的。
指针 + n =指针+宽度n // 指针向后移动n个元素
指针 - n = 指针-宽度n // 指针向前移动n个元素
指针 - 指针 = (指针-指针)/宽度 // 计算出两个指针之间相隔多少个元素。
%p 是以十六进制方式显示指针变量的值。
指针与数组
数组名就是个指针,是一种特殊指针(常指针),不能修改。
数组名与数组的首地址是对应关系,而指针是指向关系。
数组名可以使用指针的语法,指针也可以使用数组的语法。
arr[i] <=>*(arr+i)
当数组作函数的参数时,它就蜕变成了指针,在函数中无法计算出数组的长度,因此需要再添加一个参数把数组的长度传递过来。
指针与const配合
const int* p; // 保护的是指针指向的内存,不能通过指针去修改内存的值。
int const *p; // 同上
int* const p; // 保护的是指针变量,不能修改指针变量的值。
const int* const p; // 既保护的是指针变量又保护指针变量指向的内存。
int const* const p; // 同上
下面为一段指针基础用法的代码
#include <stdio.h>
int main(void)
{
int num = 10;
int* p = NULL; // 定义一个指针p
printf("%d", num);
p = # // 将num的地址赋值给指针p,此时*p <=> num,*p == 10
printf("%d", *p);
*p = 100; // 此时num == 100;
printf("%d %d", *p, num);
}