美文网首页
C语言-3、堆栈、野指针、悬空指针、动态开辟

C语言-3、堆栈、野指针、悬空指针、动态开辟

作者: 喂_balabala | 来源:发表于2022-07-12 19:52 被阅读0次
  • 栈区:占用内存大小 最大值: 大概 2M 大于2M会栈溢出 跟平台有关系
  • 堆区:占用内存大小 最大值: 大概80% 40M没有任何问题,基本上不用担心 堆区很大的
  • 大概80%: Windows系统 给我们的编译器给予的空间 的 百分之百八十
开辟栈区
#include <stdio.h>
#include <unistd.h> // 小写的

// 函数进栈 定义一个int arr[5];  定义一个 int i;  (静态的范畴)

// 进栈
void staticAction() {
    int arr[5]; // 静态开辟 栈区 (栈成员)

    for (int i = 0; i <5; ++i) {
        arr[i] = i;
        printf("%d, %p\n", *(arr + i), arr + i);
    }
} // 函数的末尾会弹栈(隐式):执行完毕会弹栈  会释放所有的栈成员

// 2.静态开辟。
int mainT3() {
    // int 4 * 10 = 40M
    // int arr[10 * 1024 * 1024]; // 10M * 4 = 40M  会栈溢出

    // int arr[1 * 1024 * 1024]; 会栈溢出

    int arr[(int)(0.2 * 1024 * 1024)]; //  不会栈溢出

    while (9) {
        sleep(100);
        staticAction(); // 调用开辟20
    }

    return (0);
}

开辟堆区
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // 小写的

/// 函数进栈 定义一个int arr[5];  定义一个 int i;  (静态的范畴)

// malloc 在堆区开辟的内存空间 , (动态的范畴)

// C的开发过程中,不能出现,野指针,悬空指针
void dynamicAction() {
    int * p; // 野指针  没有地址的,空的

    // void * 可以任意转变   int*  double *
    int * arr = malloc(1 * 1024 * 1024); // 堆区开辟 1M

    printf("dynamicAction函数,arr自己的内存地址:%p,堆区开辟的内存地址:%p\n", &arr, arr);

    // C工程师,堆区开辟的空间,必须释放
    free(arr); // 释放掉
    arr = NULL; // 重新指向一块内存地址00000

    printf("dynamicAction函数2 堆区开辟的内存地址:%p\n", arr); // 悬空指针
}

int mainT1() {

    while (9) {
        // sleep(100);
        dynamicAction(); 
    }

    return 0;
}
动态开辟的使用的场景
#include <stdio.h>
#include <stdlib.h>

int mainT2() {
    // 静态开辟的内存空间大小,是不能修改的,如果不需要动态修改空间大小,当然使用 栈区 【尽量使用 静态开辟的,如果实在是需要动态改变,才使用下面
    // int arr [6];
    // ===================================  下面是 动态开内存的使用场景

    // 开辟的空间 想要变化, 动态范畴

    int num;
    printf("请输入数的个数:");

    // 获取用户输入的值
    scanf("%d", &num);

    // 动态开辟 用户输入的值 空间的大小   【堆区】
    int * arr = malloc(sizeof(int) * num);
    // int arr2 []   ==   int * arr  一样的了

    int print_num;
    // 循环接收
    for (int i = 0; i < num; ++i) {
        printf("请输入第%d个的值:", i);

        // 获取用户输入的值
        scanf("%d", &print_num);

        arr[i] = print_num;
        printf("每个元素的值:%d, 每个元素的地址:%p\n", *(arr + i), arr + i);
    }

    // for 循环打印
    for (int i = 0; i < num; ++i) {
        printf("输出元素结果是:%d\n", arr[i]); // arr[i] 隐士 等价与 * (arr + i)
    }

    getchar();

    return 0;
}

动态开辟之realloc
#include <stdio.h>
#include <stdlib.h>

