1.内存和地址
1.1内存
我们在买电脑时,有着8GB、16GB、32GB等不同内存大小的电脑,而这些内存会被分成一个个小的内存单元,每个内存单元的大小是1bit,也就是一个字节,一个比特位可以存储一个1/0,所以说每一个字节都有它对应的地址。在c语言中,我们给地址取了一个新的名字:指针。也就是说:指针就是地址,地址就是指针,就是他们在内存单元中的编号
1.2如何理解编址
计算机的编址,并不是把每个字节的地址记下来,而是通过硬件设计来完成的,也就是说一开始的地址的确定的。那如何将这么多的硬件连接起来呢?答案是:用线
地址信息被下达给内存,在内存上就能找到这个地址所记录的数据,将这些数据通过数据总线传递给CPU内寄存器。
可以简单理解为:32位机器上有着32根地址线,每一个地址线只能有两种状态:0/1,而32根地址线能够表示出2^32种不同的状态,每一种状态都表示一个地址
2.指针变量跟地址
2.1取地址操作符&
C语言中创建变量其实就是向内存中申请空间,那么怎样才能知道他们的地址呢?答案是:取地址操作符&
而取地址操作符取出的是最低位的字节的地址
2.2指针变量和解引用操作符*
2.2.1指针变量
我们可以将地址存储在指针变量中
指针变量就是用来存放地址的,存放在指针变量中的值都会被理解成指针
2.2.2解引用操作符*
解引用操作符就是通过pa中存放的地址,找到其指向的空间,其实也就是a变量,所以*pa = 20就给a改变成20了
2.3指针变量的大小
1.在32位平台下地址是32个bit位,指针变量大小是4个字节
2.在64位平台下地址是64个bit位,指针变量大小是8个字节
3.指针变量的大小与指针类型无关,只要是指针类型的变量,在相同的平台下,大小是相同的
3.指针变量类型的意义
3.1解引用操作
对比以上两个代码,我们可以发现,int的指针在改变时将a的4个字节的数全部改成了0,而char的指针在改变时只改变了n的一个字节,所以说:指针的类型决定了指针在解引用时能够访问的多大权限
3.2指针±整数
其实就是+1*(sizeof(指针类型))
指针的类型决定了指针向前或向后走的距离有多大
3.3void*类型指针(泛型指针)
如果我们将int类型变量的地址赋给char*,会报警告:
但当我们用void*来接受时,就不会报警告:
但是void类型的指针无法进行指针运算:
4.const修饰指针
2.1const放在指针前
2.2const放在指针后
2.3const放在指针前后
5.指针的基本运算
5.1指针±整数
5.2指针±指针
注意:
只有相同类型的指针才能够相减,而只有在同数组中的指针相减才有意义
两个指针相减的结果是一个整数,表示两个指针之间的元素个数
5.3指针的关系运算
1.==:判断两个指针是否指向同一处地址
2。>、<、<=、>=:判断两个指针指向的内存地址的大小,通常用于数组:
int arr[] = {1, 2, 3, 4, 5};
int *p1 = arr;
int *p2 = arr+1;
if(p1 < p2)
//会执行,因为p1指向数组第一个元素,p2指向数组第二个元素
}
6.野指针
概念:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
6.1野指针成因
6.1.1指针未初始化
6.1.2指针越界访问
6.1.3指针指向的空间释放
因为n是局部变量,离开test函数之后会被销毁,所以返回值不知道
6.2如何规避野指针
6.2.1指针初始化
如果知道指针指向哪里就给指针赋值,如果不知道指向哪里就赋给NULL:
6.2.2小心指针越界
6.2.3指针变量不再使⽤时,及时置NULL,指针使⽤之前检查有效性
6.2.4避免返回局部变量的地址
6.3assert断言
我们可以使用assert函数来判断指针是否位空指针
7.指针的传值调用和传址调用
7.1strlen函数的模拟实现
chuan
7.2传值调用和传址调用
传入了值,但是无法将a和b进行交换
传入的是地址,实现了a和b的交换
7.3总结
传址调⽤,可以让函数和主调函数之间建⽴真正的联系,在函数内部可以修改主调函数中的变量;所以未来函数中只是需要主调函数中的变量值来实现计算,就可以采⽤传值调⽤。如果函数内部要修改主调函数中的变量的值,就需要传址调⽤。