首页 > 系统相关 >C语言-动态内存管理(二)

C语言-动态内存管理(二)

时间:2023-12-03 22:05:02浏览次数:35  
标签:10 return 管理 int free C语言 动态内存 空间 NULL

第二部分主要是常见的动态内存错误

动态内存错误


1.对NULL指针的解引用操作

对NULL指针的解引用操作,什么意思呢?有些同学写代码的时候比较冲动,如下:

int main(){
    int *p= (int *)malloc(40);
    for (int i = 0; i < 10; ++i) {
        *(p+1)=i;

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

一般我们开辟空间并进行赋值的时候会去这样写,看似申请了空间也初始化了也释放了,没有问题。但是,如果开辟空间失败了呢?如果没有申请到这4个字节的空间呢?那么此时p就被赋值为NULL了

所以for循环中p为NULL 不管加1还是加2 或者加n都是非法地址,对非法地址解引用是不是就出现问题了?

所以这里一定要对p进行判断。

int main(){
    int *p= (int *)malloc(40);
    if (p!=NULL){//在这里加上对p的是否为NULL判断。
        for (int i = 0; i < 10; ++i) {
            *(p+1)=i;

        }
    }else{
        printf("%s\n", strerror(errno));
    }

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


2.对动态开辟空间的越界访问

我们看下面这个例子

int main(){
    int *p=(int *) malloc(5*sizeof (int));
    if (p==NULL){
        return 0;
    } else{
        for (int i = 0; i < 10; ++i) {
            *(p+i)=i;
        }
    }
    free(p);
    p=NULL;
    return 0;
}

输出结果:

C语言-动态内存管理(二)_初始化

大眼一瞅好像没什么问题,也判断p是否为NULL了也释放空间了。并且赋值了10个输出了10个数好像也没有报错。我这里没有报错是因为我的编译器以及我开辟的这片空间后面刚好可以满足继续越界访问。但是这是非法操作。换个机器换个编译器可能程序就要崩溃或者报错的。

但是 我们要注意:在申请空间的时候只申请了5个int类型变量大小的空间,也就是20个字节,但是你在使用的时候循环赋值,赋值了10次,也就是对10个int类型变量进行赋值,那空间明明没有那么大,你却要这样操作,这就出现了越界访问。


3.对非动态开辟内存使用free释放

举个例子:

 有的同学写代码写迷糊了,在栈区开辟的空间,最后也适用free给释放掉了。

int main(){
    int a=10;
    int *p=&a;
    *p=20;
    free(p);
    p=NULL;
    return 0;
}

输出结果为

C语言-动态内存管理(二)_动态内存_02

注意 a这个空间是在栈区申请的一段空间,而free函数是对堆区空间的释放。如果这样执行,程序就会报错。


4.使用free释放动态开辟内存的一部分

我们先看下面这个代码

int main(){
    int *p= (int *)malloc(40);
    if (p==NULL){

        return 0;
    }
    for (int i = 0; i < 10; ++i) {
        *p++=i;
    }
    //回收空间
    free(p);
    p=NULL;
}

看似逻辑是申请了40个字节的空间,然后对这是个int类型进行初始化,然后也判断是否申请成功,也执行空间回收了,但是我们看一下运行结果。

报了一个错误:

C语言-动态内存管理(二)_动态内存_03

那么这里是为什么会出现这种情况呢?

C语言-动态内存管理(二)_动态内存_04

我简单画了个示意图,我们看到

 *p++=i;

这行代码起始改变了p这个指针的位置,如果我们初始化完毕之后,p已经指向最后一个数字的后面的地址了,如果此时在进行释放p的空间的话,已经不是我们原本申请的40个字节了。只要不是指向最初的位置,无论p指向哪都只是空间的一部分,所以不能使用free。

所以我们只能使用:

*(p+i)=i

这种方式可以正常赋值。因为它并没有改变p的指针指的位置。

5.对同一块动态内存的多次释放

我们看下面这段代码:

int main(){
    int *p=(int*) malloc(40);
    if (p==NULL){
        
        return 0;
    }
    free(p);
    free(p);
    p=NULL;
    return 0;
}

申请了一段内存空间,然后对这段空间释放了两次。就会报错:

C语言-动态内存管理(二)_动态内存_05

显示第二次释放的空间还没有被分配。所以对空间的回收要遵守:谁开辟谁回收的原则。

另外在释放之后将p赋值为NULL也可以避免这种情况。


6.忘记释放动态开辟的空间(内存泄漏)

int main(){

    while (1){
        malloc(1);
       // Sleep(1000);
    }
    return 0;
}

执行这段代码,我们可以从任务管理器中直观的看到你的内存正在不断被占用,内存使用会变的越来越大。这个会出现死机的风险的。就是因为只开辟空间而不回收你开辟的空间造成的。

切记:动态开辟的空间一定要释放,并且正确释放

这就是内存泄漏。

总结

这就是C语言动态内存管理的第二部分的内容,主要是总结一些,代码上常见的错误,这六种错误需要小心。

下一个部分的内容准备出一些经典的面试题有关C语言动态内存管理相关的。


标签:10,return,管理,int,free,C语言,动态内存,空间,NULL
From: https://blog.51cto.com/u_16160587/8669067

相关文章

  • 第5章进程管理
    一、进程组成部分:已分配内存的地址空间安全属性,包括所有权凭据和特权程序代码的一个或多个执行线程进程状态每个进程都有唯一的进程标识PID,一个PID只能标识一个进程,PPID为父进程ID,需要给该进程分配系统资源。进程状态:就绪态:进程已经具备运行条件,但是CPU还没有分配过来。......
  • 文件管理
    文件管理是计算机使用中至关重要的一部分,涉及到文件目录与路径、目录与文件操作、文本编辑器、文件时间以及文件类型等方面。在这篇博客中,我们将深入探讨这些文件管理的关键概念,为你揭示文件管理的精彩世界。1.文件目录与路径文件目录是文件系统中的一个组织单元,用于存储文件和......
  • 进程管理系统
    初识进程在Linux系统中,进程是执行中的程序的实例。每个进程都有一个唯一的进程标识符(PID)和一些相关的属性,如进程状态、优先级等。进程的管理对于系统的稳定性和性能至关重要。查看进程使用ps命令可以查看系统上正在运行的进程。例如,以下命令可以列出当前用户的所有进程:bashpsau......
  • 【C语言】自定义类型:联合和枚举
    1、联合体1.1、联合体类型的声明像结构体⼀样,联合体也是由⼀个或者多个成员构成,这些成员可以不同的类型。但是编译器只为最大的成员分配足够的内存空间。联合体的特点是所有成员共⽤同⼀块内存空间。所以联合体也叫:共用体。给联合体其中⼀个成员赋值,其他成员的值也跟着变化。#inclu......
  • 【C语言】浮点数在内存中的存储
    常⻅的浮点数:3.14159、1E10等,浮点数家族包括:float、double、longdouble类型。 浮点数表⽰的范围:float.h中定义我们先通过一道题目来了解:#include<stdio.h>intmain(){intn=9;float*pFloat=(float*)&n;printf("n的值为:%d\n",n);printf("*pFloat的值为:%f\n",......
  • 《初学C语言第14天》
    ////结构体成员的访问//#include<stdio.h>//typedefstructstu//{// //成员变量// charname[20];// shortage;// chartele[12];// charsex[7];//}Stu;//voidPrint1(Stutmp)//形参tmp//形参是实参的一份临时拷贝,且此块空间放到其他的位置上即tmp位置上(存在空间浪费......
  • Java智慧工地一体化解决方案(里程碑管理)源码
    智慧工地为管理人员提供及时、高效、优质的远程管理服务,提升安全管理水平,确保施工安全提高施工质量。实现对人、机、料、法、环的全方位实时监控,变被动“监督”为主动“监控”。一、建设背景施工现场有数量多、分布广,总部统一管理难度大;工地作业流程节点多,缺少过程可视化管理,成本......
  • C语言基础知识
    C语言的特点关键字(32个):auto、break、case、char、const、continue、default、do、double、else、enum、extern、float、for、goto、if、int、long、register、return、short、signed、static、sizeof、struct、switch、typedef、union、unsigned、void、volatile、while......
  • 【C语言】自定义类型:结构体
    1、结构体类型的声明1.1、结构体的概念结构是⼀些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。1.2、结构的声明structtag{member-list;}variable-list;在一般情况下,tag、member-list、variable-list这3部分至少要出现2个。以下为实例://此声明......
  • C语言冒泡排序法
    引言冒泡排序是一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。冒泡的实现在细节上可以有很多种变化。最简单排序实现/*对顺序表L做交换排序*/voidBubbleSortO(SqList*L){ inti,j;for(i=1;i<L->length;i++) { fo......