栈内存的问题

yhai_lee 2011-01-26 03:06:43
有谁帮忙解释下
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char fun(char *p)
{
p=(char *)malloc(sizeof(char)*10);
}
char fun1(char **p)
{
*p=(char *)malloc(sizeof(char)*10);
}
char *fun2();
{
char *p=(char *)malloc(sizeof(char)*10)
return p;
}
int main()
{
char *str=NULL;
fun(str); //error
fun1(&str); //OK
p=fun2); //error
strcpy(str,"hello world");
puts(p);
}
...全文
521 32 打赏 收藏 转发到动态 举报
写回复
用AI写文章
32 条回复
切换为时间正序
请发表友善的回复…
发表回复
lengxujun 2011-01-27
  • 打赏
  • 举报
回复
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char fun(char *p)
{
// 从此这快内存将被泄露掉
p = (char *)malloc(sizeof(char)*10);
// free(p);

// 是否该返回一个值呢?
return ((char)0);
}

char fun1(char **p)
{
// 数字10空间小了吧?
// "hello world"有11个字符,加上'\0',应该分配12个字节
*p = (char *)malloc(sizeof(char)*10);
}

char *fun2() //;是多余的吧,否则通不过编译吧?
{
// 数字10空间小了吧?
// "hello world"有11个字符,加上'\0',应该分配12个字节
char *p = (char *)malloc(sizeof(char)*10)
return p;
}

int main()
{
char *str = NULL;
char *p; // 是否还要声明一个p指针?似乎后面有用到

// error: 此处内存泄露,尽管程序退出所有内存会被释放,但还是自己释放的好
fun(str);

fun1(&str); // OK

p = fun2(); // OK: 不知道lz是否要这样写? 开始少了一个'('

// error:写越界了,你只分配了10个字节,实际需要12个字节
// 程序运气好崩溃,运气不好就不知道什么时候疯掉!
strcpy(str, "hello world");

// 这句运行结果恐怕难测:p指向的一片内存天知道是什么?
// 当然malloc()分配可能会统一把其清成某个值,但这种是不确定的
// puts()函数看不到结束标志'\0'誓不罢休
puts(p);

// 规范一点,加上这一句吧
return 0;
}
CaiBirdy 2011-01-27
  • 打赏
  • 举报
回复
参数将会在栈里以一个新的变量存在,
也就是说fun函数中的参数p在每一次调用时都会是一个存在栈里的指针变量,
函数里面对这个参数指针赋值是没有意义的,
正确有效的操作是对这个参数指针所指的地址内容操作数据才是有意义的。
当然你malloc得到的指针赋给参数P,这时候是从堆里申请到的内存,再将这个内存的地址赋给参数P,
所以函数结束后你的p变量在栈里被清了,但是这个p变量所指的那一段内存并没有被释放掉,
这就是最常见的内存管理不当的问题了
董小尾 2011-01-27
  • 打赏
  • 举报
回复
这个问题很常见

弄明白了对于指针的理解就会更深一层的
weerweer 2011-01-27
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 wangliangffaflgh 的回复:]

闲话休提,我推荐侬好好读读林锐的《高质量程序设计指南C/C++》
[/Quote]

++
yhai_lee 2011-01-27
  • 打赏
  • 举报
回复
*p=(char *)malloc(sizeof(char)*10); 改为*p=(char *)malloc(sizeof(char)*12);
p=fun2改为str=fun2
yhai_lee 2011-01-27
  • 打赏
  • 举报
回复
不好意思,我写错了。我改下。欢迎大家多支持。
tompaz 2011-01-27
  • 打赏
  • 举报
回复
第三个当然没问题,反汇编下就知道,fun2的虽然是局部变量,但是作为返回值是可以被传出来的
TimZhuFaith 2011-01-27
  • 打赏
  • 举报
回复
3ks[Quote=引用 28 楼 cinvitejavatodance 的回复:]
引用 26 楼 timzhufaith 的回复:

引用 15 楼 cinvitejavatodance 的回复:
用fun2()举例,调用fun2()的反汇编代码:

Assembly code

