zoukankan      html  css  js  c++  java
  • 内存分配的几种方式,以及动态内存传递的注意事项

    一.内存的分配方式?静态存储区,栈,堆

    静态存储区:内存在程序编译的时候已经分配好,这块内存在程序的整个运行期间都存在,比如说全局变量。

    栈:在栈上创建,在函数执行期间,函数内部局部变量和形参可以在栈上创建,函数执行这些存储单元自动释放。所以我们不能返回在函数内部定义的变量(函数定义的指针可以返回),因为他们在函数执行结束时已经被销毁了,处理器的指令集有关于站内部的分配运算,因此效率很高,但是分配的内存资源有限。

    堆:从堆上分配,也称为动态内存分配,使用new malloc等申请任意多内存,程序员自己决定何时释放内存,使用灵活,但是常出问题,比如说申请了忘了释放,就会造成内存泄露,这块存储区域一直不能被使用。

    注意事项:(1)全局变量以及静态变量存放在静态数据区

         (2)注意常量的存放区域,通常情况下常量是存放在程序区的(程序区是只读的,因此任何修改常量的行为都是违法的),而不是数据区。也有的系统将部分常量分配到静态数据区,比如说字符串常量,但是要记住一点,常量所在的内存空间都是受系统保护的,不能修改,对常量的修改将造成访问内存出错,一般系统都会提示,常量的生命周期一直到程序执行结束为止。

    二. 函数调用的过程

    执行某个函数时,如果有参数,则在栈上为形式参数分配空间(引用类型参数除外),继续进入到函数内部,如果遇到变量,则按情况在不同存储区分配空间(如果是static类型的变量,则在进行编译的过程中就已经分配了空间),函数内的语句执行完后,如果函数没有返回值,则直接返回调用该函数的地方(即执行原点),如果存在返回值,则先将返回值进行拷贝传回,在执行执行原点,函数全部执行完毕后,执行退栈操作,将方才函数内部在栈上申请的内存空间释放掉。

    三. 具体例子解释内存分配和函数返回值的问题

    内存分配:

    int a=1;       a在栈区

    char s[]="123";       s在栈区,“123”在栈区,其值可以改变

    char *s="123";        s在栈区,但是"123"在常量区,其值不能被改变

    int *p=new int;        p在栈区,申请的空间在堆区(p指向的区域)

    int *p=(int *)malloc(sizeof(int));     p在栈区,p指向的空间在堆区

    static int b=0;          b在静态存储区

    实例1:

    #include<iostream>
    using namespace std;
    
    void test(int *p)
    {
        int b=2;
        p=&b;
        cout<<p<<endl;
    }
    
    int main(void)
    {
        int a=10;
        int *p=&a;
        cout<<p<<endl;
        test(p);
        cout<<p<<endl;
        return 0;
    }

    你认为输出是什么?发现第一个和第三个输出相同,和第二个不同也就是说当指针作为形参时,如果改变指针的指向,那么是不会影响实参的,但是如果改变指针指向内存存放的数值,那么是会改变实参所指向的内存的数值的。这个也可以理解因为形参只是对实参的拷贝,所以改变形参是不会改变实参的,但是即使是拷贝,也和实参一样指向了同一块区域,所以可以改变区域存放的内容

    实例2:

    #include<iostream>
    using namespace std;
    
    char* test(void)
    {
        char str[]="hello world!";
        return str;
    }
    
    int main(void)
    {
        char *p;
        p=test();
        cout<<p<<endl;
        return 0;
    }

    这个实例输出可能是HelloWorld也可能是乱码,因为test函数中定义了字符型数组并存放在栈上,并返回存放该字符串的地址,但是函数执行完后,站上的内存就会释放,所以虽然指针p还是指向该内存单元,但是可能该内存单元已经被重写了,所以打印出的结果可能是乱码也可能是HelloWorld

    实例3:

    #include<iostream>
    using namespace std;
    
    int test(void)
    {
        int a=1;
        return a;
    }
    
    int main(void)
    {
        int b;
        b=test();
        cout<<b<<endl;
        return 0;
    }

    但是对于上述代码?为何输出是1呢,为什么不是随机值,不是内存单元已经被释放,栈会刷新啊,可能会被重写吗?

        答案是?栈确实刷新了,但是程序在执行return时,会创建一个int型的临时变量,该临时变量是返回值的拷贝,因此返回值的内存被释放也没有关系

    实例4:

    #include<iostream>
    using namespace std;
    
    char* test(void)
    {
        char *p="hello world!";
        return p;
    }
    
    int main(void)
    {
        char *str;
        str=test();
        cout<<str<<endl;
        return 0;
    }

    这里为什么会输出HelloWorld,因为p是存放在栈上的,但是“HelloWorld”是存放在静态存储区的常量,他的生存期和整个程序是一样长的,所以即使子函数执行完毕后,返回的指针指向的内存单元所存放的东西也不会变。

    实例5:

    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    using namespace std;
    
    char* test(void)
    {
        char *p=(char *)malloc(sizeof(char)*100);
        strcpy(p,"hello world");
        return p;
    }
    
    int main(void)
    {
        char *str;
        str=test();
        cout<<str<<endl;
        return 0;
    }

    上述程序输出结果是:HelloWorld。为什么可以正确输出,因为malloc申请的动态内存是在堆上的,必须有程序员手动释放,否则是不会自己释放的,所以程序返回后,该指针指向的内存单元所存放的东西是不会变的

    实例6:

    #include<iostream>
    using namespace std;
    
    void test(void)
    {
        char *p=(char *)malloc(sizeof(char)*100);
        strcpy(p,"hello world");
        free(p);
        if(p==NULL)
        {
            cout<<"NULL"<<endl;
        }
    }
    
    int main(void)
    {
        test();
        return 0;
    }

    这个没有输出?因为释放内存之后,变成了空指针,但是并没有销毁指针,函数结束的时候才会销毁指针

  • 相关阅读:
    致命错误 RC1004: 文件查找结束时有无法预知的错误(vc++)
    demo713总结
    图标,鼠标,字符串,音频..
    不同的色深条件(8、16、24、32),像素绘制方式
    SQL 保留两位小数的实现方式
    MVC4的REmote缺陷
    MVC4安装过程
    mongodb 的几种驱动
    iis7 web配置问题及解决办法
    Fast Binary File Reading with C#
  • 原文地址:https://www.cnblogs.com/jijiji/p/4854780.html
Copyright © 2011-2022 走看看