栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C语言学习笔记——(三)静态开辟内存和动态开辟内存

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C语言学习笔记——(三)静态开辟内存和动态开辟内存

注:编码工具是CLion+Cygwin64

目录

补充知识:C语言的布尔类型——非零即true。

静态开辟内存

静态开辟内存上限测试:

静态开辟内存特点:

静态开辟内存自动开辟和自动释放测试:

动态开辟内存

动态开辟内存特点:

动态开辟内存的使用场景:

动态开辟的内存未回收示例:

动态开辟的内存用完回收示例:

realloc


补充知识:C语言的布尔类型——非零即true。

NULL==0。

#include 

int main(){
    int i = 99;
    if(i){
        printf("%d is truen", i);
    }else{
        printf("%d is falsen", i);
    }

    char * str = "string";
    if(str)
    {
        printf("%s is truen", str);
    }else{
        printf("%s is falsen", str);
    }

    char c = ' ';
    if(c)
    {
        printf("'%c' is truen", c);
    }else{
        printf("'%c' is falsen", c);
    }

    if(NULL)
    {
        printf("NULL is truen");
    }else{
        printf("NULL is falsen");
    }

    if(0)
    {
        printf("0 is truen");
    }else{
        printf("0 is falsen");
    }
    return 0;
}

输出:

99 is true
string is true
' ' is true
NULL is false
0 is false

静态开辟内存

        在函数体中不用xxalloc系列函数开辟内存定义的变量都是静态开辟内存,静态开辟内存是在栈中开辟。静态开辟内存的上限比较小,一般用于定义内存占用比较小的不需要动态改变内存空间大小的变量。

静态开辟内存上限测试:
#include 

// 环境 64位CLion + Cygwin64
int main(){
//    int arr[10 * 1024 * 1024];// 40M 超出栈内存上限
//    int arr[1024 * 1024];// 4M超出栈内存上限
//    int arr[512 * 1024];// 2M超出栈内存上限
    int arr[256 * 1024]; // 1M 正常开辟内存
    printf("sizeof arr is %dn", sizeof arr);
    return 0;
}

输出:

sizeof arr is 1048576

静态开辟内存特点:

        函数入栈时,自动开辟函数内部变量所需内存,函数出栈时,自动释放函数内部变量所占的内存。因此不需要担心内存泄漏和内存溢出问题。所以一般情况下,如果静态开辟内存方式满足程序所需,应该尽量用此种方式定义和使用变量。

静态开辟内存自动开辟和自动释放测试:
#include 
#include 

void staticAllocation(){
    int arr[256 * 1024];
    printf("staticAllocation run...n");
}

int main(){
    while(1)
    {
        Sleep(100);
        staticAllocation();
    }
    return 0;
}

输出:

staticAllocation run...
staticAllocation run...
...

动态开辟内存

        动态开辟内存需要调用xxalloc系列函数,需要引入stdlib头文件,具体如:

#include 
#include 

int main() {
    int *arr = malloc(sizeof(int) * 8);
    if (arr) {
        int i;
        for (i = 0; i < 8; i++) {
            arr[i] = i + 10001;
        }
        for (i = 0; i < 8; i++) {
            printf("第%d个数是:%dn", i + 1, *(arr + i));
        }

        free(arr);
        arr = NULL;
    }
    return 0;
}

输出:

第1个数是:10001
第2个数是:10002
第3个数是:10003
第4个数是:10004
第5个数是:10005
第6个数是:10006
第7个数是:10007
第8个数是:10008

动态开辟内存特点:

        1、动态开辟内存是在堆上开辟内存,所以内存可用上限比静态开辟内存方式大得多,所以一般定义占用大内存空间的变量使用此种方式。

        2、用动态开辟内存方式开辟的内存空间,不会自动释放,需要调用free函数手动释放。如果变量不需要使用后没有手动释放,那块内存会一直存在,且不能被使用,造成内存泄漏,如果这种内存块累积过多,就可能造成内存溢出。

        3、用动态开辟内存方式开辟的内存空间,不能重复调用free函数释放。

        4、内存释放后,需要将对应的指针类型变量置为NULL,否则将生成悬空指针(虽然指针保存的内存地址所对应的内存被释放了,但是内存地址值依然保存在指针中)。

悬空指针和野指针:

        悬空指针是指动态开辟的内存被回收后,存放该内存地址的指针变量依然保存该内存地址值,但是那块内存已经被释放不能使用了。

        野指针是指定义一个指针类型变量但没有赋值内存地址给它,此时该变量可能指向系统的任意内存区域。所以一般出现这种情况,应该要么用&运算符赋一个内存地址给该变量,要么赋NULL给该变量,要么用xxalloc系列函数动态开辟一块内存并将内存地址给该变量,或者用其他我不知道的方式给该变量赋一个安全的值。

动态开辟内存的使用场景:

        1、内存空间大小需要动态改变的场景;

        2、开辟大内存空间。

动态开辟的内存未回收示例:
#include 
#include 
#include 

void dynamicAllocation(){
    int * arr = malloc(1024 * 1024);
}

int main() {
    while(1){
        Sleep(100);
        dynamicAllocation();
    }
    return 0;
}

动态开辟的内存用完回收示例:
#include 
#include 
#include 

void dynamicAllocation(){
    int * arr = malloc(1024 * 1024);
    if(arr){
        free(arr);
        arr = NULL;
    }
}

int main() {
    while(1){
        Sleep(100);
        dynamicAllocation();
    }
    return 0;
}

realloc

        注意:动态开辟内存可能失败,所以在使用之前,应该先判空。

#include 
#include 
#include 

int main() {
    printf("请输入要保存的数的个数:");
    int num_count;
    scanf("%d", &num_count);
    int i;
    int *arr = malloc(sizeof(int) * num_count);
    if (arr) {
        for (i = 0; i < num_count; i++) {
            *(arr + i) = 10001 + i;
        }
        for (i = 0; i < num_count; i++) {
            printf("第%d个数是%dn", i + 1, arr[i]);
        }

        printf("------------------------------------n");
        printf("请输入要增加的数的个数:");
        int new_num_count;
        scanf("%d", &new_num_count);
        int * new_arr = realloc(arr, sizeof(int) * (num_count + new_num_count));

        if(new_arr)
        {
            for(i = num_count; i < new_num_count + num_count; i ++){
                *(new_arr + i) = 10001 + i;
            }
            for (i = 0; i < new_num_count + num_count; i++) {
                printf("第%d个数是%dn", i + 1, new_arr[i]);
            }
            printf("arr的值是%p, new_arr的值是%pn", arr, new_arr);
            free(new_arr);
            arr = NULL;
            new_arr = NULL;
        }else if(arr)
        {
            free(arr);
            arr = NULL;
        }

    }
    return 0;
}

输出:

请输入要保存的数的个数:4
第1个数是10001
第2个数是10002
第3个数是10003
第4个数是10004
------------------------------------
请输入要增加的数的个数:4
第1个数是10001
第2个数是10002
第3个数是10003
第4个数是10004
第5个数是10005
第6个数是10006
第7个数是10007
第8个数是10008
arr的值是0x8000389d0, new_arr的值是0x8000389d0

Process finished with exit code 0

        realloc原理:如果arr后面有足够的内存空间,则直接申请arr后面的内存空间,并将两块内存空间合为一块,将空间的地址赋值给new_arr;如果没有足够的内存空间,则重新申请一块足够的内存空间,将空间的地址赋值给new_arr,并将之前arr中的数据复制到新开辟的内存空间的前面部分。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/384255.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号