首页 新闻 会员 周边 捐助

循环体内的局部变量内存分配和释放

0
悬赏园豆:10 [已解决问题] 解决于 2015-10-16 17:10

最近查找bug时碰到了循环体中局部变量的内存分配相关的问题,于是查找相关知识,产生了一点疑问。先写代码:

 1 int main()
 2 {
 3     int i;
 4     bool bl = true;
 5     for (i=0; i<3; i++)
 6     {
 7         int nvar[10];
 8         if(bl)
 9         {
10             printf("uninitial ");
11             bl = false;
12         }
13         else{
14             printf("before:%d ",nvar[0]);
15         }
16                                  nvar[0] = 10*i;
17         //nvar[i] = 10*i;
18         printf("after:%d\n",nvar[0]);
19     }
20 }

实际上,我主要是想看看几个问题:

1、循环体每次循环是否都会为整形数组分配内存

2、每次进入循环时,nvar[0]的值是不是都保留了上一个循环时的值

发现:

1、由于编译器的优化,不会每次循环都会为数组分配内存,而是进入for循环之前一次分配好。

2、每次进入循环时,nvar[0]的值虽然保留了上一个循环的值,但是打印这个值是会报错的,编译器提示变量undefined,因为实际上这个地址对应的变量是一个新的变量,上一个循环产生的变量已经在循环结束时析构。其实把这个数组换成一个类的对象,会更好理解,如下:

 1 class B
 2 {
 3 private:
 4     int b;
 5 public:
 6     B()
 7     {
 8         printf("construction function\n");
 9     }
10     B(B &b)
11     {
12         printf("copy construction function\n");
13     }
14     ~B()
15     {
16         printf("destruction function\n");
17     }
18 };
19 
20 int main()
21 {
22                 B class1;
23                 for(int i=0; i<3; i++)
24                 {
25     B bclass1;
26     for (i=0; i<3; i++)
27     {
28         B bclass2 = bclass1;
29                 }
30 }

结果:

在回到上面的那个问题,当我把循环体中数据的复制方式换成nvar[i] = 10*i时,就不会产生运行错误。这是为什么?难道这样赋值时,上一次循环的临时对象不会析构吗?

c++
钱吉的主页 钱吉 | 初学一级 | 园豆:123
提问于:2012-09-25 20:41
< >
分享
最佳答案
0

临时变量每次循环回收是肯定回收的。我研究了一下,你这个错误是运行时错误,就是未初始化时出现的,属于编译器问题。vc上如果打开了RTC运行时检查就会报这个错,但是gcc上就不会。这个错,我看了一下汇编代码,还是跟编译器有关。编译器在开始的时候给为赋值的数组打了一个标志位。

1 mov    BYTE PTR $T3913[ebp], 0

而循环进行第二次的时候,

1 cmp    BYTE PTR $T3913[ebp], 0
2     jne    SHORT $LN8@main
3     push    OFFSET $LN9@main
4     call    __RTC_UninitUse
5     add    esp, 4

比较发现该数组依然没有初始化,就到了__RTC_UninitUse这个函数报了个错。诡异的是

当  

nvar[i] = 10*i;

 时编译器没有打初始化的标志位。所以也不会报错。原因可能跟编译器有关。

 
收获园豆:5
会飞的机器猫 | 初学一级 |园豆:86 | 2013-03-12 16:46
其他回答(4)
0

int nvar[10] = {0};  // 变量初始化

Launcher | 园豆:45050 (高人七级) | 2012-09-26 09:58

谢谢关注,我知道没初始化而去printf的时候是会出错的,但是问题是:如果换成nvar[i] = 10*i时,printf是不会出错的,我想知道这个原因

支持(0) 反对(0) 钱吉 | 园豆:123 (初学一级) | 2012-09-26 19:56

@DarkHorse: 你可以 printf nvar[9] 试试。

支持(0) 反对(0) Launcher | 园豆:45050 (高人七级) | 2012-09-27 09:13
0

这么销魂的代码格式,还指针人家读代码?

chncwang | 园豆:204 (菜鸟二级) | 2012-10-01 19:53

哈哈,新手。不知道为什么代码贴上来以后格式就乱了。还请多多指教

支持(0) 反对(0) 钱吉 | 园豆:123 (初学一级) | 2012-10-09 11:22
0

#include<stdio.h>
int main()
{
int i;
bool b1=true;
for(i=0;i<2;i++)
{
int nvar[10];
if(b1)
{
printf("uninitial\n");
b1=false;
}
else
{
printf("befored:%d\n",nvar[0]);
}
nvar[i]=10*i;
/*
第一次调用时i=0没有进行初始化,nvar[0]=0;打印0,超过了nvar的作用范围,释放nvar数组空间
第二次调用时i=1,重新分配数组,只是分配的数组地址与原来的数组地址相同,释放时也没进行内存擦除操作,
故打印结果为第一次所赋的值

汇编代码如下:

0040108B: call printf (004010c0)
00401090: add esp,8

可发现结束时没进行擦写操作,是直接移动堆栈指针
*/
printf("after:%d\n",nvar[0]);
}
return 0;
}

收获园豆:2
星空雾雨 | 园豆:311 (菜鸟二级) | 2012-10-18 14:40
0

尽管在高级代码中,你的数组的生存周期,位于你的循环体内,但是编译器会把函数内需要用到的临时变量,他们的空间在刚进入函数的时候就全部分配好了(换句话说,函数内的临时变量在汇编代码级别其实在整个函数内均有效,这里值得是那些基本数据类型,不考虑C++的类)。而不存在你说的什么反复申请释放的问题。也许那只是你的一种在高级代码中的理解,但是编译器是没必要按这种比较笨的方式去实现的。

so sorry,你的后面的问题描述不知所云(完全不懂你在说什么,因为你已经在循环体内对这个数组里的元素赋值,它们的值在函数之内一直保持着这个值,因为他们在栈上的空间在函数体内是固定分配给他们的,不会被其他人占用)。使用了未初始化的变量,是编译器提出的意见,是你没有通过编译器的检查,它可能是警告,而不是说不能生成可执行的代码。这没什么可大惊小怪的。

收获园豆:3
hoodlum1980 | 园豆:573 (小虾三级) | 2012-11-29 08:58
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册