内存分配的几种方式,以及动态内存传递的注意事项

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

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

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

堆:从堆上分配,也称为动态内存分配,使用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;
}

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

原文地址:https://www.cnblogs.com/jijiji/p/4854780.html