1、内存那些事儿
物理内存:计算机设备中的
存储固件
。虚拟内存:操作系统虚拟出来的内存,当一个进程被创建或者程序运行的时候都会分配虚拟内存;由
操作系统
实现物理内存
和虚拟内存
之间的映射。虚拟内分配机制:内存(线性空间),以字节为单位,每字节都会有独一无二的地址,地址呈线性增长。数据在内存中是以
大、小端字节序
的方式存储。
- 基本数据类型(int、short):以小端或大断方式存储。
- 数组类型:在内存中会为数组分配一块连续的内存空间,按顺序存储。(数组中的基本数据类型,根据小端或大端存储,而数组元素按顺序存储)
注意:在32位系统下,每个进程的寻址范围是4G,0x00 00 00 00 ~ 0xff ff ff ff。
了解更多: 动态内存DRAM和静态内存SRAM
2、指针
指针就是
地址
(虚拟内存中的地址)。
3、指针变量
是个变量,用来存放一个
地址编号
,该地址编号
是其它数据单元(变量
/数组
/结构体
/函数
等)的首地址。若指针存放了某个数据单元的首地址,则这个指针指向了这个数据单元,若指针存放的值是0,则这个指针为空指针。
4、指针大小
在32位系统下,所有类型的指针都是
4个字节
。
5、指针和变量的关系
在程序中,引用变量的方法
- 直接通过变量的名称
int a;
a = 100;也可以通过指针变量
int *p; // 定义一个指针变量,*修饰p是个指针变量
p = &a; // 取的地址给 p赋值,p保存了a的地址,也可说p指向了a
*p = 100;// 在调用的时候*是取值的意思,*指针变量 等价于 指针指向的变量
6、指针的运算
6.1、指针可以加一个整数,往上指几个它指向的变量,结果还是个地址
int array[] = "hello";
int *point = array;// c语言规定:数组名
是数组的首地址
,此时point指向数组的首地址,也是第 0 个元素的地址
point += 1;// 移动指针地址(最终移动的字节数和指针变量的类型有关)
printf("point = %p\n",point);// 输出结果为数组元素‘e’的地址(和大小端有关也存在一定关系)
6.2、两个相同类型指针可以比较大小
前提:只有
两个相同类型的指针
指向同一个数组元素
的时候,比较大小才有意义;指向前面元素的指针
小于指向后面元素的指针
;
6.3、两个相同类型的指针可以做减法
前提:必须是
两个相同类型的指针
指向同一个数组的元素
的时候,做减法才有意义;做减法的结果是,两个指针指向的中间有多少个元素。
6.4、两个相同类型的指针可以相互赋值
注意:
1、只有相同类型的指针才可以相互赋值(void *类型的除外)。
2、如果类型不同的指针想要互相赋值,必须进行强制类型转换。
6.5、指针操作方式总结
指针操作方式:
取地址
、取内容
、加
、减
等。
7、指针 和 数组的关系
1、
指针
可以保存数组元素的地址
。
2、可以定义一个数组,数组中有若干个相同类型的指针变量
,这个数组被称为指针数组
。
8、指针数组
指针数组:本身是个数组,是指针数组,是
若干个相同类型的指针变量构成的集合
。其数组名
即为指向该数据类型的指针
,数组的定义等效于
申请内存、定义指针和初始化。
例1:(申请内存、定义指针和初始化)
char a[ ] = {0x33, 0x34, 0x35};
等效于:
- 申请内存;
- 定义 char *a = 0x4000;
- 初始化数组;
例2:(利用下标引用数组数据也等效于指针取内容.)
- a[0]; 等效于 *a;
- a[1]; 等效于 *(a+1);
a[2]; 等效于 *(a+2);
9、指针的指针:即指针的地址
int a; // 定义一个变量a
int *p;// 定义一个指针变量p,即一级指针,保存普通变量的地址
(指针变量本身占4个字节)
p = &a;// 将普通变量a的地址
赋值给指针变量p
此时:*p == a
int **pp;// 定义一个
指针的指针变量pp
(二级指针:保存一级指针的地址)
pp = &p;// 将指针变量p
赋值给指针的指针变量pp
此时:
*pp == p
*(*pp) == *p == a
int ***ppp;// 定义一个三级指针(三级指针:保存二级指针)
ppp = &pp;
此时:*(*(*ppp)) == a
⚠️注意:p、pp、ppp都是指针变量,都占4个字节,都存放地址编号,只是类型不同
10、指针和字符串
字符串:以
\0
结尾的若干字符的集合。
字符串的存储形式:数组
、字符串指针
、堆
char string[100] = "Hello world!";
定义并初始化字符数组
string,来存储"Hello world!"字符集合,该字符集合是存储在string这个变量中的。可动态修改
字符串内容。char *string = "Hello world!";
定义并初始化一个指针变量
string,因为char只占一个字节,只能存放字符地址编号,所以"Hello world!"字符集合不能存放在string指针变量中。此时这里string指针变量只是存放了字符‘H’的地址编号,"Hello world!"字符集合存放在内存的文字常量区。不可动态
修改字符串内容。char *string = (char *)malloc(13 * sizeof(char));
strcpy(string, "Hello world!")
动态申请 13(12个字符 + 1个\0
结尾字符) 个字节的存储空间
,将首地址
赋值给指针变量
string。最后将字符串"Hello world!"拷贝到string指向的内存空间。可动态修改
字符串内容。拓展:
char *string = "Hello world!";
字符数组
:在内存(栈、静态全局区)中开辟了一段空间存放字符串。
字符串指针
:在文字常量区开辟了一段空间存放字符串,将字符串的首地址赋值给字符指针。
堆
:使用malloc函数在堆区申请空间,将字符串拷贝到堆区
创建操作局部变量时,可使用字符数组;创建使用全局变量时,可在堆区申请内存使用,堆区内存要手动申请、手动释放;⚠️ 注意:字符串的
可修改性
1、栈和全局区中的内存是可以修改的。
2、文字常量区的内存是不可修改的。
3、堆区的内容是可以修改的