关于free,我不知道的事——求解释!

时间:2021-03-14 15:26:23
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char *p = malloc(10);
    if(NULL == p)
    {   
        perror("malloc");
        return 0;
    }   
    printf("p1=%08x\n",p);
    strcpy(p,"111111111012");//大于等于"111111111012345"会报错
    printf("%s\n",p);

    free(p);
    printf("p2=%08x\n",p);
        
    strcpy((char*)p,"222222222");
    printf("%s\n",p);
    strcpy((char*)p,"33333333301234567890");
    printf("%s\n",p);

    return 0;
}

上述代码有三处以上的错误(都是我故意写的)。
可我在linux下运行gcc一样可以编译,而且运行得就像啥事都没有一样欢畅,三个都能print。
当然,我若在第一个printf后面strcpy一个长于15的字符串它才不行,才晓得报错。
难道我的代码被优化了,如果是,那也不能优化得这么离谱吧。
版本?4.1的版本不能存在问题吧?我用的可是公司服务器的linux系统。
我的理解是,free掉的内存,至少不可写吧。可事实不像是这样,反而能写很长!
盼高人指点!!!
gcc version 4.1.2 20080704 (Red Hat 4.1.2-44)

18 个解决方案

#1


该回复于2011-11-23 16:45:46被版主删除

#2


首先,你请求分配10字节的数据,但是为了 内存对齐,它实际给你分配的是 16 字节的空间,内存对齐的概念就跟struct 数据成员对齐是一个概念,都是为了提高存储器的效率。
再次,你free掉以后,分配给进程的地址空间还是存在的,但此时的p已经成了野指针,不能保证对数据的访问是“可重现的”(即多次运行程序,结果不一定能完全一致),比如你在free之后调用了一个malloc给另一个指针(设为pp)赋值,那么原先的p指针指向的可能就和pp指向同一区域

#3


1 c语言对越界处理的不是很好,所以程序因内存拷贝,赋值等导致越界的情况很多

楼主拷贝字符串的时候,虽然拷贝的字符已经远远超过了申请的10个字节,但是程序是不会理睬的,程序执行的就是拷贝动作,不关心是否已经超过了申请的大小,这样多出来的字符就存放到了没有规划的空间上,如果这块空间上就被偷着修改了,当这块空间的主人使用的时候,就会出现问题,问题现象是不可预期的,如果这块空间没有分配,就不会出任何问题。

2 free函数只负责释放空间,但是指针指向的地址仍未原来对应的地址,所以一般free后需要清空操作,
p = NULL;如果不清空,则指向的还是原来的地址,由于这块地址是刚释放的,没有主人,就可以肆意挥霍了,程序也不会出现错误。

#4


野指针

#5


野指针也可以用,而且在debug的时候似乎不太容易出错,特别是你只运行一次两次的话。

最基本的原则,new delete、malloc free成对出现。delete free后,马上把指针置NULL。

如果是C++的话,建议使用智能指针,这个非常可靠

#6


LS的都说出来了。

#7


如果你释放之后,这段内存被申请做其他用途,那么你的行为就很可能修改了其他数据。错误代码不能以短时间之内或者说偶尔运行两次崩溃不崩溃作为衡量标准吧。

#8


引用 2 楼 seucs 的回复:
首先,你请求分配10字节的数据,但是为了内存对齐,它实际给你分配的是 16 字节的空间,内存对齐的概念就跟struct 数据成员对齐是一个概念,都是为了提高存储器的效率。
再次,你free掉以后,分配给进程的地址空间还是存在的,但此时的p已经成了野指针,不能保证对数据的访问是“可重现的”(即多次运行程序,结果不一定能完全一致),比如你在free之后调用了一个malloc给另一个指针(设为pp)赋……


即便是对齐,为什么是16呢?
正常情况下按四字节对齐,那也应该是12啊,是吧?

#9


引用 8 楼 xinshirn 的回复:
引用 2 楼 seucs 的回复:
首先,你请求分配10字节的数据,但是为了内存对齐,它实际给你分配的是 16 字节的空间,内存对齐的概念就跟struct 数据成员对齐是一个概念,都是为了提高存储器的效率。
再次,你free掉以后,分配给进程的地址空间还是存在的,但此时的p已经成了野指针,不能保证对数据的访问是“可重现的”(即多次运行程序,结果不一定能完全一致),比如你在free之后调用了一个……
这里说的对齐是说分配的内存大小按照16字节对齐。

#10


嗯,用智能指针吧,自己管理资源

#11


free()之后的空间会可以继续使用,但是你的指针指向的地址不一定就是原来的地址了。有可能会指向原来的地址,所以你可以继续使用。但这样做会很危险,所以不要把free()释放后的指针不要在使用,为了防止再次使用会正常显示,你可以把释放后的指针指向NULL.下次使用时,会立即报错。

