指针与动态内存

1,指针与动态内存申请的关系

释放内存是把堆区里的指针和内存端点断开,不是把值置为0;

1.1 内存四区

C语言内存四区(程序在执行的时候,内存划分为4个区域)

  • 代码区:存放函数体的二进制代码,由操作系统进行管理

  • 全局区:存放全局变量和静态变量以及常量

  • 栈区:由编译器自动分配释放,存放函数的参数值,局部变量等(先进后出)

  • 堆区:由程序员分配和释放,如果程序员不释放,程序结束后由操作系统回收释放(自由进出)

1.2申请动态内存的函数和释放内存函数

动态内存申请就是堆区内存的操作,由程序员自己申请和释放内存

C语言使用内存申请和释放函数一定要记得包含stdlib.h头文件。不包含可能会导致申请内存失败

  • malloc函数:

    void* malloc(size_t _Size);

    • _Size:申请内存字节数

    • 返回申请内存的首地址

    • 申请内存不会做初始化

  • calloc函数:

    void* calloc(size_t _Count,size_t _Size);

    • _Count:申请几个

    • _Size:每个占用字节数

    • 申请内存并且默认初始化为0

  • realloc函数:

    void* realloc(void* _Block,size_t _Size);

    • _Blcok: 重新申请内存的首地址,含原数据

    • _Size:重新申请内存大小,要大于原大小

    • 申请失败返回空, 申请成功返回申请内存首地址

  • free函数:

    void free(void* _Block);

    • _Block:释放的内存首地址

    • 同一段内存不能被重复释放

    • 哪里申请的内存就要从哪里释放,指针做了偏移一定要还原

    • 释放内存后,指针要置空,防止悬浮指针存在

1.3 断言函数 assert( )

#include<assert.h>//断言
int main()
{
   assert(false);// 判定为非的时候会让程序在这里崩掉,在申请动态内存的时候可以判定申请的是否为空,如果是就让该程序在assert()崩溃
   return 0;
}u

1.4 malloc函数

#include<stdio.h>
#include <stdlib.h>
#include<assert.h>//断言
#include<stdbool.h>
void tset_malloc()
{
    int* p = (int*)malloc(sizeof(int));//强制类型转换
    //申请一个int变量内存,首地址返回给p
    //这个是申请堆区内存
    if (p == NULL)
        exit(-1);//判断申请是否为空
    assert(p);//判断申请是否为空
    *p = 999;
    printf("%d\n", *p);
    free(p);
    p = NULL;
    
    
    //申请一段内存--->数组
    int len = 0;
    scanf_s("%d", &len);
    int* parr = (int*)malloc(sizeof(int) * len);
    assert(parr);//判断申请是否为空
    //当作产生了一个int parr[len]数组去用
    for (int i= 0; i < len; i++)
    {i
        parr[i]=i;
        printf("%d\t", parr[i]);
    }
    printf("\n");
     /*
    parr ++;不再指向你申请内存首地址回导致释放问题
    valid heap pointer
    解决办法:
    int* temp = parr;记录开始位置
    后续对指针进行偏移操作就可以进行如下释放
    free(temp);
    temp = NULL;
    */
    free(parr);
    parr = NULL;
}
int main()
{
    tset_malloc();
    assert(1);
    return 0;
}
​

malloc使用场景:

  • 处理大量数据的时候,使用malloc函数,栈区内存会溢出,堆区内存不会出现溢出问题

    int* array = (int*)malloc(size(int)*300000000);
    assert(array);
    free(array);
    array = NULL;

  • 动态数组,可以自动增长的数组

  • 函数返回指针,不会自动释放掉内存,从而解决掉返回局部变量地址的问题

    char* get_data()
    {
        char str [] = "iloveyou";
        int len = strlen(str)+1;//加一是有一个'\0'结束标记
        char* pstr = (char*)malloc(len);
        strcpy_s(pstr,len,str);
        return pstr;//在其他地方用完后就可以把pstr给释放掉
    }

1.5 calloc函数i

默认把申请的内存初始化为0

int *p = (int*)calloc(1,sizeof(int));//默认把申请的内存初始化为0
assert(p);
printf("%d\n",*p);
free(p);
p = NULL;

1.6 realloc函数

内存的自动增长

void test_realloc()
{
    int* p = (int*)realloc(sizeof(int));
    assert(p);
    *p = 123 ;
    int* temp = (int*)realloc(p,sizeof(int)*4);//做重新申请内存大小,由原来的1个内存申请到4个内存
    p = temp;//把p指向temp,必须要做的操作
    p[1] = 456;
    p[2] = 789;
    p[3] = 000;
    for (int i = 0; i < 4; i++) 
    {
        printf("%d\t", p[i]);
    }
    printf("\n");
    free(p);//置空
    p = NULL;
}

