关闭

C++中内存分配、函数调用和返回值问题

378人阅读 评论(0) 收藏 举报
分类:

C++编译器将计算机内存分为代码区和数据区,很显然,代码区就是存放程序代码,而数据区则是存放程序编译和执行过程出现的变量和常量。数据区又分为静态数据区、动态数据区,动态数据区包括堆区和栈区。

以下是各个区的作用:

(1)代码区:存放程序代码;

(2)数据区

   a.静态数据区: 在编译器进行编译的时候就为该变量分配的内存,存放在这个区的数据在程序全部执行结束后系统自动释放,生命周期贯穿于整个程序执行过程。

   b.动态数据区:包括堆区和栈区

    堆区:这部分存储空间完全由程序员自己负责管理,它的分配和释放都由程序员自己负责。这个区是唯一一个可以由程序员自己决定变量生存期的区间。可以用malloc,new申请对内存,并通过free和delete释放空间。如果程序员自己在堆区申请了空间,又忘记将这片内存释放掉,就会造成内存泄露的问题,导致后面一直无法访问这片存储区域。

    栈区:存放函数的形式参数和局部变量,由编译器分配和自动释放,函数执行完后,局部变量和形参占用的空间会自动被释放。效率比较高,但是分配的容量很有限。

 

注意: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.test1 

复制代码
#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.test2

复制代码
#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;
}
复制代码

 

输出结果可能是hello world!,也可能是乱码。

出现这种情况的原因在于:在test函数内部声明的str数组以及它的值"hello world”是在栈上保存的当用return将str的值返回时,将str的值拷贝一份传回,当test函数执行结束后,会自动释放栈上的空间,即存放hello world的单元可能被重新写入数据,因此虽然main函数中的指针p是指向存放hello world的单元,但是无法保证test函数执行完后该存储单元里面存放的还是hello world,所以打印出的结果有时候是hello world,有时候是乱麻。

4.test4

复制代码
#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;
}
复制代码

执行结果是 hello world!

同样返回的是指针,为什么这里会正确地打印出hello world1?这是因为char *p="hello world!",指针p是存放在栈上的,但是"hello world!”是一个常量字符串,因此存放在常量区,而常量区的变量的生存期与整个程序执行的生命期是一样的,因此在test函数执行完后,str指向存放“hello world!”的单元,并且该单元里的内容在程序没有执行完是不会被修改的,因此可以正确输出结果。

5.test5

复制代码
#include<iostream>
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;
}
复制代码

运行结果 hello world

这种情况下同样可以输出正确的结果,是因为是用malloc在堆上申请的空间,这部分空间是由程序员自己管理的,如果程序员没有手动释放堆区的空间,那么存储单元里的内容是不会被重写的,因此可以正确输出结果


3.test3  

复制代码
#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

有人会问为什么这里传回来的值可以正确打印出来,不是栈会被刷新内容么?是的,确实,在test函数执行完后,存放a值的单元是可能会被重写,但是在函数执行return时,会创建一个int型的临时变量,将a的值复制拷贝给该临时变量,因此返回后能够得到正确的值,即使存放a值的单元被重写数据,但是不会受到影响。

6.test6

复制代码
#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;
}
复制代码

没有输出

在这里注意了,free()释放的是指针指向的内存!注意!释放的是内存,不是指针!这点非常非常重 要!指针是一个变量,只有程序结束时才被销毁。释放了内存空间后,原来指向这块空间的指针还是存在!只不过现在指针指向的内容的垃圾,是未定义的,所以说是垃圾。因此,释放内存后应把把指针指向NULL,防止指针在后面不小心又被使用,造成无法估计的后果。

转自

http://www.cnblogs.com/dolphin0520/archive/2011/04/04/2005061.html

作者:海子
         
本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。


0
0
查看评论

C++中内存分配、函数调用和返回值

一个由C/C++编译的程序占用的内存分为以下几个部分1、栈区(stack)— 由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。2、堆区(heap) — 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是...
  • penzo
  • penzo
  • 2010-11-17 22:05
  • 703

[转]浅谈C++中内存分配、函数调用和返回值问题