#12


引用 3 楼 w28050 的回复:
1 c语言对越界处理的不是很好,所以程序因内存拷贝,赋值等导致越界的情况很多

楼主拷贝字符串的时候,虽然拷贝的字符已经远远超过了申请的10个字节,但是程序是不会理睬的


strcpy不检查目标地址的可用性?我记得有断言啊。难道没有?

引用 3 楼 w28050 的回复:
2 free函数只负责释放空间,但是指针指向的地址仍未原来对应的地址,所以一般free后需要清空操作,
p = NULL;如果不清空,则指向的还是原来的地址,由于这块地址是刚释放的,没有主人,就可以肆意挥霍了,程序也不会出现错误。

free掉的堆空间,还具有可写属性吗?

#13


引用 10 楼 yuelengdihai 的回复:
嗯,用智能指针吧,自己管理资源


我们现在的项目只用c,c++不用的。
另外,解决问题有很多种办法,我现在关心的是问题出现的原因

#14


引用 11 楼 cfjtaishan 的回复:
free()之后的空间会可以继续使用,但是你的指针指向的地址不一定就是原来的地址了。有可能会指向原来的地址,所以你可以继续使用。但这样做会很危险,所以不要把free()释放后的指针不要在使用,为了防止再次使用会正常显示,你可以把释放后的指针指向NULL.下次使用时,会立即报错。

我了解常规做法是要在free掉后对指针赋空的安全做法,正常写程序也不会做这么危险的事。

free的行为是释放空间。
我想了解所谓的“释放空间”具体都干了什么?
除了让这片空间有可再被分配的属性外。它还具有可写属性?

#15


引用 12 楼 xinshirn 的回复:
引用 3 楼 w28050 的回复:
1 c语言对越界处理的不是很好,所以程序因内存拷贝,赋值等导致越界的情况很多

楼主拷贝字符串的时候,虽然拷贝的字符已经远远超过了申请的10个字节,但是程序是不会理睬的

strcpy不检查目标地址的可用性?我记得有断言啊。难道没有?

free掉的空间如果没有把指针置空即置为NULL, 指针是不为空的,只是它指向的空间不属于它而已。
引用 3 楼 w28050 的回复:2 free函数只负责释放空间,但是指针指向的地址仍未原来对应的地址,……

#16


该回复于2011-11-24 09:32:47被版主删除

#17


1 strcpy 函数如何检测目标地址的可用性能,如果目标地址为空,会断言,对越界之类的是不做断言的

2 在vc中free会检查对应的指针是否有越界现象,如果越界,运行时会出现问题,但如果不设为空,是可以继续通过该指针向原地址里面拷贝数据的。

以上在VC中验证过,gcc中没做过验证。

#18


个人觉得free掉得空间能不能写,不由我们决定,而由操作系统决定。

#1


该回复于2011-11-23 16:45:46被版主删除

#2


首先,你请求分配10字节的数据,但是为了 内存对齐,它实际给你分配的是 16 字节的空间,内存对齐的概念就跟struct 数据成员对齐是一个概念,都是为了提高存储器的效率。
再次,你free掉以后,分配给进程的地址空间还是存在的,但此时的p已经成了野指针,不能保证对数据的访问是“可重现的”(即多次运行程序,结果不一定能完全一致),比如你在free之后调用了一个malloc给另一个指针(设为pp)赋值,那么原先的p指针指向的可能就和pp指向同一区域

#3


1 c语言对越界处理的不是很好,所以程序因内存拷贝,赋值等导致越界的情况很多

楼主拷贝字符串的时候,虽然拷贝的字符已经远远超过了申请的10个字节,但是程序是不会理睬的,程序执行的就是拷贝动作,不关心是否已经超过了申请的大小,这样多出来的字符就存放到了没有规划的空间上,如果这块空间上就被偷着修改了,当这块空间的主人使用的时候,就会出现问题,问题现象是不可预期的,如果这块空间没有分配,就不会出任何问题。

2 free函数只负责释放空间,但是指针指向的地址仍未原来对应的地址,所以一般free后需要清空操作,
p = NULL;如果不清空,则指向的还是原来的地址,由于这块地址是刚释放的,没有主人,就可以肆意挥霍了,程序也不会出现错误。

#4


野指针

#5


野指针也可以用,而且在debug的时候似乎不太容易出错,特别是你只运行一次两次的话。

最基本的原则,new delete、malloc free成对出现。delete free后,马上把指针置NULL。

如果是C++的话,建议使用智能指针,这个非常可靠

