【C++基础语法 11】——指针

11. 指针

补充知识

存储器和存储地址空间

  • 存储器:计算机的组成中,用来存储程序和数据,辅助CPU进行运算处理的重要部分。
  • 内存:内部存储器,暂存程序/数据,掉电丢失。SRAM、DRAM、DDR3、DDR4
  • 外存:外部存储器,长时间保存程序/数据,掉电不丢失。ROM、FLASH、硬盘、光盘等。

内存是沟通CPU与硬盘的桥梁

  • 暂时存放CPU中的运算数据
  • 暂时存放与硬盘等外部存储器交换是数据

存储地址空间:对存储器编码的范围

  • 编码:对每个物流存储单元(一个字节)分配一个号码
  • 寻址:根据分配的号码找到相应的存储单元,完成数据的读写

内存地址

  • 将内存抽象成一个很大的一维字符数组
  • 编码就是对内存的每一个字节分配一个32位或64位的编号,这个内存编号称为内存地址(唯一)
  • 内存中的每一个数据都会分配相应的地址
  • 对变量应用地址运算符(&),可以获取它在内存中的地址

11. 1 指针和指针变量

指针:是一种独立的数据类型,这种类型的变量存储的值就是内存地址

指针的作用:通过指针间接访问内存

  • 内存编号从0开始记录,一般用16进制数字表示

指针变量:保存内存地址

不同类型的指针变量所占用的存储单元长度是相同的


11.1.1 声明和初始化指针变量

指针变量的声明:

声明格式:

  • 数据类型 * 变量名: int * ptr;
  • 数据类型 *变量名: int *ptr;
  • 数据类型* 变量名: int* ptr;

注意:

  • 对每个指针变量名,都需要使用一个*
  • int* p1,p2; //声明创建一个指针变量p1和一个int类型变量p2;
  • int *p1, *p2; //声明创建一个指针变量p1和一个指针变量p2;
//在声明语句中初始化指针变量
int num=5;
int *pt_num=#//让指针pt_num记录变量num的地址

//声明指针变量后对其进行初始化
double d=2.0;
double *pt_d;
pt_d=&d;

11. 1. 2 使用指针变量(解引用)

可以通过解引用的方式来找到指针指向的内存。

指针前加 *代表解引用,找到指针指向的内存中数据。

*p 间接的访问内存,并对内存进行读写操作。

int main() {
	int a = 10;
	int* p = &a;//定义指针并赋值
	cout << "a的地址为" << &a << endl;//000000E75DCFFBA4
	cout << "指针p为" << p << endl;//000000E75DCFFBA4
  
  //使用指针
	*p = 1000;
	cout << "a=" << a << endl;//1000
	cout << "*p=" << *p << endl;//1000
  
    int num = 10;
	int* p;
	p = &num;
	cout << p << endl;
	cout << &num << endl;
	//对p解除引用运算符
	//*p == num;
	cout << *p << endl;
  
	*p = 100;
	cout << *p << endl;//100
	cout << num << endl;//100

	(*p)++;//++优先级高于*
	cout << *p << endl;//101
	cout << num << endl;//101

	cin >> *p;
	cout << *p << endl;//300
	cout << num << endl;//300

	return 0;
}

解除引用

  • 运算符称为间接值或接触引用运算符,将其应用于指针变量,可以得到该地址处存储的值。
  • 例如 ptr 是一个指针变量,则 ptr 存储的是一个地址,而 * ptr表示存储在该地址处的值, *ptr与常规变量等效。
  • 一定要在对指针变量解除引用之前,将指针变量初始化为一个确定的,适当的地址
  • 不能简单的将整数值赋值给指针变量


11. 2 指针所占内存空间

为什么要使用指针类型来保存地址的值?

  • 编译时类型检查
  • 指明一个内存地址所保存的二进制数据该怎么解释
#include<iostream>
using namespace std;
int main() {
	int num = 10;
    int *p=&num;
	cout << &num << endl;
	cout << sizeof(&num) << endl;
    cout << sizeof(int *) << endl;
	//在同一个平台上,所有的地址所占的空间大小是一样的
	//32位系统分配32位编码,4个字节
	//64位系统分配64位编码,8个字节
	return 0;
}


11. 3 空指针和野指针

空指针:指针变量指向内存中编号为0的空间

  • 在C++中值为0的指针变量称为空指针(null pointer)。空指针不会指向有效的数据。
  • C++中,空指针的值可以使用0NULLnullptr来表示

用途:初始化指针变量
注意:空指针指向的内存是不可以访问的

#include<iostream>
using namespace std;

int main() {
	//空指针
	//对指针变量进行初始化
	int* p = NULL;
	cout << p << endl;//0000000000000000
	int* ptr = nullptr;
	cout << ptr << endl;//0000000000000000
	//空指针不可进行访问
	// 0~255之间的内存编号是系统占用的,因此不可进行访问
	//*p = 100;//报错
	return 0;
}

野指针:指针变量指向非法的内存空间

  • 任意数值赋值给指针变量没有意义,这样的指针变量就是野指针,野指针指向的区域是未知的
  • 野指针不会直接引发错误,操作野指针指向的内存区域可能会出现问题。
#include<iostream>
using namespace std;

int main() {
	//野指针
	int* ptr = (int*)0x787878;
	*ptr = 10;//写入权限冲突,因为地址不存在
  	cout << *ptr << endl;//访问野指针报错
	return 0;
}