2,函数与动态内存申请

2.1一维数组的两种申请方法

//一级指针
int* create_array1D_01(int arrayNum)
{
    int* p = (int*)malloc(sizeof(int) * arrayNum);
    assert(p);
    return p;
}//在主函数中别忘了释放
//二级指针方式
void create_array1D_02(int** array, int arrayNum) 
{
    *array= (int*)malloc(sizeof(int) * arrayNum);
    assert(*array);
}
int main()
{
    int* parr = NULL;
    create_array1D_02(&parr,5);
    free(parr);//申请完后可以释放掉再次申请使用
    create_array1D_02(&parr,7);
    free(parr);
    parr = NULL;
}

2.2二维数组的申请

//一级指针可以操作多个数字,二级指针可以操作多个一级指针
int** creat_array2D_01(int row,int cols)
{
    int** p = (int**)malloc(size(int*)*row);
    for(int i = 0;i < row;i++)
    {
        //为每一个一级指针申请内存存储一段数据
        p[i] = (int*)malloc(sizeof(int) * cols);
    }
    reurn p;
}
void print_array2D(int** array, int row,int cols)
{
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < cols; j++) 
        {
            array[i][j] = i * row + j;
            printf("%d\t", array[i][j]);
        }
        printf("\n");
    }
}
int main()
{
    int** pp = create_array2D_01(2, 3);
    print_array2D(pp, 2, 3);
    free(pp);
    return 0;
}

3,函数指针

3.1基础函数指针

int Max(int a,int b)
{
    return a > b ? a : b;
}
int Sum(int a,int b)
{
    return a + b;
}
//回调函数,以函数指针为参数的函数都算是回调函数
void print_data(int(*func)(int,int),int a,int b)
{
    printf("%d\n",func(a.b));
}
​
//创建函数指针--->(*指针名)替换函数名
int (*pFunc)(int a,int b) = NULL;
int (*pFunc1)(int,int) = NULL;
*pFunc2 = NULL;
//函数指针调用函数
//用函数名或者&函数赋值直接当作函数名去用就OK
pFunc = Max;
pFunc = &Max; //推荐写法
//用法
result = pFunc(1,2);//推荐写法
result = (*pFunc)(1,2);
printf_data(Max,1,2) 
​

3.2复杂函数指针

//typedef定义函数
void test_typedf()
{
    //用定义的名字替换掉typedef语句中的名字
    //看的时候去掉typedef即可
    typedef int INT;
    INT num = 123;
    typedef int ARRAY[3];
    ARRAY arr;
    typedef int(*FUNC)(int,int);
    FUNC func = NULL;
    int* p ,q;//p是指针,q是整型变量
    p = &num;
    p = num;
    typedef int* int_point;
    int_point p1.p2;//都是int* 类型的指针
}
//返回函数指针的函数
//1.1 typedef
typedef int(*FUNC)(int ,int);
FUNC get_max(FUNC pmax,int a,int b)
{
    pmax(a,b);
    return pmax;
}
//1.2把函数名和参数写到返回函数指针的类型中*后面
// int(*)(int,int) get_max2(int(*)(int,int),int a,int b) 
int(*get_max2(int(*pmax)(int,int),int a,int b))(int,int) 
{
    pmax(a,b);
    return pmax;
}
int(*(*func)(int(*)(int,int)int ,int))(int,int) = &get_max;
int(*)(int,int)-->int(*(*func)int(*)(int,int)int,int)(int,int)//套了三层
    
//万能指针充当函数指针
void print_data
{
    printf("ddd\n");
}
void* p = &printf_data;
((void*()) p) ();
p = &get_max2;
((int(*(*)(int(*)(int,int),int ,int ))(int,int)) p) = (Max,2,3);

4,指针数组

//在后面就是什么
//数组指针
int(*p)[4] = NULL;
p = (int(*)[4])mallic(sizeof(int[4]) * 2);
for (int i = 0; i < 2; i++) 
    {
        for (int j = 0; j < 4; j++) 
        {
            p[i][j] = i * 4 + j;
            printf("%d\t", p[i][j]);
        }
        printf("\n");
    }
//指针数组
int* parr[3] = {NULL,NULL.NULL};
char* arr[3] = {"abc","ddd","aaa"};\
for (int i = 0; i < 3; i++) 
 {
     puts(pstr[i]);
 }
//函数指针数组
int(*pfunc)(int,int) = Sum;
int(*pfunc[4])(int,int) = {Sum,Sum,Sum,Sum};//里面放的是函数
int Sum(int a, int b) 
{
    return a + b;
}

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值