计算机中的数据都存在内存中,访问内存的最小单元是“字节”,所有数据,就保存在内存中具有连续编号的一串字节中。
指针顾名思义就是指向另一种数据类型的复合类型。指针是C/C++中保存另一个数据对象在内存中的“地址”。通过指针可以访问到指向的那个数据对象,所以这是一种间接访问对象的方法。
指针的定义语法形式:类型* 指针变量;
类型是指针指向的对象的类型。
例如:以下 int 类型占4个字节,char占1个字节,指针占8个字节,指针里存的是a的地址:
00 00 00 34 F7 EF F8 88
#include<iostream>
using namespace std;
int main()
{
//定义指针
int *p1;
long *p2;
long long *p3;
cout << "p1长度:" << sizeof(p1) << endl;
cout << "p2长度:" << sizeof(p2) << endl;
cout << "p3长度" << sizeof(p3) << endl;
//指针存放的都是地址,因此它的长度只与系统有关,而不是与类型有关
//此处输出都是8
}
//指针的使用
int a = 10;
int b = 20;
long c = 88;
p1 = &a; //p1指针指向a
p2 = &c;
cout << "p1:" << p1 << endl;
cout << "p2:" << p2 << endl;
//如何通过指针获取内容
cout << "*p1:" << *p1 << endl; //*p1:10
cout << "*p2:" << *p2 << endl; //*p2:88
*p1 = 33;
cout << "a:" << a << "\t*p1:" << *p1 << endl; //a:33 *p1:33
定义一个指针后,如果不进行初始化,指针的内容就是不确定的。如果这时把它的内容当成一个地址去访问,那访问的是不存在的对象;如果访问到的是系统核心区域,修改其中的内容就有可能导致系统崩溃。这样的指针就是“无效指针”,也被叫做“野指针”。
int *p1;
//*p1 = 100 //直接解引用,危险!指针没有初始化,是无效指针
如果先定义了一个指针,但不确定它要指向哪一个对象,可以先初始化为“空指针”。空指针不指向任何对象。
//空指针
int *np = nullptr; //空指针的字面值常量,推荐使用
np = NULL; //预处理变量
np = 0; //只有0可以初始化,让其指向一个未被使用的内存
int zero = 0;
//np = zero //该初始化行不通
// void *ptr
int a = 10;
char b = 'c';
long d = 67.2;
int *p1 = &a; //p1只能指向int类型
//想要一个能指向任意类型的指针
void *ptr;
ptr = &a;
ptr = &b;
ptr = &c;
// cout << *ptr << endl; //错误,void类型指针只能用来存储地址,但是不能解引用
也叫“二级指针”,用连续两个“*” 表示,如果是三级指针则用三个表示。
// 指向指针的指针
int i = 22;
int *p5 = &i;
int **pp5 = &p5;
cout << "i:\t" << i << endl;
cout << "p5:\t" << p5 << endl;
cout << "pp5:\t" << pp5 << endl;
cout << "*p5:\t" << *p5 << endl;
cout << "*pp5:\t" << *pp5 << endl;
cout << "**pp5:\t" << **pp5 << endl;
/*输出
i: 22
p5: 0x61fdc8
pp5: 0x61fdc0
*p5: 22
*pp5: 0x61fdc8
**pp5: 22
*/
//指向常量的指针
const int i = 10, j = 20;
const int *p = &i;
cout << "p\t" << p << endl;
cout << "*p\t" << *p << endl;
//*p = 15 //错误,常量不可修改
p = &j; //但是指针指向的对象可以换
cout << "*p\t" << *p << endl;
int x = 10;
int y = 20;
int *const ptr = &x; // 定义一个指向整型变量的指针常量,指向 x
cout << "x 的值为:" << x << endl;
cout << "通过指针访问 x 的值:" << *ptr << endl;
// 尝试修改指针指向的地址
// ptr = &y; // 这行代码会导致编译错误,因为 ptr 是一个指针常量,不能再指向其他地址
// 通过指针修改所指向地址的内容
*ptr = 100;
cout << "修改后,x 的值为:" << x << endl;
用到数组名时,编译器一般都会把它转换为指针,这个指针就指向数组第一个元素。所以也可以用数组名给指针赋值
//指针和数组的关系
int arr[5] = {1, 2, 4, 5, 6};
cout << "&arr\t" << &arr << endl;
cout << "arr\t" << arr << endl;
cout << "&arr[0]\t" << &arr[0] << endl;
cout << "arr+1\t" << arr + 1 << endl; // arr+1 相当于是arr[1]的地址
cout << "&arr[1]\t" << &arr[1] << endl;
int *ptr = arr;
cout << "ptr\t" << ptr << endl;
cout << "*ptr\t" << *ptr << endl;
cout << "ptr+1\t" << ptr + 1 << endl;
cout << "*(ptr + 1)\t" << *(ptr + 1) << endl;
输出:
&arr 0x61fe00
arr 0x61fe00
&arr[0] 0x61fe00
arr+1 0x61fe04
&arr[1] 0x61fe04
ptr 0x61fe00
*ptr 1
ptr+1 0x61fe04
*(ptr + 1) 2
int arr[5] = {1, 2, 3, 4, 6};
//指针数组,本质是数组,数组的所有的元素都是同类型的指针
int *pa[5];
cout << "sizeof(pa)\t" << sizeof(pa) << endl;
pa[0] = arr;
pa[1] = arr +1;
cout << "pa[0]\t" << pa[0] << endl;
cout << "*pa[0]\t" << *pa[0] << endl;
输出
sizeof(pa) 40
pa[0] 0x61fe00
*pa[0] 1
//数组指针,本质是指针,指向一个数组
int (*ap)[5] = &arr;
cout << "sizeof(ap)\t" << sizeof(ap) << endl;
cout << "ap\t" << ap << endl;
cout << "*ap\t" << *ap << endl;
cout << "**ap\t" << **ap << endl;
cout << "*(*ap + 1)\t" << *(*ap + 1) << endl;
输出:
sizeof(ap) 8
ap 0x61fe00
*ap 0x61fe00
**ap 1
*(*ap + 1) 2