首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

关于内存空间的开辟的疑问解决思路

2012-02-15 
关于内存空间的开辟的疑问最近在使用C++,关于变量的内存开辟问题一直不太明白,请大家指点:比如下面的例子:

关于内存空间的开辟的疑问
最近在使用C++,关于变量的内存开辟问题一直不太明白,请大家指点:
比如下面的例子:
int   i=5;   //这个变量i的空间应该是在栈上,不需要手动释放
int   *k   =   new   int(5)   //这个变量k的空间应该是在堆上开辟,   不用了的时候需要手动释放.

上面是我对定义一个整型变量的两种方式的理解,   不知道有没有错误?

但是关于struct/class   这种类型的内存开辟问题我还是很糊涂.
我知道关于链表之类的动态的结构,内存开辟是必须用new   /alloc等在堆上进行.但是普通的struct/class   呢?   比如说下面两种不同的方式

方式1:
struct   test
{   int   a;
int   b;
};
test   *testObj   =   new   test();
testObj-> a   =1;
testObj-> b   =2;

方式2:
struct   anotherTest
{   int   a;
int   b;
};
anotherTest   anotherTestObj;
anotherTestObj.a=1;
anotherTestObj.b=2;


问题:   1:   方式2这种定义方法有没有问题?是不是在栈上分配内存?   如果该struct/class很大,超出了栈的大小怎么办?  
2. 如果上面的方式2的写法没有问题, 如果struct/class中有动态指针(比如链表)的成员,是不是这样写就会有问题?
3.方式1和方式2的区别?

[解决办法]
1、没问题
2、指针本身也是栈上的,动态分配内存后,指向的内存放在堆上
3、就是栈和堆的区别
[解决办法]
对 自定义类型和内置类型 使用new是一样的

1: 方式2这种定义方法有没有问题?是不是在栈上分配内存? 如果该struct/class很大,超出了栈的大小怎么办?
--------------------
栈,太大,栈溢出

2. 如果上面的方式2的写法没有问题, 如果struct/class中有动态指针(比如链表)的成员,是不是这样写就会有问题?
--------------------
没问题,那是stuct和class内部的处理,

3.方式1和方式2的区别?
-------------
一个在堆上申请空间
一个在栈里


[解决办法]
问题: 1: 方式2这种定义方法有没有问题?是不是在栈上分配内存? 如果该struct/class很大,超出了栈的大小怎么办?  
--------------------------------------
没有问题。是在栈上(如果不是全局的话)。栈溢出。

2. 如果上面的方式2的写法没有问题, 如果struct/class中有动态指针(比如链表)的成员,是不是这样写就会有问题?
-------------------------------------------
有指针的话最好有构造函数和析构函数,只要有NEW的地方就要有DELETE,配对就可以了。

3.方式1和方式2的区别?
--------------------
方式1的内存由你自己管理,什么时候释放你说了算。方式2由系统管理。


你的疑问应该是在指针上,注意结构本身占用的内存和结构里的指针申请的内存是不一样的!!!结构本身和int一样,你定义了系统就会自动分配内存给你用,但是指针的内存必须要你申请才会有,所以也要你来释放。总之一个原则,谁申请谁释放。
[解决办法]
首先,你对:

int i=5; //这个变量i的空间应该是在栈上,不需要手动释放
int *k = new int(5) //这个变量k的空间应该是在堆上开辟, 不用了的时候需要手动释放.

的理解基本正确!严谨的说应该是: "这个变量k指向的空间应该是在堆上配置, 不用了的时候需要delete(对于数组是delete[]!)释放. "

其次,对于方式二:

方式2:
struct anotherTest
{
int a;
int b;
};
anotherTest anotherTestObj;
anotherTestObj.a=1;
anotherTestObj.b=2;

的问题1:

当然是在栈上建构anotherTestObj!程序员无须担心栈的大小,那是编译器的责任!一条重要的原则是, "栈空间的管理是语言的责任,而堆空间的管理是程序员的责任 "!

