第十课
1,指针运算
算术运算:指针是一个用数值表示的地址。可以进行四种算术运算:++ -- + -
//指针的每一次递增,它就会指向下一个元素的存储单元
//指针的每一次递减,它就会指向前一个元素的存储单元
//指针在递增和递减时,跳跃的字节数(步长),取决于指针所指向变量数据类型长度。
关系运算:指针可以用关系运算符进行比较,如:== < >
【注意:如果p1和p2指向两个相关的变量,比如在同一个数组,则可对p1和p2比较大小】
//对相关变量的指针进行比较,才有意义
//大于小于常用于数组,全等一般用于判断指针是否为NULL
2,动态内存分配
动态内存:指在堆空间分配内存【注意:静态内存指的是在栈空间分配内存】
//局部变量、形参是在栈上分配的,自动申请和释放//动态内存需要自己手动分配和释放
动态内存分配的意义:
//C语言中的一切操作都是基于内存的
//变量和数组都是内存的别名
//定义数组时,必须指定数组的大小,使用动态内存分配可以在运行时调整大小
//函数结束之后,不希望变量的内存被释放
3,动态内存分配方法
【注意:不要改变动态内存分配了的指针的指向】
1,首先包含stdlib.h头文件
2,使用函数
·malloc void* malloc(size_t _Size);
//功能:在堆区申请大小为size字节的连续内存【注意:不会对内存进行初始化】
//返回值:返回内存空间的首地址,申请失败返回NULL
例子:
#include<stdlib.h>
#include<stdio.h>
#include<string.h>//包含memset函数
int main()
{
int* pn=(int*)malloc(sizeof(int)*5);
if(pn==NULL)
{
return -1;
}
memset(pn,0,sizeof(int)*5);//将动态内存分配的空间全部初始化为0
...
free(pn);
pn=NULL;
}
·calloc void* calloc(size_t _Count,size_t _Size);
//功能:和malloc相同,申请count个大小为size的连续内存,【并把内存全部初始化为0】
//返回值:返回内存空间的首地址,申请失败返回NULL
例子:
#include<stdlib.h>
#include<stdio.h>
int main()
{
int* pn=(int*)calloc(3,sizeof(int));//自动初始化为0
if(pn==NULL)
{
return -1;
}
...
free(pn);
pn=NULL;
}
·realloc void* realloc(void* _Black,size_t _Size);
//功能:把用以上两个函数申请的内存(_Black指向的),重新申请大小(size);
//如果size大于原内存的大小,则新分配的内存不会初始化;如果size小于原内存大小,会导致数据丢失
返回值:返回内存空间的首地址,申请失败返回NULL
例子:
#include<stdlib.h>
#include<stdio.h>
#include<string.h>//包含memset函数
int main()
{
int* pn=(int*)malloc(sizeof(int)*5);
if(pn==NULL)
{
return -1;
}
memset(pn,0,sizeof(int)*5);//将动态内存分配的空间全部初始化为0
//如果还需添加内存
if(!realloc(pn,sizeof(int)*6))
{
return -1;
}
*(pn + 5)=3;//给新分配的内存初始化
...
free(pn);
pn=NULL;
}
·free void free(void* _Block);
//功能:释放malloc、calloc或realloc申请的内存。如果传递的参数是一个空指针,则不会执行任何操作
注意事项:
//申请之后一定要记得释放,否则会导致内存泄漏
//不要重复释放同一内存
//释放之后。一般会把指针置为NULL(可以避免释放后误用)
3,memset void* memset(void* _Dst,int _val,size_t _Size);
//功能:作用是在一段内存块中填充val这个值//常用来清零操作
//参数:dst表示要初始化的内存;val表示对每个字节填充的值;size表示总共初始化多少个字节数
4,memcpy void* memcpy(void* _Dst,void const* _Src,size_t _Size);
//功能:和strcpy类似,memcpy用于内存拷贝,size表示要拷贝的字节数
4,大端模式和小端模式
大端和小端:表示数据在存储器中的存放顺序;
高位 | 0x12345678 | 低位 |
大端模式:数据的高字节保存在内存的低地址中,数据的低字节保存在内存的高地址中;
//该存储模式类似于把数据当作字符串处理:地址由小向大增加,数据从高位往低位存放
大端模式图:
大端模式: | 低地址 | 12 | 34 | 56 | 78 | 高地址 |
小端模式:数据的高字节保存在内存的高地址中,数据的低字节保存在内存的低地址中;
//该模式将地址的高低和数据位权有效结合,高地址部分权值高,低地址部分权值低
小端模式图:
小端模式: | 低地址 | 78 | 56 | 34 | 12 | 高地址 |
5,typedef
1,typedef是给类型取别名
2,定义:
typedef 类型 别名;
//typedef int INT;INT就是我们定义的新类型名
//typedef int(*PARR)[5];PARR就是定义的数组指针类型
//typedef void(*PFUNA)(int a);
6,数组指针
定义方式:
数据类型 (*变量名)[size];//是一个指针,指向一个数组
7,指针数组
定义方式:
数据类型* 变量名[size];//数组里存的都是指针
8,二维数组指针
1,最大存储单元:一个指向一维数组的指针
例子:
int a[2][3]={0};
int(*p)[3]=a;//二维数组指针,指向的是第一个一维数组的首地址//这里的3表示一维数组的元素个数
10,指针函数
指针函数:返回值为指针类型的函数;
注意:
//不要返回临时变量的地址
//可以返回静态变量(全局变量)的地址//生命周期长
//可以返回动态申请的空间的地址;如:malloc(存在于堆区,不会自动释放)