指针实际就是保存内存地址的一个变量,指针是有类型的,当对指针进行解引时,会根据指针的类型对所指的内存进行相应的解析,同变量一样也占用一定的内存(32位系统下占4位字节,64位占8位字节)
指针的定义
int a;
int* p = &a;
*代表 p为int类型的指针,&为取地址符
int* p, s1;
在这行代码中p为int类型的指针,s1为整形变量
指针的三种const用法
const int* p;// int const* p;
p = &a;
//这两种定义方法的指针,所指向的数据不能通过该指针进行修改
int a;
int* const p = &a;
//这种方式定义的指针,必须进行初始化,且该指针值不会改变,可以通过指针对其指向的值进行修改
int a;
const int* const p = &a;//或者int const* const p = &a;
//这种方式定义的指针,必须进行初始化,且该指针值不会改变,不可以通过指针对其指向的数据进行修改
指针与数组的纠缠
当函数参数中出现数组时,实际上传递的数组首个元素的地址,而不是把整个数组copy到栈空间,大量的拷贝会使得程序效率下降.因此在函数中对形参传来的数组进行的操作会影响实参里的值
指针数组的定义
int* p[100];
指针数组传参
//方式一: 指针数组传参,声明成指针数组,不指定数组大小
void method_4(int *arr[], int len) {
for(int i=0; i<len; i++){ printf(" arr[%d] = %d\n", i, *arr[i]);
}
}
//方式二: 指针数组传参,声明成指针数组,指定数组大小
void method_5(int *arr[10])
{
for(int i=0; i<10; i++){ printf(" arr[%d] = %d\n", i, *arr[i]);
}
}
//方式三: 二维指针传参
//传过去是指针数组的数组名,代表首元素地址,而数组的首元素又是一个指针,
//就表示二级指针,用二级指针接收
void method_6(int **arr, int len) {
for(int i=0; i<len; i++){ printf(" arr[%d] = %d\n", i, *(*(arr+i)));
}
}
空指针
- 什么是空指针? 空指针,就是值为 0 的指针。(任何程序数据都不会存储在地址为 0 的内存块中,它是被操作系 统预留的内存块。) int *p = 0; 或者int *p = NULL; //强烈推荐
- 空指针的使用
1)指针初始化为空指针 int *select = NULL; 目的就是,避免访问非法数据。
2)指针不再使用时,可以设置为空指针 int *select = &xiao_long_lv; //和小龙女约会 select = NULL;
3)表示这个指针还没有具体的指向,使用前进行合法性判断897943840118979438401111 int *p = NULL; // 。。。。 if § { //p 等同于 p!=NULL //指针不为空,对指针进行操作 }
坏指针
int *select; //没有初始化
情形一printf(“选择的房间是: %d\n”, *select);
情形二select = 100; printf(“选择的房间是: %d\n”, *select);
指针也分等级
二级指针只能存放一级指针的地址,三级指针只能存放二级指针的地址,以此类推.(不能越级)
空指针
void => 空类型 void* => 空类型指针,只存储地址的值,丢失类型,无法访问,要访问其值,我们必须对这个指 针做出正确的类型转换,然后再间接引用指针。 所有其它类型的指针都可以隐式自动转换成 void 类型指针,反之需要强制转换
指针运算
(1)指针与整数的运算,指针加减数字表示的意义是指针在数组中位置的移动; 对于整数部分而言,它代表的是一个元素,对于不同的数据类型,其数组的元素占 用的字节是不一样的, 比如指针 + 1,并不是在指针地址的基础之上加 1 个地址,而是在这个指针地址的 基础上加 1 个元素占用的字节数:
如果指针的类型是 char*,那么这个时候 1 代表 1 个字节地址;
如果指针的类型是 int*,那么这个时候 1 代表 4 个字节地址;
如果指针的类型是 float*,那么这个时候 1 代表 4 个字节地址;
如果指针的类型是 double*,那么这个时候 1 代表 8 个字节地址。
(2)通用公式: 数据类型 *p;
p + n 实际指向的地址:
p 基地址 + n * sizeof(数据类型)
p - n 实际指向的地址:
p 基地址 - n * sizeof(数据类型)
比如
对于 int 类型,比如 p 指向 0x0061FF14,则: p+1 实际指向的是 0x0061FF18,与 p 指向的内存地址相差 4 个字节; p+2 实际指向的是 0x0061FF1C,与 p 指向的内存地址相差 8 个字节
对于 char 类型,比如 p 指向 0x0061FF28,则: p+1 实际指向的是 0x0061FF29,与 p 指向的内存地址相差 1 个字节; p+1 实际指向的是 0x0061FF2A,与 p 指向的内存地址相差 2 个字节
指针和指针可以做减法操作,但不适合做加法运算.
指针和指针做减法适用的场合:两个指针都指向同一个数组,相减结果为两个指针之 间的元素数目,而不是两个指针之间相差的字节数。
如果两个指针不是指向同一个数组,它们相减就没有意义。
不同类型的指针不允许相减(指针之间可以进行比较)
函数指针
//函数指针的定义 把函数声明移过来,把函数名改成 (* 函数指针名)
int (*fp)(const void *, const void *);
/贝尔实验室的C和UNIX的开发者采用第1种形式,而伯克利的UNIX推广者却采用第2 种形式ANSI C 兼容了两种方式/
fp = &compare_int;
(*fp)(&x, &y); //第1种,按普通指针解引的放式进行调用,(*fp) 等同于compare_int
fp(&x, &y); //第2种 直接调用
数组指针
指向数组的指针
数组指针的定义假设指向一个int 类型的数组,数组成员为3个
int (* p)[3];
引用
可以理解为对一个变量起别名,实际上c++是用常指针实现的,所谓明修栈道暗度陈仓
int &a = 10;时是成立的,编译器会在栈开辟int空间,并起一个名字