在C/C++中有一种数据类型叫做指针,符号为"*",常与其他数据类型一起使用,
教科书对指针的定义是: 指针是存放地址的变量,初见不知其意,再见连连称妙。
指针有两个作用:1.指向内存中的地址。2.读写地址上的值。
根据这两个作用我们其实就能推断出指针有两个大小,本身大小(不加*)取决于地址最大值这个和操作系统的操作位数相关,还有个就是解引用后的大小(加*)这个大小就取决于指针是什么类型,如int最大值为2147483647,short最大值为32767(65535/2-1),char 最大值为127
由此我们可以得出指针的大小(不加*)与数据类型无关,只与操作系统位数有关,例如32操作系统下指针占32/8 == 4字节 64位下占8字节。
对于结构体也是如此
sizeof返回的是无符号int而printf输出的是有符号整数因此会有警告
对于指向非法内存的指针我们称之为野指针
对于非法内存进行读写程序会直接崩溃,具体反应为main函数返回值非0,且函数拒绝执行
这里的p1比较特殊刚好指向的合法地址(地址合法,但指针不合法,在内存中有些地址存放系统运行的数据,为部分非法地址),故没有崩溃
野指针产生原因:1.创建指针的时候没有初始化
如上p1;
2.指针所指对象已消亡
最后一行,输出的并非想象中的a的值10,因为变量a是存储在栈空间的局部变量,离开函数超出其作用域后就会被释放掉,因此输出的值就是不确定的值了。
3.指针释放后未置空
指针p2被free或者delete之后,没有置为NULL,让人误以为p2是个合法的指针。对指针进行free和delete,只是把指针所指的内存空间给释放掉,但并没有把指针本身置空,此时指针指向的就是“垃圾”内存。释放后的指针应立即将指针置为NULL,防止产生野指针。
指针类别:
函数指针 int (*func)();func指向函数,func本质是指针
指针函数(返回指针的函数)int* func();func是函数名,本质是函数
数组指针int (*a)[N];a的每个成员指向一维数组;例如:
int c[N];
(*a)[0] = c;
怎么区别呢
int B[N],*a1;
a1 = B;//简单记忆:*相当于一层[]
指针可以干嘛?
1.作为参数进行传递
在C里面有两种传递,值传递和址传递
在初学时我们交换两个变量的值会写出以下代码:
swap(int a,int b){
int c = a;
a = b;
b = c;
}
当然这并不会交换实参的值,交换的是实参的值,因为会发生形参拷贝实参的过程,例如:
int a1 = 0 ,b2 = 1;
swap(a1,b2);
这里会发生a = a1,b = b2;然后执行函数体
所以最后不会修改实参的值
而2如果用指针做形参就是址传递,可以修改实参的值
swap(int *p1,int *p2){
int v = *p1;
*p2 = *p1;
*p1 = v;
}
这里调用的时候就是
int y1 = 4,y2 = 5;
swap(&y1,&y2);
int *p1 = &y1;
int* p2 = &y2;
2.用于传递复杂数据类型
比如函数,数组
当我们想传递数组时只需return数组的首地址即可
当我们想根据不同的情况调用某个函数就可以用函数指针数组来解决
3.访问数据
如果我们创建类那么我们就有两种访问方式:1.创建变量 使用"."访问成员变量。2.使用指针
#include<iostream>
using namespace std;
class fox {
public:
int length;
int age;
class fox* next;
};
int main() {
fox a;
fox* b;
a.age = 10;
printf("%d\n", a.age);
b = &a; //初始化b 让b指向a
b->age = 9;
printf("%d %d", a.age, b->age);
return 0;
}
输出:
10
9 9
当然除了以上常见的指针访问还有其它的操作,在此仅再示例一次
#include<iostream>
using namespace std;
class list {
public:
list* next;
list* pre;
};
class fox {
public:
int age;
int length;
list l;
};
int main() {
fox a;
int fox::* p = &fox::age;
a.*p = 1;
a.l.next = new list;
cout << a.age;
return 0;
}
输出:
1