char *fun2()
{
push ebp
mov ebp,esp
sub esp,44h
push ebx
push esi
push ……

debug的时候按……
[/Quote]
CInviteJavaToDance 2011-01-27
  • 打赏
  • 举报
回复
[Quote=引用 26 楼 timzhufaith 的回复:]

引用 15 楼 cinvitejavatodance 的回复:
用fun2()举例,调用fun2()的反汇编代码:

Assembly code

char *fun2()
{
push ebp
mov ebp,esp
sub esp,44h
push ebx
push esi
push ……
[/Quote]
debug的时候按Alt+8。
TimZhuFaith 2011-01-27
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 cinvitejavatodance 的回复:]
用fun2()举例,调用fun2()的反汇编代码:

Assembly code

char *fun2()
{
push ebp
mov ebp,esp
sub esp,44h
push ebx
push esi
push edi
lea edi,[ebp-44h]
……
[/Quote]用的什么工具可以看到。。。初学
赵4老师 2011-01-27
  • 打赏
  • 举报
回复
VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编不就啥都明白了吗。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
CInviteJavaToDance 2011-01-27
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 pang123hui 的回复:]

引用 3 楼 justkk 的回复:
第一个函数操作的是形式参数本身,而不是修改实参,函数调用结束后,留下了一段没有引用的内存。
第二个函数操作的是指针的地址,会为实参指针分配一块空间,ok
第三个参数返回一段已经分配好的内存的首地址,ok


第三个可不OK,p是局部变量,在执行函数终止时这个局部变量已经被销毁了
[/Quote]
我也认为第3个没问题。局部变量是销毁了,但局部变量所指的动态分配区的地址还是被return出来了。如果这里return的是局部变量p的地址,那是不行的。
pang123hui 2011-01-27
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 justkk 的回复:]
第一个函数操作的是形式参数本身,而不是修改实参,函数调用结束后,留下了一段没有引用的内存。
第二个函数操作的是指针的地址,会为实参指针分配一块空间,ok
第三个参数返回一段已经分配好的内存的首地址,ok
[/Quote]

第三个可不OK,p是局部变量,在执行函数终止时这个局部变量已经被销毁了
pang123hui 2011-01-27
  • 打赏
  • 举报
回复
你记住一点,C语言函数参数都是拷贝传递的,通过这个理解
pang123hui 2011-01-27
  • 打赏
  • 举报
回复
林锐的高质量C、C++编程指导把这个问题讲的很清楚,看看吧
niuchengshi 2011-01-26
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 wbruce 的回复:]

char *fun2();
{
char *p=(char *)malloc(sizeof(char)*10)
return p;
}
这个没问题,但是记得在外面要free,不然会内存泄露
[/Quote]



我也认为这个函数可以正确执行。尽管函数内的指针P是局部变量,但是内部是动态分配的内存,并且函数结束时,p=fun2() 这个函数外部的p可以正确指向分配的内存。只要使用完后及时释放内存即可。
CInviteJavaToDance 2011-01-26
  • 打赏
  • 举报
回复
用fun2()举例,调用fun2()的反汇编代码:

char *fun2()
{
push ebp
mov ebp,esp
sub esp,44h
push ebx
push esi
push edi
lea edi,[ebp-44h]
mov ecx,11h
mov eax,0CCCCCCCCh
rep stos dword ptr [edi];以上为常规的寄存器入栈、预留44H字节的局部栈空间、初始化11H字节的空间为0CCCCCCCCh
char *p=(char *)malloc(sizeof(char)*10);
push 0Ah
call malloc (004011b0);调用malloc函数,返回值在eax中
add esp,4
mov dword ptr [ebp-4],eax;局部变量p入栈,其值在eax内
return p;
mov eax,dword ptr [ebp-4];p的值(分配的内存首地址)存储在eax中
}
pop edi
pop esi
pop ebx
add esp,44h
cmp ebp,esp
call __chkesp (00403130)
mov esp,ebp
pop ebp;以上做一些出栈恢复和检测工作
ret

调用fun2()以后的反汇编代码:

call @ILT+35(function) (00401028)
mov dword ptr [ebp-8],eax;eax寄存器内就是分配的内存首地址,把他赋值给p。(同时,随着栈顶指针的恢复,局部变量p已经不在栈内了,也就是一般所说的“销毁”)

这样就再清楚不过了。
wbruce 2011-01-26
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 ptrunner 的回复:]
++

引用 5 楼 bdmh 的回复:
fun(str); //error 不能对指针本身进行修改
fun1(&amp;str); //OK 可以对指针指向的内容进行修改
p=fun2); //error fun2内部的p是局部变量,fun2接收后,就销毁了
[/Quote]

其中p=fun2);
楼主的意思是不是这样啊:char *p = fun2();
这样的话是正确 的,但记得在外面free(p);
pstrunner 2011-01-26
  • 打赏
  • 举报
回复
++
[Quote=引用 5 楼 bdmh 的回复:]
fun(str); //error 不能对指针本身进行修改
fun1(&str); //OK 可以对指针指向的内容进行修改
p=fun2); //error fun2内部的p是局部变量,fun2接收后,就销毁了
[/Quote]
wbruce 2011-01-26
  • 打赏
  • 举报
回复
char *fun2();
{
char *p=(char *)malloc(sizeof(char)*10)
return p;
}
这个没问题,但是记得在外面要free,不然会内存泄露
加载更多回复(11)

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