【C语言初阶】9 指针初阶

1、指针的定义

将内存空间划分为一个个内存单元,1个内存单元占1byte(字节),将内存单元的编号称为地址(地址也叫作指针)。
指针也就是内存单元的编号
口语中常说的指针指的是指针变量

int main()
{
	int a = 10;//a是一个整型变量,占用4个字节的内存空间
	int* p = &a;
	//p 是一个指针变量 &a取出的是0x00dbfd98
	return 0;
}


每个内存单元的地址都是硬件生成的,不需要单独存储。除非进行取地址操作将其存放在指针变量中,内存单元的地址才会存储。

总结
指针就是地址,口语中的指针就是指针变量
指针变量中存放的就是地址,通过地址就可以找到一个内存单元

2、指针变量

内存单元采用1比特位太小,1kb太大,所以采用1个字节
在这里插入图片描述
对于64根地址线
2^64/1024/1024/1024=17,179,869,184GB
可以看出64根地址的编址空间非常大
总结
指针变量是用来存放地址,而地址是用于唯一标识一块地址空间(内存单元)
指针的大小在32位平台上是4个字节,而在64位平台上是8个字节。

X86 指的是32位平台
X64 指的是64位平台

3、指针和指针类型

在这里插入图片描述
sizeof 返回的是无符号整型 unsigned int(使用%d可能会发生报错,严格意义上来说用%u或者%zu
输出:32位平台4个字节 64位平台8个字节

小补充:16进制位
0x11223344
两个16进制位表示1个字节大小(1个16进制位表示4个2进制位,8个二进制位为1个字节)
在这里插入图片描述
既然char 、int、double指针变量的大小都是4/8个字节为啥还要区分指针类型,直接创建一个专属指针变量的类型不好吗?
在这里插入图片描述
将int
类型的地址赋值给char* 只是报警告
在这里插入图片描述
char* pc 是存放的是a的地址的(因为都是指针变量,在同一位平台下指针大小是相同的),但是在解引用的过程中char * pc只能解引用1个字节空间,所以指针类型是有意义的。

指针类型作用1:


pa(int型指针)+1跳过4个字节
pc(char型指针)+1跳过1个字节

指针类型作用2:
在这里插入图片描述
总结
指针类型存在的意义:
方便访问内存空间,可以根据自身所需字节大小来确定指针变量的类型

在这里插入图片描述
int* 和float* 指针访问空间大小虽然一样,但是不能混用
int类型指针认为里面存放的是int类型的变量,float类型指针认为里面存放的是float类型的变量,所以在内存中存储的数据是完全不同的
浮点数和整型在内存中存储方式 ,完全不同没有可比性

地址类似于门牌号用来唯一标识某一内存空间,门牌号后面的房间大小取决于指针变量的指针类型。

4、野指针

野指针的概念:指针指向的位置是不可知的(随机的,不正确的,没有明确限制的)

4.1野指针的成因

1)指针未初始化

在这里插入图片描述
这里p没有初始化,就意味着没有明确的指向
函数栈帧中初始化的都是随机值0xcccccccc,而局部变量不初始化,那么所指向的空间内容就是随机值
0xcccccccc所指向的地址是不属于当前程序,*p =10 给非法地址赋值,非法访问内存空间

2)指针越界访问

在这里插入图片描述
arr表示首元素地址,p指针指向首元素地址
for循环进行了11次而arr数组空间只有十个,所以最后一次循环造成越界。
当指针指向的范围超出arr的数组范围,p就是野指针。

3)指针所指向的空间释放

在这里插入图片描述
main函数调用test函数 test函数中将a赋值10,返回a的地址(0x0012ff40)赋值给p
test函数在被调用完后会将内存空间归还给操作系统
但是p指针还记得a的地址,a已经被销毁了。p指针访问的空间是非法的
销毁:test函数向内存空间申请了函数栈帧空间,调用结束后归还给操作系统,就是说没有访问这块空间的能力,而不是说减少了一块内存空间。

4.2 避免出现野指针的方法

在这里插入图片描述
当我们不知道将指针变量赋什么值时,将它赋为NULL 等价与 将变量赋值为0
(int *p2 =NULL —> int b = 0)
如果指针变量为NULL,无法对其操作

NULL是内存中的0地址,计算机是无法访问内存中NULL地址。
在这里插入图片描述
这里虽然加了判断条件,但是p本身就不是空值
p是野指针(p中存放着已经被释放的内存空间)仍然指向已经释放的test函数内存空间,如果该空间未被占用,仍旧可以打印出10
(可以理解成前女友电话,骚扰行为)
但是我们在前面加上几个print打印的就不是10(空间被使用了)
在这里插入图片描述
test函数调用完成后,函数栈帧的空间就空出来了,而后面的print又调用了函数栈帧,a的空间就被覆盖了
返回的就是随机值
在这里插入图片描述

5、指针运算

5.1 指针加减整数

在这里插入图片描述
后置加加 先 * vp =0 再 vp++
在这里插入图片描述
*vp++ 是对指针加1 而(*vp)++是对解引用后的值加1
指针加减整数的用法:数组遍历
在这里插入图片描述

5.2 指针-指针

在这里插入图片描述
arr[9]和arr[0]之间有9个元素
&arr[9] - &arr[0] = 9
&arr[0] - &arr[9] = -9
指针-指针的绝对值得到的是指针之间的元素个数
在这里插入图片描述
在这里插入图片描述
这是两个不同的空间,相减都不知道表示是int的个数还是char的个数,所以是err
指针-指针的用法(计算字符串长度strlen)
之前版本
在这里插入图片描述

5.3 指针的关系运算

在这里插入图片描述
先 --vp 再 * ( )=0
在这里插入图片描述
简化代码,这样看上去更直观

在这里插入图片描述
在这里插入图片描述
C语言标准规定p1允许与p2进行比较,但不允许与p3比较
一般是正向遍历就会与p2进行比较,逆向遍历则与p3比较

6、指针与数组

在这里插入图片描述

在这里插入图片描述
&arr[ i ] 和 p + i 是等价的 两个方式打印出来的地址是一样的
在这里插入图片描述
arr[ i ] 在计算机编译时还是会转换成 *(arr + i)
上面三种printf打印结果是一样的

7、二级指针

在这里插入图片描述
二级指针变量是用来存放一级指针变量的地址

8、指针数组

在这里插入图片描述
在这里插入图片描述
用指针数组来模拟实现二维数组 但是指针数组并不是二维数组,二维数组在内存中是连续存放的,而这里只是模拟实现
在这里插入图片描述
这两个是完全等价的

练习

1. 调试的方法

调试监视窗口 内存窗口
调试按F10进入调试
F11往后走
不能通过移动箭头来实现(移动箭头只是移过去了,中间过程都跳过了)在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值