一,内存和地址
1,内存
在讲内存和地址之前,我们先举个案例
假设有⼀栋宿舍楼,把你放在楼⾥,楼上有100个房间,但是房间没有编号,你的⼀个朋友来找你玩, 如果想找到你,就得挨个房⼦去找,这样效率很低,但是我们如果根据楼层和楼层的房间的情况,给 每个房间编上号,如:
一楼:101 102 103 ...
二楼:201 202 203 ...
三楼:...
有了房间号,如果你的朋友得到房间号,就可以快速的找房间,找到你;
让我们把上面例子类比一下,会得到什么呢?
我们知道计算上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数 据也会放回内存中,那我们买电脑的时候,电脑上内存是8GB/16GB/32GB等,那这些内存空间如何⾼ 效的管理呢?
如图:其实也是把内存划分为⼀个个的内存单元,每个内存单元的⼤⼩取1个字节
先来说计算机中常⻅的单位:
bit - ⽐特位 1byte = 8bit
byte - 字节 1KB = 1024byte
KB 1MB = 1024KB
MB 1GB = 1024MB
GB 1TB = 1024GB
TB 1PB = 1024TB
PB
其中,每个内存单元,相当于⼀个学⽣宿舍,⼀ 个⼈字节空间⾥⾯能放8个⽐特位,就好⽐同学们 住的⼋⼈间,每个⼈是⼀个⽐特位
每个内存单元也都有⼀个编号(这个编号就相当 于宿舍房间的⻔牌号),有了这个内存单元的编 号,CPU就可以快速找到⼀个内存空间
⽣活中我们把⻔牌号也叫地址,在计算机中我们 把内存单元的编号也称为地址。C语⾔中给地址起 了新的名字叫:指针
所以我们可以理解为: 内存单元的编号 == 地址 == 指针
二,指针变量和地址
1,取地址操作符(&)
理解了内存和地址的关系,我们再回到C语⾔,在C语⾔中创建变量其实就是向内存申请空间,⽐如:
#include <stdio.h>
int main()
{int a = 10;return 0;
}
上述的代码就是创建了整型变量a,内存中 申请4个字节,⽤于存放整数10,其中每个字节都 有地址 ;
那我们如何能得到a的地址呢?
这⾥就得学习⼀个操作符(&)-取地址操作符
#include <stdio.h>
int main()
{int a = 100;&a; //取出a的地址printf("%p", &a);return 0;
}
运行结果(十六进制)
&a取出的是a所占4个字节中地址较⼩的字节的地址
虽然整型变量占⽤4个字节,我们只要知道了第⼀个字节地址,顺藤摸⽠访问到4个字节的数据也是可⾏的
2,针变量和解引⽤操作符(*)
2_1,指针变量
那我们通过取地址操作符(&)拿到的地址是⼀个数值,⽐如:0x006FEF80,这个数值有时候也是需要 存储起来,⽅便后期再使⽤的,那我们把这样的地址值存放在哪⾥呢?答案是:指针变量中
举例:
#include <stdio.h>
int main()
{int a = 100;int* p = &a; //取出a的地址并存储到指针变量p中return 0;
}
指针变量也是⼀种变量,这种变量就是⽤来存放地址的,存放在指针变量中的值都会理解为地址
2_2,拆解了解指针(重点!)
int a = 10;
int * p = &a;
这⾥p左边写的是 int* , * 是在说明p是指针变量,⽽前⾯的 int 是在说明p指向的是整型(int) 类型的对象 ;
搞清楚这三个的区别:
p 指针变量本身*p 等于==‘a’&a ‘a’的地址
2_3,解引⽤操作符
我们将地址保存起来,未来是要使⽤的,那怎么使⽤呢?
在现实⽣活中,我们使⽤地址要找到⼀个房间,在房间⾥可以拿去或者存放物品。
C语⾔中其实也是⼀样的,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针) 指向的对象,这⾥必须学习⼀个操作符叫解引⽤操作符(*)
#include <stdio.h>
int main()
{int a = 100;int* p = &a;*p = 0;return 0;
}
*p 的意思就是通过p中存放的地址,找到指向的空间, *p其实就是a变量了;所以*p = 0,这个操作符是把a改成了0
这样对a的修改,就多了⼀种的途径,写代码就会更加灵活
2_4,指针变量的大小
32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后 是1或者0,那我们把32根地址线产⽣的2进制序列当做⼀个地址,那么⼀个地址就是32个bit位,需要4 个字节才能存储。
如果指针变量是⽤来存放地址的,那么指针变的⼤⼩就得是4个字节的空间才可以。 同理64位机器,假设有64根地址线,⼀个地址就是64个⼆进制位组成的⼆进制序列,存储起来就需要 8个字节的空间,指针变的⼤⼩就是8个字节
#include <stdio.h>//32位平台下地址是32个bit位(即4个字节)//64位平台下地址是64个bit位(即8个字节)
int main()
{printf("%zd\n", sizeof(char*));printf("%zd\n", sizeof(short*));printf("%zd\n", sizeof(int*));printf("%zd\n", sizeof(double*));return 0;
}
结论:
• 32位平台下地址是32个bit位,指针变量⼤⼩是4个字节
• 64位平台下地址是64个bit位,指针变量⼤⼩是8个字节
• 注意指针变量的⼤⼩和类型是⽆关的,只要指针类型的变量,在相同的平台下,⼤⼩都是相同的
三,指针变量意义、
1,解引用符
指针的类型决定了,对指针解引⽤的时候有多⼤的权限(⼀次能操作⼏个字节)
如: char* 的指针解引⽤就只能访问⼀个字节,⽽ int* 的指针的解引⽤就能访问四个字节
2,指针+-整数
先看代码
#include <stdio.h>
int main()
{int n = 10;char* pc = (char*)&n;int* pi = &n;printf(" &n=%p\n", &n);printf(" pc=%p\n", pc);printf("pc+1=%p\n", pc + 1);printf(" pi=%p\n", pi);printf("pi+1=%p\n", pi + 1);return 0;
}
我们可以看出, char* 类型的指针变量+1跳过1个字节, int* 类型的指针变量+1跳过了4个字节。 这就是指针变量的类型差异带来的变化。
结论:指针的类型决定了指针向前或者向后⾛⼀步有多⼤(距离)
3,void* 指针
在指针类型中有⼀种特殊的类型是 void* 类型的,可以理解为⽆具体类型的指针(或者叫泛型指 针),这种类型的指针可以⽤来接受任意类型地址。但是也有局限性, void* 类型的指针不能直接进 ⾏指针的+-整数和解引⽤的运算
例:
#include <stdio.h>
int main()
{int a = 10;int* pa = &a;char* pc = &a;return 0;
}
在上⾯的代码中,将⼀个int类型的变量的地址赋值给⼀个char*类型的指针变量。编译器给出了⼀个警告,是因为类型不兼容。⽽使⽤void*类型就不会有这样的问题
例:
#include <stdio.h>
int main()
{int a = 10;void* pa = &a;void* pc = &a;*pa = 10;*pc = 0;return 0;
}
这⾥我们可以看到, void* 类型的指针可以接收不同类型的地址,但是⽆法直接进⾏指针运算
那么 void* 类型的指针到底有什么⽤呢?
⼀般 void* 类型的指针是使⽤在函数参数的部分,⽤来接收不同类型数据的地址,这样的设计可以 实现泛型编程的效果,后续会讲到;
四,小结
以上就是关于指针(1)的内容了,具体还需宝子们去实践,如果觉得该博客对你有用的话,希望一键三连,点个关注不迷路,谢谢支持!
后续马上更!后续马上更!后续马上更!