关于C/c++内存分配问题
验证书上所言的"返回值是局部变量数组指针不可以"这条理论时,写了一个简单程序.想了解下C/c++中内存分配的深层原理.源程序:#include<stdio.h>#defi...
验证书上所言的"返回值是局部变量数组指针不可以"这条理论时,写了一个简单程序.想了解下C/c++中内存分配的深层原理.
源程序:
#include <stdio.h>
#define N 3
int *fun(int a[N])
{
int b[N];
int i;
b[0]=a[0]+10;
b[1]=a[1]+10;
b[2]=a[2]+10;
for(i=0;i<N;i++)
{
printf("数组元素地址:%10d",&b[i]);
printf("%9d\n",b[i]);
}
printf("\n");
printf("fun函数内数组首地址\t\t%d\n",b);
return b;
}
void main()
{
int *p,w[N];
w[0]=1;w[1]=2;w[2]=3;
p=fun(w);
printf("main函数内得到的返回值地址\t%d\n",p);
int i;
for(i=0;i<N;i++)
{
printf("数组元素地址:%10d",p+i);
printf("%9d\n",*(p+i));
}
printf("\n");
}
在main函数中访问的地址跟在fun中局部变量数组b的地址相同,函数中没有重新申请地址,也就是说这些地址没被重新赋值.再次访问时,该还能输出原值,为什么不行了?
测试得到的数据有三种(该还有很多情况):(1) 11 1 1245056 (2) 8 1 1245056 (3) 23 1 1245056
若是返回指向一个普通变量的指针,则不会出现问题.
源程序如下:
#include <stdio.h>
int *fun()
{
int *pi;
int i=3;
pi=&i;
return pi;
}
main()
{
int *p;
p=fun();
printf("%d\n",*p);
}
两者对比,该如何解释? 展开
源程序:
#include <stdio.h>
#define N 3
int *fun(int a[N])
{
int b[N];
int i;
b[0]=a[0]+10;
b[1]=a[1]+10;
b[2]=a[2]+10;
for(i=0;i<N;i++)
{
printf("数组元素地址:%10d",&b[i]);
printf("%9d\n",b[i]);
}
printf("\n");
printf("fun函数内数组首地址\t\t%d\n",b);
return b;
}
void main()
{
int *p,w[N];
w[0]=1;w[1]=2;w[2]=3;
p=fun(w);
printf("main函数内得到的返回值地址\t%d\n",p);
int i;
for(i=0;i<N;i++)
{
printf("数组元素地址:%10d",p+i);
printf("%9d\n",*(p+i));
}
printf("\n");
}
在main函数中访问的地址跟在fun中局部变量数组b的地址相同,函数中没有重新申请地址,也就是说这些地址没被重新赋值.再次访问时,该还能输出原值,为什么不行了?
测试得到的数据有三种(该还有很多情况):(1) 11 1 1245056 (2) 8 1 1245056 (3) 23 1 1245056
若是返回指向一个普通变量的指针,则不会出现问题.
源程序如下:
#include <stdio.h>
int *fun()
{
int *pi;
int i=3;
pi=&i;
return pi;
}
main()
{
int *p;
p=fun();
printf("%d\n",*p);
}
两者对比,该如何解释? 展开
3个回答
展开全部
前者和后者都一样犯了同一个错误
由于变量是在栈中分配 每个程序都有自己的栈,也就是这里面的数据不会被其他的程序修改,但是可能会被你自己修改。
所以当你立刻返回这个地址,并且立刻按照正确的类型读取它那么你所获得的值是正确的.这就是你的试验结果 看起来没有什么错误.
但是这种小"技巧"很可能让你的程序崩溃或者运行结果谬之千里。因为当你返回了已经释放的局部变量的内存的时候。那块内存可以被分配给其他变量,也就是说你的指针指向的是一块不知道属于哪个变量的内存.因为这块内存随时可以分配给程序中的其他变量.并且值会随之改变.
请看如下代码:
#include <stdio.h>
#include <stdlib.h>
int *fun()
{
int *pi;
int i=3;
pi=&i;
printf("fun: %p\n",pi);
return pi;
}
int *fun2()
{
int *pi;
int i=7;
pi=&i;
printf("fun1: %p\n",pi);
return pi;
}
int main(void)
{
int*p=fun();
p=fun();
printf("%p\n",p);
p=fun2();
printf("%p\n",p);
system("pause");
}
你会发现fun()和fun2()中的局部变量的地址是一样的
也就是说fun()返回的指针所指向的内存,p指向的内存随时会意外改变
再试试如下代码
#include <stdio.h>
#include <stdlib.h>
int *fun()
{
int *pi;
int i=3;
pi=&i;
printf("fun: %p\n",pi);
return pi;
}
int *fun2()
{
int *pi;
int i=7;
pi=&i;
printf("fun1: %p\n",pi);
return pi;
}\
int * funset(int k){
int *pi;
int i=k;
printf("funset: %p\n",&i);
return &i;
}
int main(void)
{
int*p=fun();
printf("%p\n",p);
printf(" %d\n\n",*p);//输出p指向的内存值
p=fun();
printf("%p\n",p);//第二次调用fun(),p没有改变 说明两次调用函数局部变量用的是同一块内存,也就是内存被重新分配了。
printf(" %d\n\n",*p);
p=fun2();
printf("%p\n",p);//调用另一个函数p还是局部变量地址还是没变,这个函数用得还是同一块内存。
printf(" %d\n\n",*p);
p=funset(100);//猜猜这个函数干了什么,你就会明白.
//我猜你没有打算改变p所指向的内存吧。
printf("%p\n",p);//调用另一个函数p还是局部变量地址还是没变,这个函数用得还是同一块内存。
printf(" %d\n\n",*p);
system("pause");
}
----------
书上说不要返回局部变量的地址就是因为这个地址指向的内存已经是free的
随时可以分配给别的变量。
free的内存,它不是由你使用的,而是由程序自动使用,程序会随时让这个内存发生你没打算干的改变.比如分配给别的局部变量,栈的分配工作是在编译期决定的。不是动态分配。
-----------
你再想想假如你做了如下的事情
返回了一个局部变量的地址保存到p中
你以为这块内存没有变化并且打算利用这块内存保存点东西。
然后调用了一个函数。
然后你莫名其妙的发现p所指向的内存莫名其妙的变化了。
由于变量是在栈中分配 每个程序都有自己的栈,也就是这里面的数据不会被其他的程序修改,但是可能会被你自己修改。
所以当你立刻返回这个地址,并且立刻按照正确的类型读取它那么你所获得的值是正确的.这就是你的试验结果 看起来没有什么错误.
但是这种小"技巧"很可能让你的程序崩溃或者运行结果谬之千里。因为当你返回了已经释放的局部变量的内存的时候。那块内存可以被分配给其他变量,也就是说你的指针指向的是一块不知道属于哪个变量的内存.因为这块内存随时可以分配给程序中的其他变量.并且值会随之改变.
请看如下代码:
#include <stdio.h>
#include <stdlib.h>
int *fun()
{
int *pi;
int i=3;
pi=&i;
printf("fun: %p\n",pi);
return pi;
}
int *fun2()
{
int *pi;
int i=7;
pi=&i;
printf("fun1: %p\n",pi);
return pi;
}
int main(void)
{
int*p=fun();
p=fun();
printf("%p\n",p);
p=fun2();
printf("%p\n",p);
system("pause");
}
你会发现fun()和fun2()中的局部变量的地址是一样的
也就是说fun()返回的指针所指向的内存,p指向的内存随时会意外改变
再试试如下代码
#include <stdio.h>
#include <stdlib.h>
int *fun()
{
int *pi;
int i=3;
pi=&i;
printf("fun: %p\n",pi);
return pi;
}
int *fun2()
{
int *pi;
int i=7;
pi=&i;
printf("fun1: %p\n",pi);
return pi;
}\
int * funset(int k){
int *pi;
int i=k;
printf("funset: %p\n",&i);
return &i;
}
int main(void)
{
int*p=fun();
printf("%p\n",p);
printf(" %d\n\n",*p);//输出p指向的内存值
p=fun();
printf("%p\n",p);//第二次调用fun(),p没有改变 说明两次调用函数局部变量用的是同一块内存,也就是内存被重新分配了。
printf(" %d\n\n",*p);
p=fun2();
printf("%p\n",p);//调用另一个函数p还是局部变量地址还是没变,这个函数用得还是同一块内存。
printf(" %d\n\n",*p);
p=funset(100);//猜猜这个函数干了什么,你就会明白.
//我猜你没有打算改变p所指向的内存吧。
printf("%p\n",p);//调用另一个函数p还是局部变量地址还是没变,这个函数用得还是同一块内存。
printf(" %d\n\n",*p);
system("pause");
}
----------
书上说不要返回局部变量的地址就是因为这个地址指向的内存已经是free的
随时可以分配给别的变量。
free的内存,它不是由你使用的,而是由程序自动使用,程序会随时让这个内存发生你没打算干的改变.比如分配给别的局部变量,栈的分配工作是在编译期决定的。不是动态分配。
-----------
你再想想假如你做了如下的事情
返回了一个局部变量的地址保存到p中
你以为这块内存没有变化并且打算利用这块内存保存点东西。
然后调用了一个函数。
然后你莫名其妙的发现p所指向的内存莫名其妙的变化了。
展开全部
main中返回的地址当然和函数内的数组地址是相同的,这是函数返回值设计的最重要原因之一,只是出了函数体,这个地址指向的内存空间“并不存在”了(可能被回收,可能被其它程序占用)。
所以当你再次去访问时,不仅编译过程中会警告你,甚至报错,即使你侥幸运行起来,也会弹出内存不可访问的错误。
所以当你再次去访问时,不仅编译过程中会警告你,甚至报错,即使你侥幸运行起来,也会弹出内存不可访问的错误。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
参考资料: http://blog.csdn.net/newman0708/archive/2009/08/02/4401983.aspx
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询