指 针——用来存放内存地址的一类变量
符号: *
- 决定了指针的大小为系统位数那么大;并指所使用的电脑系统的位数,而是当前你的C所在的编译器架构的位数。
- 决定了point(下边的例子名)本身是用地址的形式存放数据(分析方式,就是一个地址数字)
注意:
- 当该符号出现在声明语句里时起修饰作用,代表该变量是一个指针
- 当其出现在其他地方时代表一个动作——解引用!
例子:*point; //引用point所指向的那块内存,类似于&,区别在于*后面 加的是指针变量,而
&后边接的是基本变量类型;很类似于 数组的 A[ i ]
大小:系统位数的大小——因为系统大小是固定的,能一次申请的内存上限就是系统的位数,故我只有那么多个变量的地址,所有指针上限就是系统位数大小
声明格式:
修饰类型 * 变量名;
例如:int *point;
取址符号(操作):&
例如:int x; 则 &x 就是取变量x的地址
解析方式:
指针本身的分析方式:按照系统位数宽度的无符号的数字的方式去分析(或者说去存放)的,即 long 型
修饰类型的意义:int,其决定了指针所指向的那块内存的分析方式
范例:
Int i = 200;
Int *point = &i;
*point = 100; // *point == *(&i) ,这两者是等效的,* 和 &可以相互抵消掉
Printf(“point = %ld, i = %d, *point = %d\n”, (long)point, i, *point);
//这个point的值会随系 统状态的变化而在不同次运行时有差别,因为变量 并非没错都申请到同一片内存
应用场景:
- 在函数调用时要更改某块内存的值则必须传入要修改的变量的地址!
例如:
2、登记匿名内存;
匿名内存指不是通过定义变量而得来,而是通过其他手段得来的内存,例如可调用malloc进行内存申请
例如:int *addr;
Addr = malloc(4);//这句话表示:用addr这个指针变量来记录了malloc申 请的4字节的内
存的首地址,并且该内存按照addr这 个指针变量的修饰类型符号所代表
的基本数据类型(此 处为 int)来进行分析
这个函数本身返回的是申请的内存首地址,故可用指针来记录这个地址,并通过指针的加减运算来进行偏移以访问该内存内不同地址的内存;
3、优化内存——主要用于函数传参时
如此,在我们用到结构体这种大内存的变量类型时,我们在传参的时候就可以不用再申请一个结构体那么大的变量类型去实现某个参数的传输,而只用定义这个结构体类型的指针(且是 const的指针)即可进行数据的传参,因为无论什么类型的指针其大小都是系统位数那么大,想比与结构体那么一个庞大的类型,一下子便节省了很多内存,实现了内存的优化!如此传参降低了内存和数据传输的负担!
但这样传址的操作也把地址传了过去,给了调用者可以修改所传变量的机会,故!常常搭配const 常量关键字来进行权限限制!
指针的运算
仅可以进行加减运算,更准确的说是进行地址的偏移,加和减代表两个不同的偏移方向(加右减左);而偏移的单位由修饰类型来决定,int的话就是一次偏移四字节(或说偏移了一个int型);
注意:1、两个指针变量不可相加,但!可以相减!并且只能同种修饰类型的地址相减,不同则单位都不匹配,不可相减!
相减的意义——可以知道两个指针(两个地址)之间相差多少单位
例如这里 dd - pp 我们就能知道它们之间的相差内存大小;
这操作与数组很类似,但这样操作内存更自由;
运算例子:int *point;
Point + 1;//指针向后偏移1个单位
Point - 1;//指针前偏移1个单位
Point + +;//指针向后偏移1个单位
Point - -;//指针向前偏移1个单位
Point1 - point2;//计算两指针相差多少单位的内存
分类——一维指针、二维指针、多维指针
实际应用中往往最多用到二维而已!
二维指针——本质为使能通过一个指针变量就能跳转访问多个内存——
因为 指针本质还是一个变量,而要改变它就得记录有东西
记录它的地 址,也就是用二维数组来记录。
例如:int **a;//此处的 a 即是二维指针变量
Int *p;
A = &p;//用a来存指针变量p的地址
多维东西的万能的理解公式
此处的type只是我们自己定义出来帮助理解的一个符号,系统并不存在这个类型
例如:
Int a, b;
Int *i = &b; //i = &b
Int **p;
P = &i;
*p = &a;// i = &a = *p
**p = 100 == *i=100 == *(&a)=100 == a=100
应用
二维指针只会出现在函数传参时想改变指针所指向的地址的情况下,其二维指针的声明式子 只会出现在子函数的函数头的参数声明(函数参数列表)里!例如下:
指针跟数组的对比
相同的地方:
指针跟数组的解引用可以互换:*(point+1)等价于point[1];
不同得地方:
数组名字不能自加自减,指针变量可以
注意事项
1、没有被赋予初值的指针称为野指针,会乱指向某块内存,此时若代码访问到它时可能会对别的内存造成干扰;故初始化时往往会赋值为NULL,代表空指针,不指向哪块内存,这样当不小心访问到该指针时能确保系统会马上奔溃,停止运行,可以防止对其他内存的干扰!
野指针——没有被赋予初值的指针。不可对其进行访问与赋值;
NULL指针——一旦访问马上奔溃的指针,为了有效的防止野指针操作,我们一般都会给指针变量赋予初值,若会没决定好初值,则直接赋值为NULL;
2、关于以下情况:
3、指针只能记录同种类型的变量的地址!
void * 指针——通配型指针:通配所有其他类型的指针
void i; //不可以不可以修饰变量,因为这样不知道该怎么分析这个变量的内存,也不 知道该
分配多少内存给这个变量
void *p; //可以修饰指针,代表这个是一个无初始属性的指针,可以用其记录其他任何 类型的
变量的地址。
int a;
p=&a; /可以,p兼容所有类型的指针
*p = 100;//不可以,p没有指定分析方式
*(int *)p = 100;//阔以,此处已经指定类型了