C语言理论篇——带你轻松玩转指针与动态分配内存

2019.12.11

1.什么是指针以及它的作用

储存数据的内存是一串连续的字节单元格,如图

C语言理论篇——带你轻松玩转指针与动态分配内存_第1张图片
内存图解.png

每一个单元格都有自己的地址,而 指针则是用来储存某个地址的变量
那么我们什么时候需要用到指针呢?下图作为引例
C语言理论篇——带你轻松玩转指针与动态分配内存_第2张图片
值改变.png

使用函数返回值可以实现 一个值的改变,而return只能返回一个值,改变两个及以上的值便需要指针
C语言理论篇——带你轻松玩转指针与动态分配内存_第3张图片
地址详解.png

说明:首地址是指第一个字节的地址,其实指针并没有如图所示的指向作用,那样画方便理解,指针就是地址,通过它可以间接访问或修改所存的地址内的值,依图举个例子,可以将0x100(地址)理解为一个小区中的房间门牌号,1(所存的值)当做租客,而指针就是保安室(登记有所有门牌号即地址),通过保安室可以查到门牌号,再使用一个*即登门拜访
一个指针所占用空间:64位系统占8个,32位系统占4个

2.指针的类型

指针的运算指针+i是指指针所指地址向右移动i*sizeof(所指向的变量类型)
指针之间还可以作减法,仅限于数组内,作差的结果是两个地址间相差的元素个数
整型指针:int *a
字符指针:char *a
指针数组:int *a[5],一个大小为5,每个元素都是指针
数组指针:int (*a)[5] 只能指向二维数组,且二维数组中的一维数组长度为5
如int a[3][5];
 int (*p)[5]=a;
常量指针:指向地址的值不能改变
int a=20,b=30;
int const *p=&a;const(常量)在前
*p=&b;//可以改变指针的指向关系
指针常量:指向关系不能变,值可以变
int *const p1=&a;*指针在前
*p1=50;//可以改变里面的值
谁在前谁不变
二级指针: int**p;里面存的是一个一级指针的地址,指针本身是有地址的

C语言理论篇——带你轻松玩转指针与动态分配内存_第4张图片
二级指针图解.png

二级以上的指针如图类推
指针函数:int *add(); 先忽略*,add()是个函数,它的返回类型是int*指针(即地址)
函数指针:int (*p)(int ,int); 由于()的优先级更高,所以无法先忽略*,所以从*开始读,是一个指针,它指向的类型是一个函数,函数的返回类型是整型
函数名其实是一个指针常量,它指向该函数代码的首地址
int minus(a,b);
p=minus;
(*p)(a,b);等价于minus(a,b)

☆补充说明:相信很多初学指针的小伙伴都有这样的一个困惑,指针只能用地址来赋值,为什么 常量字符串可以使用 char* name="xiaoming",常量字符串为什么可以这样赋值,其实啊, 真正赋值给name的还是一个地址双引号" "做了以下三件事:
1.在内存中开辟了一片连续的空间
2.将常量字符串放进去,并在末尾添加\0
3.最后返回那一片连续内存空间的 首地址
所以常量字符串的赋值不需要使用malloc为字符指针分配内存空间,直接使用双引号即可,这样的表达是没有任何问题的,这是指针中容易搞混的地方

3.指针和数组的关系

1.指针与一维数组之间可以相互转换,数组名是数组的首地址,可以直接赋给指针

C语言理论篇——带你轻松玩转指针与动态分配内存_第5张图片
指针与数组的转换.png

被注释掉的输出结果一样
数组是指针常量,所以不能对首地址进行自增(++)或自减(--)运算,本质上是不能对首地址赋值如a=a+1而*(a+1)则是正确的,数组地址移动方式和指针是相同的,a+i其实是a+i*sizeof(数组类型),所以对首地址先进行移动,然后再显示新地址内的值
C语言理论篇——带你轻松玩转指针与动态分配内存_第6张图片
指针移动等同数组.png

所以其实a[i]等价于*(a+i)
2. 数组指针:数组指针是二维的,(只能说)类似于二级指针,要访问里面的单个元素,需要使用**
先定义一个数组指针
int a[2][3]={{1,2,3},{4,5,6}};int (*p)[3]=a;
C语言理论篇——带你轻松玩转指针与动态分配内存_第7张图片
数组指针图解.png

而对p+1则是纵向的移动,移动到4所在地址
C语言理论篇——带你轻松玩转指针与动态分配内存_第8张图片
数组指针.png

上图则是运行效果
也可以换一种方式理解为什么需要两个**:前面提到一维数组等价于指针,所以二维数组就相当于一维数组里的元素全是指针,*p访问到第一个元素还是指针即地址,所以还需要一个*才能访问到真正的第一个元素

4.动态分配内存

常量区 常量 const int a=1;程序结束时释放
静态区 static 直到程序结束才会被释放内存
静态变量只会被初始化一次,生命周期从开始(预编译)到程序结束为止
栈 局部变量 int a=10;作用于代码块,出了代码块就释放
堆 自己申请的内存(malloc calloc realloc) 必须自己释放内存
为什么需要分配内存:
1.存储的数据需要延长生命周期
2.一个指针变量需要存储数据,变量本身只能存地址,不能存数据,需要分配内存空间来存储数据,必须为指针变量分配内存空间,用malloc,引入stdlib.h
如何分配内存
char *name;
name=(char *)malloc(10*sizeof(char));
格式:malloc(需要对应数据类型空间的数量*sizeof(对应的数据类型)),前面需要对其声明,(数据类型*)
动态分配内存的本质:malloc函数在内存中申请了一片连续指定大小的空间单元格,然后返回那片连续单元格的首地址
name=(char*)realloc(name,20*sizeofz(char))//重新分配已经分配的动态内存
格式:realloc(需要重新分配的指针名,对应数据类型空间的数量*sizeof(对应的数据类型))
为了不浪费空间,程序结束之间需要释放申请的内存,free(name);
以上具体的使用会在实战篇中体现

你可能感兴趣的:(C语言理论篇——带你轻松玩转指针与动态分配内存)