在谈述函数调用和返回值问题之前,先来看看C++中内存分配的问题。 C++编译器将计算机内存分为代码区和数据区,很显然,代码区就是存放程序代码,而数据区则是存放程序编译和执行过程出现的变量和常量。数据区又分为静态数据区、动态数据区,动态数据区包括堆区和栈区。 以下是各个区的作用: (...
  • lsl_123
  • lsl_123
  • 2012-07-25 19:45
  • 414

浅谈C++中内存分配、函数调用和返回值问题

在谈述函数调用和返回值问题之前,先来看看C++中内存分配的问题。 C++编译器将计算机内存分为代码区和数据区,很显然,代码区就是存放程序代码,而数据区则是存放程序编译和执行过程出现的变量和常量。数据区又分为静态数据区、动态数据区,动态数据区包括堆区和栈区。 以下是各个区的作用: (1)代码区...
  • brk1985
  • brk1985
  • 2014-02-08 13:16
  • 486

浅谈C/C++中内存分配、函数调用和返回值问题

在谈述函数调用和返回值问题之前,先来看看C++中内存分配的问题。   C++编译器将计算机内存分为代码区和数据区,很显然,代码区就是存放程序代码,而数据区则是存放程序编译和执行过程出现的变量和常量。数据区又分为静态数据区、动态数据区,动态数据区包括堆区和栈区。   以下是各个区的作用:   (...
  • heqiangflytosky
  • heqiangflytosky
  • 2013-04-09 11:09
  • 485

内存分配 函数调用 返回值

http://www.cnblogs.com/dolphin0520/archive/2011/04/04/2005061.html 123456
  • xpplearnc
  • xpplearnc
  • 2014-01-22 18:33
  • 249

C++函数参数和返回值

形式参数和实际参数 在调用函数时,大多数情况下,函数是带参数的。主调函数和被调用函数之间有数据传递关系。前面已提到:在定义函数时函数名后面括号中的变量名称为形式参数(formal parameter,简称形参),在主调函数中调用一个函数时,函数名后面括号中的参数(可以是一个表达式)称为实际参数(a...
  • feng020a
  • feng020a
  • 2017-02-07 15:09
  • 463

函数调用和栈的内存分配过程分析

学习程序到底怎么调用的和内存怎样分配的,其实了解函数的调用和堆栈的内存管理是很有必要的。程序的代码是存放在代码区的,一般代码区为只读的,不可修改的,道理很简单就是程序的安全性。其他的常量什么的也有自己的内存区域, 栈的调用过程一般是内存地址向下分配的。首先来看一个简单的例子:VC6.0测试...
  • longronglin
  • longronglin
  • 2008-03-29 19:19
  • 2836

C++内存分配和管理

[导语] 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中无处不在,内存泄漏几乎在每个C++程序中都会发生,因此要想成为C++高手,内存管理一关是必须要过的,...
  • Jeson_Mei
  • Jeson_Mei
  • 2016-08-16 11:05
  • 2494

C++内存分配、函数调用(值传递、指针传递、引用传递)、返回值问题

在谈述函数调用和返回值问题之前,先来看看C++中内存分配的问题。 C++编译器将计算机内存分为代码区和数据区,很显然,代码区就是存放程序代码,而数据区则是存放程序编译和执行过程出现的变量和常量。数据区又分为静态数据区、动态数据区,动态数据区包括堆区和栈区。 以下是各个区的作用: (1)代码区:...
  • u010511579
  • u010511579
  • 2015-04-29 17:26
  • 381

C++之函数调用的返回值

函数调用中的返回值是放在一个临时变量中的,这个临时变量可能存在于寄存器中,也可能在栈中预先分配的一段空间中(因为编译器根据函数拥有返回值会预先分配空间),函数返回时,再把临时变量的值拿出来,放到应赋给的值所在的空间中(如果有赋值的话)。举个例子:int getnum(){ int a = ...
  • maoliran
  • maoliran
  • 2016-05-28 19:45
  • 1152
    个人资料
    • 访问:54454次
    • 积分:1393
    • 等级:
    • 排名:千里之外
    • 原创:78篇
    • 转载:52篇
    • 译文:0篇
    • 评论:3条
    文章分类