C++ 内存布局 变量在堆栈的分配

1.  变量的内存分布:

const变量存储在.rodata(read only)区域;

char* p = "abcd"; p指向的是静态文本区域.text

.rodata 和 .text 被合并为一个segment,由OS保护起来,只可读。

register变量存放在.bss区域;

局部变量存放在栈空间,static变量存放在静态存储空间 (.data)

.bss 和.data  被合并为一个segment,可读可写。

变量在内存中的不同位置,影响着变量的读写方式。程序1很正常,因为p在栈上,可以修改。

  1. const char * strA()  
  2. {  
  3. char p[] = "hello";  
  4. p[0] = 'm';   
  5. return p;  
  6. }  

程序2就会出错。因为对于全局区域的值,程序员是不可以修改的。

  1. const char * strA()  
  2. {  
  3. char *p = "hello";  //所以我们写用一个指针指向一个字符串时把指针变为常量指针,这样有错误在编译阶段就可以看出。char const *  p3 = "hello";   p3[0] = 'm'; 编译不过去。l-value specifies const object
  4. p[0] = 'm'//虽然编译时没有错误,但运行时报出异常如下图,这样的bug 千万不要留着。运行时的错误很难找出来。
  5. return p;  
  6. }  


如果想要修改其值,可以声明为静态变量,这样编译器会在静态存储区域分配一块空间。如程序3:

  1. const char * strA()  
  2. {  
  3. static char p[] = "hello";  //注意这里分配的是数组空间,不同于上面的指针。如果是static char * p, 说明指针p占用的4个字节在静态区域可修改,但它所指的内存“hello”仍然在全局区域,不可以修改。  
  4. p[0] = 'm'//OK  
  5. return p;  
  6. }  

另外,一个类中的静态成员变量时不占这个类的存储空间的。

比如class A{}; class B{static int M;};

sizeof(A) = sizeof(B) = 1

静态成员应该在类定义体的外部初始化。static int B::M = 6;

const成员应该在初始化列表中初始化,除此之外,没有任何地方可以改变它的值。

2.变量的堆栈分布

可以看到栈是从大到校,堆是从小到大。
我们可以通过程序来验证:

#include <iostream>
#include <string>
using namespace std;  
class base    
{    
public:    
    void bfun(){}    
    virtual void vfun1(){}    
    virtual int vfun2(){return 0;}  
    base(){  
        cout<<"base constructor"<<endl;  
    }  
private:    
    int a;    
};    
class derived : public base    
{    
public:    
    void dfun(){}    
    virtual void vfun1(){}  
    int  vfun2(){cout<<"derived vfun2()"<<endl;return 0;}  
    virtual int vfun3(){return 0;}   
    derived(){  
        cout<<"derived constructor"<<endl;  
    }  
private:    
    int b;    
};  
void test(base &pBase)    
{    
    //pBase->vfun2();    
    pBase.vfun2();  
}
int max(int a,int b){
	if(a>b){
		return a;
	}else{
		return b;
	}
}    
int main(int argc, char* argv[])    
{ 
	int a=0;
	cout<<"int 类型变量:  "<<&a<<endl;
	derived d;
	cout<<"derived 类型变量取地址:  "<<&d<<endl;
	derived *p=new derived;//new 的只能赋给指针。
	cout<<"derived 指针 p:  "<<p<<endl;
	derived *p1=new derived;
	cout<<"derived 指针 p1:  "<<p1<<endl;
	return 0;    
} 

程序运行结果为:
int 类型变量:  0012FF70//int 肯定是栈里。
base constructor
derived constructor
derived 类型变量取地址:  0012FF64//0012FF64 比int 型变量小所以栈里地址是从大到小。并且发现derived 自定义类型也是在栈里(0012FF64),只有用new 才放在堆里(与java不一样)。
base constructor
derived constructor
derived 指针 p:  00481AF0
base constructor
derived constructor
derived 指针 p1:  00481910
Press any key to continue

并且有一点一定要强调,c++ 的new 的只能用指针指向:
int *a=new int[4];//int a[]=new int[4];//cannot convert from 'int *' to 'int []'
	 int *p=a;
	 for(int i=0;i<4;i++){
		 *p=i;
		 p++;//可以用指针指向访问
	 }
	 for(int j=0;j<4;j++){
		 cout<<a[j];//也可以用下标访问。tp-link 就问了这个问题,堆里的数据地址可不可以连续。当初达成了不连续悲催...
	 }




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值