#6


LS的都说出来了。

#7


如果你释放之后,这段内存被申请做其他用途,那么你的行为就很可能修改了其他数据。错误代码不能以短时间之内或者说偶尔运行两次崩溃不崩溃作为衡量标准吧。

#8


引用 2 楼 seucs 的回复:
首先,你请求分配10字节的数据,但是为了内存对齐,它实际给你分配的是 16 字节的空间,内存对齐的概念就跟struct 数据成员对齐是一个概念,都是为了提高存储器的效率。
再次,你free掉以后,分配给进程的地址空间还是存在的,但此时的p已经成了野指针,不能保证对数据的访问是“可重现的”(即多次运行程序,结果不一定能完全一致),比如你在free之后调用了一个malloc给另一个指针(设为pp)赋……


即便是对齐,为什么是16呢?
正常情况下按四字节对齐,那也应该是12啊,是吧?

#9


引用 8 楼 xinshirn 的回复:
引用 2 楼 seucs 的回复:
首先,你请求分配10字节的数据,但是为了内存对齐,它实际给你分配的是 16 字节的空间,内存对齐的概念就跟struct 数据成员对齐是一个概念,都是为了提高存储器的效率。
再次,你free掉以后,分配给进程的地址空间还是存在的,但此时的p已经成了野指针,不能保证对数据的访问是“可重现的”(即多次运行程序,结果不一定能完全一致),比如你在free之后调用了一个……
这里说的对齐是说分配的内存大小按照16字节对齐。

#10


嗯,用智能指针吧,自己管理资源

#11


free()之后的空间会可以继续使用,但是你的指针指向的地址不一定就是原来的地址了。有可能会指向原来的地址,所以你可以继续使用。但这样做会很危险,所以不要把free()释放后的指针不要在使用,为了防止再次使用会正常显示,你可以把释放后的指针指向NULL.下次使用时,会立即报错。

#12


引用 3 楼 w28050 的回复:
1 c语言对越界处理的不是很好,所以程序因内存拷贝,赋值等导致越界的情况很多

楼主拷贝字符串的时候,虽然拷贝的字符已经远远超过了申请的10个字节,但是程序是不会理睬的


strcpy不检查目标地址的可用性?我记得有断言啊。难道没有?

引用 3 楼 w28050 的回复:
2 free函数只负责释放空间,但是指针指向的地址仍未原来对应的地址,所以一般free后需要清空操作,
p = NULL;如果不清空,则指向的还是原来的地址,由于这块地址是刚释放的,没有主人,就可以肆意挥霍了,程序也不会出现错误。

free掉的堆空间,还具有可写属性吗?

#13


引用 10 楼 yuelengdihai 的回复:
嗯,用智能指针吧,自己管理资源


我们现在的项目只用c,c++不用的。
另外,解决问题有很多种办法,我现在关心的是问题出现的原因

#14


引用 11 楼 cfjtaishan 的回复:
free()之后的空间会可以继续使用,但是你的指针指向的地址不一定就是原来的地址了。有可能会指向原来的地址,所以你可以继续使用。但这样做会很危险,所以不要把free()释放后的指针不要在使用,为了防止再次使用会正常显示,你可以把释放后的指针指向NULL.下次使用时,会立即报错。

我了解常规做法是要在free掉后对指针赋空的安全做法,正常写程序也不会做这么危险的事。

free的行为是释放空间。
我想了解所谓的“释放空间”具体都干了什么?
除了让这片空间有可再被分配的属性外。它还具有可写属性?

#15


引用 12 楼 xinshirn 的回复:
引用 3 楼 w28050 的回复:
1 c语言对越界处理的不是很好,所以程序因内存拷贝,赋值等导致越界的情况很多

楼主拷贝字符串的时候,虽然拷贝的字符已经远远超过了申请的10个字节,但是程序是不会理睬的

strcpy不检查目标地址的可用性?我记得有断言啊。难道没有?

free掉的空间如果没有把指针置空即置为NULL, 指针是不为空的,只是它指向的空间不属于它而已。
引用 3 楼 w28050 的回复:2 free函数只负责释放空间,但是指针指向的地址仍未原来对应的地址,……

#16


该回复于2011-11-24 09:32:47被版主删除

#17


1 strcpy 函数如何检测目标地址的可用性能,如果目标地址为空,会断言,对越界之类的是不做断言的

2 在vc中free会检查对应的指针是否有越界现象,如果越界,运行时会出现问题,但如果不设为空,是可以继续通过该指针向原地址里面拷贝数据的。

以上在VC中验证过,gcc中没做过验证。

#18


个人觉得free掉得空间能不能写,不由我们决定,而由操作系统决定。