问题2:

同样没有问题,但要注意如果struct/class中有动态指针(比如链表)的成员,那在struct/class的设计中一定要牢记上述那条重要的原则,在相关的代码中管理好堆空间!

问题3:

区别也在于那条重要的原则。



[解决办法]

int i=5; //这个变量i的空间应该是在栈上,不需要手动释放
int *k = new int(5) //这个变量k的空间应该是在堆上开辟, 不用了的时候需要手动释放.

-------------

第二个理解还有点问题

int *k = new int(5);

指针变量 k 的空间在栈上, 在32位机器上指针变量大小4字节

指针变量k所存储的4字节地址所指向到空间在堆上,类型为 int 大小为 4 * sizeof(int);


方式1:
struct test
{ int a;
int b;
};
test *testObj = new test();
testObj-> a =1;
testObj-> b =2;

方式2:
struct anotherTest
{ int a;
int b;
};
anotherTest anotherTestObj;
anotherTestObj.a=1;


anotherTestObj.b=2;


问题: 1: 方式2这种定义方法有没有问题?是不是在栈上分配内存? 如果该struct/class很大,超出了栈的大小怎么办?  


----------

几乎不会出现问题,除非你在这个结构的生命周期外引用了它

比如

anotherTest* get_test() {
anotherTest anotherTestObj;
anotherTestObj.a=1;
anotherTestObj.b=2;
retrun &anotherTestObj;
}

void mian() {
anotherTest* p = get_test();
// 致命错误,应该 anotherTestObj在函数 get_test 的栈上
所以函数结束的时候anotherTestObj已经摧毁
}


至于会不会很大超过栈,那你一般不太用担心,如果你能写出这个大

的结果,就算没把栈蹭爆, 你的程序也会有问题, vc栈大小默认是1M

可以自己调整


2. 如果上面的方式2的写法没有问题, 如果struct/class中有动态指针(比如链表)的成员,是不是这样写就会有问题?

这个问题要看你的具体情况,

只能这么个你说说

比如

struct sct {

int* p;
}

sct get() {

sct s;
s.p = new int[10];

return s;

}

void mian() {

sct s = get();
cout < <*(s.p) < <endl;
delete[] s.p;

}

上面这个程序运行良好(至于设计上的问题不在讨论内)


3.方式1和方式2的区别?

基本就是实例和实例指针的区别

这个要说就太多太广了,只能靠你在平时写程序的时候慢慢积累

什么时候用什么最合适


比如对于stl的容器,大结构一般就用指针了


struct big_struct {.........};


std::vector <big_struct> s1;
std::vector <big_struct*> s2; // 这个在各方面都要优于上面



[解决办法]
1: 方式2这种定义方法有没有问题?是不是在栈上分配内存? 如果该struct/class很大,超出了栈的大小怎么办? 

A:方法2定义没有问题.因为这个变量会在栈上被分配.如果的确超出了栈的大小.小生估计这里程序会出错...
 
2. 如果上面的方式2的写法没有问题, 如果struct/class中有动态指针(比如链表)的成员,是不是这样写就会有问题?

A:这样写也是没有问题的.该结构体的变量依然在栈内生成.但其内部的动态指针会被初始化为0(也许是其它值.这个偶不太清楚^_^).但如果想要没初始化就直接使用.肯定会报错.

3.方式1和方式2的区别?

A:方式1在在栈上分配一个test型指针变量.只占用栈4个字节(如果是在32位机的情况下^_^).这个变量指向一个在堆中分配的test型结构体.所以在程序结束时如果不显式的delete testObj.那么这个在栈中的指针变量虽然被自动删除.但为其在堆中分配的test结构并没有被销毁.内存于是泄漏...

方式2在栈上分配一个anothertest变量.这个变量占栈的大小为sizeof(anothertest)个字节.和堆没有关系.所以这个变量所占用的栈空间在程序结束时会被自动删除.

热点排行