// 动态开辟之realloc
int main() {

    int num;
    printf("请输入个数");
    // 获取用户输入的值
    scanf("%d", &num);

    // 5个值
    int * arr = (int *) malloc(sizeof(int) * num);
    for (int i = 0; i < num; ++i) {
        arr[i] = (i + 10001); // arr[i]的内部隐士 == *(arr+i)
    }
    printf("开辟的内存指针: %p\n", arr);

    // 打印 内容
    for (int i = 0; i < num; ++i) {
        // 装B的打印
        // &取出内存地址 *然后取值
        // &取出内存地址 *然后取值
        // &取出内存地址 *然后取值
        // .....
        printf("元素的值:%d, 元素的地址:%p\n",
               *&*&*&*&*&*&*&*&
                       *&*&*&*&*&*&*&*&*&
                               *&*&*&*&*&*&*&*&
                                       *&*&*&*&*&*&*&*&
                                               *&*&*&*&*&*&*&*&
                                                       *&*&*&*&
               *&*(arr + i)
               ,
               (arr + i)
               );
    }




    // =================================   在堆区开辟新的空间  加长空间大小

    // C的岗位
    // C工程师的面试题:  realloc 为什么一定要传入 arr指针,为什么要传总大小

    // 新增
    int new_num;
    printf("请输入新增加的个数");
    scanf("%d", &new_num);

    // 原来的大小4 + 新增加的大小4  =  总大小 8
    // void *realloc (void *前面开辟的指针, size_t总大小);
    int * new_arr = (int *) realloc(arr, sizeof(int) * (num + new_num));

    if (new_arr) { // new_arr != NULL 我才进if  【非0即true】
        int j = num; // 4开始
        for (; j < (num + new_num); j++) { // 5 6 7 8
            arr[j] = (j + 10001);
        }

        printf("新 开辟的内存指针: %p\n", new_arr);

        // 后 打印 内容
        for (int i = 0; i < (num + new_num); ++i) {

            printf("新 元素的值:%d, 元素的地址:%p\n",
                   *(arr + i),
                   (arr + i)
            );
        }
    }

    // 我已经释放
    free(new_arr);
    new_arr = NULL;

    // 1000行代码
    // 。。。

    //  重复释放/重复free VS会奔溃,   CLion会优化(发现不奔溃)   [错误的写法]
    /*free(new_arr);
    new_arr = NULL;*/

    // 必须释放【规则】
    /*if (arr) {
        free(arr);   // 如果不赋值给NULL,就是悬空指针了
        arr = NULL;
    }*/

    if (new_arr) {// new_arr != NULL 进去if, 重新开辟的堆空间是成功的
        free(new_arr);   // 如果不赋值给NULL,就是悬空指针了
        new_arr = NULL;
        arr = NULL; // 他还在指向那块空间,为了不出现悬空指针,指向NULL的空间
    } else { // 重新开辟的堆空间是失败的
        free(arr);
        arr = NULL;
    }

    return 0;
}

Question

realloc 为什么一定要传入 arr指针
  • 因为realloc可能会遇到后面的空间被系统或者其他地方占用了,这个时候就系统会重新找个地方开辟新的空间,这个时候就需要arr指针,拷贝arr的数据到新的空间,再返回回来。
realloc 为什么一定要传入总大小
  • 因为假如后面的空间被占用了,要找新的地方,这个时候要知道新的地方需要开辟多少空间
realloc返回的指针为什么要判空
  • 因为某些异常情况会导致返回的是空指针

总结

  • free和置null一定要成对出现,养成习惯
  • 指针不能被重复释放

相关文章

  • C语言-3、堆栈、野指针、悬空指针、动态开辟

    栈区:占用内存大小 最大值: 大概 2M 大于2M会栈溢出 跟平台有关系 堆区:占用内存大小 最大值: 大概8...

  • 什么是野指针?什么是僵尸对象?

    野指针与僵尸对象 1. 野指针 1>C语言中的野指针:一个指针变量指向一块随机的空间,这个指针就是野指针当我们声明...

  • crash之野指针

    例子一 堆栈信息 根据堆栈分析:1,野指针2,有对应的堆栈查看堆栈代码,看那些有可能野指针: 分析所有参数:url...

  • Xcode崩溃原因汇总

    调用野指针 野指针定义:C语言: 当我们声明1个指针变量,没有为这个指针变量赋初始值.这个指针变量的值是1个垃圾指...

  • 如何Check僵尸对象

    野指针和僵尸对象 野指针: C语言:当我们声明一个指针变量,没有为这个指针变量赋初始值,这个指针变量的值是一个垃圾...

  • C基础-数组指针操作、内存开辟、函数指针和结构体

    数组指针操作的常用几种方式 内存开辟 静态开辟 *动态内存开辟和释放 函数指针(常用于回调) 结构体、结构体指针别...

  • 02-C语言的指针

    02-C语言的指针 目标 C语言指针释义 指针用法 指针与数组 指针与函数的参数 二级指针 函数指针 指针在C中很...

  • C语言05- 指针

    C语言05- 指针 13:指针 指针是C语言中的精华,也是C语言程序的重点和难点。 13.1:指针定义与使用 指针...

  • 指针的一些概念总结

    野指针:未初始化的指针悬空指针:指向的地址被free之后,未被置为null的指针(又叫迷途指针) 溢出:申请了10...

  • iOS assign,weak,strong等属性和引用计数

    先介绍指针相关的几个概念(看有的书上介绍下面的未初始化的叫野指针,野指针叫悬空指针,可能和其它平台理解有所差异,但...

网友评论

      本文标题:C语言-3、堆栈、野指针、悬空指针、动态开辟

      本文链接:https://www.haomeiwen.com/subject/psbabrtx.html