堆 栈 内存

一、地址

1.对于32位的操作系统,地址都是32位的,前0不可以省略
例:
  1. int *p = NULL;  
  2. cout<<p<<endl;//输出00000000,而不是0  
int *p = NULL;
cout<<p<<endl;//输出00000000,而不是0
2.指针可以通过内存地址直接访问数据,可避免在程序中复制大量的代码。因此指针效率最高

例:a[j]:a+j

        a[i][j]:a[i]+j


 

二、内存

1.数据在内存中的存放形式

1)栈区:由编译器自动分配和释放

                  一般存放函数的参数值、局部变量的值等

2)堆区:由程序员分配及释放。若程序员不释放,程序结束后可能由OS回收

3)寄存器区:用来保存栈顶指针和指令指针

4)全局区(静态区):全局变量和静态变量是存储在一起的。初始化的和未初始化的是分开的。

                                          程序结束后由系统释放

5)文字常量区:程序结束后由系统释放

                              存放常量字符串

6)程序代码区:存放函数体的二进制代码

2.堆与栈的区别:

 
内存申请方式程序员自己申请,申请时需要指明申请的大小系统自己分配
系统响应方式

遍历内存空闲地址链表,找到比申请的要大的堆结点,将其

中申请的大小分配给程序,程序空间放入空闲链表中

栈的剩余空间不足时会overflow
最大空间大小由系统中的有效虚拟内存决定2M
执行效率慢、易产生内存碎片、灵活快、无内存碎片

补充:

(1)指针对内存数据有保护作用

栈可以为它其中的某个内存单元命名,但堆中的每个内存单元都是匿名(这是对数据的保护)的。必须先在堆中申请一个内存单元地址,然后把它的保存在一个指针中,只有该指针才可以访问该内存单元的数据。

(2)delete运算符只能删除堆中的空间,删除栈中的空间会导致出错

  1. int main()  
  2. {  
  3.     A a;  
  4.     A *p = new A;  
  5.     A *q = &a;    
  6.     delete p;//正确,因为p指向堆中的未命名空间   
  7.     delete q;//错误,因为q指向栈中的空间   
  8.     return 0;  
  9. }  
int main()
{
	A a;
	A *p = new A;
	A *q = &a;  
	delete p;//正确,因为p指向堆中的未命名空间
	delete q;//错误,因为q指向栈中的空间
	return 0;
}


3.内存泄漏

(1)某指针指向某堆结点,没有释放
  1. class A  
  2. {};  
  3. int main()  
  4. {  
  5.     A *p = new A;//没有释放   
  6.     return 0;  
  7. }  
class A
{};
int main()
{
	A *p = new A;//没有释放
	return 0;
}

(2)指针是一个局部变量,在释放内存之前,因为离开作用域而消失了
  1. class A  
  2. {};  
  3. void Test()  
  4. {  
  5.     A *p = new A;  
  6. }  
  7. int main()  
  8. {  
  9.     //无法释放   
  10.     return 0;  
  11. }  
class A
{};
void Test()
{
	A *p = new A;
}
int main()
{
	//无法释放
	return 0;
}

(3)用父类指向一个子类对象,析构函数没有实现多态
  1. class A  
  2. {};  
  3. class B:public A  
  4. {  
  5.     int x;  
  6. };  
  7. void Test()  
  8. {  
  9.     A *p = new A;  
  10. }  
  11. int main()  
  12. {  
  13.     A *p = new B;//只释放了基类所占用的空间,x所占用的空间没有释放   
  14.     delete p;  
  15.     return 0;  
  16. }  
class A
{};
class B:public A
{
	int x;
};
void Test()
{
	A *p = new A;
}
int main()
{
	A *p = new B;//只释放了基类所占用的空间,x所占用的空间没有释放
	delete p;
	return 0;
}

三、堆

1.访问堆中成员的两种方式

访问堆中成员有两种方式,它们是等价的:A *p = new A();

1)(*p).get();                              2)p->get

例:

  1. class A  
  2. {  
  3.     int x;  
  4. public:  
  5.     A(int i):x(i){}  
  6.     int get(){return x;}  
  7. };  
  8. int main()  
  9. {  
  10.     A *p = new A(1), *q = new A(2);  
  11.     cout<<(*p).get()<<' '<<q->get()<<endl;  
  12.     return 0;  
  13. }  
class A
{
	int x;
public:
	A(int i):x(i){}
	int get(){return x;}
};
int main()
{
	A *p = new A(1), *q = new A(2);
	cout<<(*p).get()<<' '<<q->get()<<endl;
	return 0;
}
输出:1 2

四、栈

1.在函数调用时的入栈和出栈的顺序:

入栈顺序:1)被调用函数的下一行地址2)参数(从右往左)3)函数的全局变量

出栈的顺序相反。

2.栈中的对象,遇到“}”时自动析构

例:
  1. class A  
  2. {  
  3. public:  
  4.     ~A(){cout<<"析构"<<endl;}  
  5. };  
  6. void Test()  
  7. {  
  8.     A a;  
  9. }  
  10. int main()  
  11. {  
  12.     Test();  
  13.     return 0;  
  14. }  
class A
{
public:
	~A(){cout<<"析构"<<endl;}
};
void Test()
{
	A a;
}
int main()
{
	Test();
	return 0;
}

输出:析构
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值