开发者社区> 问答> 正文

C的生命周期不理解,而容易犯下的一个典型错误。?报错

char *GetMemory( void )
{
 char p[] = "hello world";
 return p;
}
 
void main( void )
{
 char *str = NULL;
 str = GetMemory();
 printf( str );

}
这个 GetMemory试图返回一个字符串。我的理解是,GetMemory函数创建了字符串p,其实p存放的是字符串的头地址,这个地址指向"hello world"的存放位置。但是函数结束的时候,p变量中存放的指向hello world的地址的内容被释放掉了,然后p中的那个地址就编程没有指向内容,内存泄漏?然后报错?是吗?


展开
收起
爱吃鱼的程序员 2020-06-22 21:00:18 525 0
1 条回答
写回答
取消 提交回答
  • https://developer.aliyun.com/profile/5yerqm5bn5yqg?spm=a2c6h.12873639.0.0.6eae304abcjaIB

    我来解释下你的问题,可能会有点长

    charp[]="helloworld";   -称为A定义方式
    char*p="helloworld";   -称为B定义方式
    两个p的区别
     

    分两种情况:

    1
    这个p是全局变量(通俗点就是在函数外面定义的)
    那么这两种方式,产生的效果有点相同的地方:

     A:使用A定义方式,只分配了 sizeof(p)== sizeof("helloworld")==12字节的内存
     (字符串长度为11,加上一个字节的结束符号)
     p是这段内存的开始地址,他不是实际的指针变量,所以  p=p+1; 这类的操作,连编译都通过不了。

     B:使用B定义方式,字符串分配了sizeof("helloworld")==12
     的内存,除了这之外还分配了sizeof(p)==sizeof(void*)的内存(一个指针的内存一般是4或8字节)
     p是一个指针,它存的值是这个字符串的开始地址。所以   p++;p="shit";  这类的操作都是合法的。

    但是如果B方式没有修改p指针的指向,这两种方式使用p都能够获取到字符串"helloworld",产生是一样的错觉,其实差别很大。
    但是有一点是相同的: 相同的字符串"helloworld"会存放在全局变量存放的地方。


    2
    这个p是局部变量(通俗点就是在函数内部定义的)
    那么这两种方式,产生的效果就会有很大的不同:

     A:使用A定义方式,只在stack(栈)中分配了12字节的内存
     p是这段内存的开始地址,他不是实际的指针变量,所以  p=p+1; 这类的操作,连编译都通过不了。
     而且只能在函数内部使用p,函数返回后,p这块内存值就是非法的了

     B:使用B定义方式,也是在全局变量区分配了sizeof("helloworld")==12的内存,
     除了这之外还在stack(栈)中分配了一个指针的内存
     p是一个指针,它存的值是这个字符串的开始地址。所以   p++;p="shit";  这类的操作都是合法的。
     但是只能在函数内部使用p

     

     

     

    还有一个可以修改和不能修改忘记说了回答的不能再好了不是内存泄露,当函数调用的时候,里面你只是用到了局部变量,自然函数调用完之后就被自动清除了,所以指针指向的地方已经没有数据了,不存在内存泄露;如果你在函数中换成malloc就可以成功返回了,不过记得自己用完后释放,否则会造成内存泄露回复 @幻の上帝:你看下我回复zerodeng的错。此处决定生存期的重点是存储类而不是作用域。自动局部对象会在块结束时销毁,但静态局部对象就不会。大概对吧回复 @Xsank:“HelloWorld”这个数据还在,会被编译器放到.rodata这个只读的段里回复 @txgcwm:多半会被覆盖,栈空间那么少如果那块内存被其他数据覆盖了,就出问题了用char*p="abc";就可以了要加const

    printf(str);

    =》楼主这样也不合理,要么就用puts(str);

    “Youshouldnever returnanaddresstoalocalvariable”

    引用来自“Xsank”的答案

    不是内存泄露,当函数调用的时候,里面你只是用到了局部变量,自然函数调用完之后就被自动清除了,所以指针指向的地方已经没有数据了,不存在内存泄露;如果你在函数中换成malloc就可以成功返回了,不过记得自己用完后释放,否则会造成内存泄露还有一个错误。字符串字面量在C语言不具有const类型,根本就没说一定要实现为映像的只读区域,更不是什么常量。因为修改字符串字面量行为未定义,所以允许实现在只读存储上。调用栈是具体的语言实现才需要考虑的,不使用栈来模拟栈语义也可行(虽然一般低效)。顺便,避免使用“堆栈”这种对新手来说稀里糊涂的翻译。仍然理解错误。局部是指作用域,而决定生存期的是存储期。只不过俗称“局部”的块作用域对象可以显式或隐式地声明为自动存储类对象(而文件作用域不行)而具有自动存储期罢了,并没有和局部进一步的联系。关于前者,是局部变量,执行的时候会在堆栈上分配空间存放数据,你可以随意操控,但是过后就被抹杀了;关于后者,其实那是常量,放在.data中,只不过你有了一个指向其地址的指针,这个是在程序执行过程中保存的,但是只可读,所以过后你依旧能访问

    引用来自“zerodeng”的答案

    引用来自“Xsank”的答案

    不是内存泄露,当函数调用的时候,里面你只是用到了局部变量,自然函数调用完之后就被自动清除了,所以指针指向的地方已经没有数据了,不存在内存泄露;如果你在函数中换成malloc就可以成功返回了,不过记得自己用完后释放,否则会造成内存泄露#Goodquestion#建议先去了解下应用程序在内存中的分布,理解堆和栈,然后再回过头来看这个就会轻松很多。
    2020-06-22 21:00:36
    赞同 展开评论 打赏
问答分类:
C++
问答地址:
问答排行榜
最热
最新

相关电子书

更多
典型业务逻辑漏洞挖掘 立即下载
阿里巴巴代码缺陷检测探索与实践 立即下载
代码未写,漏洞已出——谈谈设计不当导致的安全问题 立即下载