注意: 在程序中尽量避免出现野指针


取地址与取值的关系
//在使用中,*(取值)和 &(取地址)运算符之间的关系
int num=0;
int *p;
//p=&num;   num是int类型    &num是int*类型    
//总结:对变量取地址 &,整个表达式类型加上一个 *
int *p=&num;//int *p; p=&num;

p=&num;// p是 int* 类型    *p==num是int类型
//总结:在使用中,对指针变量使用 * ,整个表达式类型上减少一个 *
//注意:在使用中,当*和&同时出现时,从左往右,依次抵消
//&*&*&num


11. 4 指针变量的宽度和跨度

指针变量的两种类型:

  • 自身类型:去掉变量名,剩余的部分就是指针变量的自身类型

    int * ptr;//指针变量 ptr 的自身类型是 int *
    int ** ptr;//指针变量 ptr 的自身类型是 int **
    
  • 指向类型:去掉变量名以及离它最近的一个*,剩余的部分就是指针变量的指向的类型


int * ptr;//指针变量 ptr 指向的类型是 int
int ** ptr;//指针变量 ptr 指向的类型是 int *
int *p;
short *p1;

在这里插入图片描述

指针变量所取内容的宽度

  • 指针变量所取内容的宽度是由指针变量所指向的类型长度决定的。

指针变量+1的跨度

  • 指针变量+1的跨度是由指针变量所指向的类型的大小决定。
#include<iostream>
using namespace std;
//演示指针变量取值的宽度和+1的跨度
int main() {
	//宽度
	int num = 0x01020304;
	int* p = &num;
	cout << hex<<*p << endl;//hex 表示取 十六进制,即取num的十六进制格式:01020304,第一个0省略 1020304

	short* s = (short*)&num;
	cout << hex << *s << endl;//取前两个宽度,0304,第一个0省略,304

	//跨度
	short* s1 = nullptr;
	cout << "s1:" << s1 << endl;//s1:0000000000000000
	cout << "s1+1:" << s1 + 1 << endl;//s1 + 1:0000000000000002 short的跨度是2

	int* p1 = nullptr;
	cout << "p1:" << p1 << endl;//	p1 : 0000000000000000
	cout << "p1+1:" << p1 + 1 << endl;//	p1 + 1 : 0000000000000004 int的跨度是4
	return 0;
}

在这里插入图片描述

	//获取第二和第三个字节
	char* c = (char *) & num;
	short* s2 = (short*)(c + 1);
	cout << hex <<*s2 << endl;//0203,省略第一个0,203


11. 5 void类型指针

void* 为“无类型指针”

  • void* 可以保存任意类型的地址(万能指针)
  • 主要作为函数的参数

void*指针变量可以指向任意变量的内存空间,任何类型指针变量都可以转为void*

int num=10;
void *p=&num;
int * p_num=&num;
void *p1=p_num;//任何类型指针变量都可以转为void*

不要对void* 指针变量做解除引用与算数运算,如果想通过void* 指针变量取出内容,必须进行强制类型转换。

因为void* 是不完整的数据类型,系统不知道指针变量所指向的类型,所以不知道具体要取多少宽度,会报错

不允许使用void定义普通变量



11. 6 const和指针

const修饰指针变量,const修饰谁,谁就只读
在这里插入图片描述

#include<iostream>
using namespace std;
//const 和 指针
int main() {
	int num = 100;
	//第一种情况:const 在 * 的左边,修饰的是 * (*p1只读,p1可读可写)
	const int* p1 = &num;
	//*p1=20;报错,因为*p1不能修改
	int data = 20;
	p1 = &data;//p1可修改
	cout << *p1 << endl;//20,p1已被修改
  
  	//第二种情况:const在*的右边,修饰的是p2,(*p2可读可写,p2只读)
	int* const p2 = &num;
	*p2 = 200;
	cout << *p2 << endl;//200

	//第三种情况:const在*的左右两边,既修饰*也修饰指针变量(*p3只读,p3只读)
	const int* const p3 = &num;
	return 0;
}


11. 7 指针和数组

作用:利用指针访问数组中的元素

#include<iostream>
using namespace std;

int main() {
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	cout << "数组第一个元素为:" << arr[0] << endl;//1

	int* p = arr;
	cout << "利用指针访问第一个元素:" << *p << endl;//1
	p++;
	cout << "利用指针访问第二个元素:" << *p << endl;//2
	return 0;
}


11. 8 指针和函数

作用:利用指针作函数参数,可以修改实参的值

#include<iostream>
using namespace std;

void swap01(int a, int b) {
	int temp = a;
	a = b;
	b = temp;
}

void swap02(int *a, int *b) {
	int temp = *a;
	*a = *b;
	*b = temp;
}
int main() {
	int a = 10;
	int b = 20;
	//值传递   不会改变实参
	swap01(a, b);
	cout << "a=" << a << endl;//10
	cout << "b=" << b << endl;//20
	//地址传递  会改变实参
	swap02(&a, &b);
	cout << "a=" << a << endl;//20
	cout << "b=" << b << endl;//10
	return 0;
}


11. 9 二级指针

二级指针:一个指针指向的是另外一个指针,或者指向指针的指针

即一个指针变量保存的是另外一个指针变量的地址值

int num=10;
int *p=&num;
int **q=&p;//二级指针   
//*p : 获取的是 num 的值
//*q:获取的是num的地址值
//**q:获取的是 num 的值 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值