从内存的角度看free(p) , p=NULL

讲C的书多告诉我们malloc出的内存用完要free掉,为了避免出现野指针,还要将指针置为NULL。

今天做了个小实验,从内存的角度看free()究竟做了什么、为什么最后要把指针设为NULL。

-----

看下面的例子:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2.   
  3. int main(int argc, char **argv) {  
  4.     int *p = (int *)malloc(sizeof(int));  
  5.     *p = 1;  
  6.     printf("p: %p, *p:%d\n", p, *p); // p: 0x1f1c010, *p:1  
  7.   
  8.     free(p); // free之后,p的内存地址没有变,而p指向的内容置为0了,此时p是野指针  
  9.     printf("p: %p, *p:%d\n", p, *p); // p: 0x1f1c010, *p:0  
  10.   
  11.     *p = 2;  //错误的操作野指针,观察内存:  
  12.     printf("p: %p, *p:%d\n", p, *p); // p: 0x1f1c010, *p:2  
  13.   
  14.     // double free错误,这个是肯定的。  
  15.     //free(p);  
  16.     //printf("p: %d, *p:%d\n", p, *p);  
  17.   
  18.     p = NULL; //  此时不能对p进行解引,p是空指针  
  19.     printf("p: %p\n", p); // p: (nil)  
  20.   
  21.     return 0;  
  22. }  

---

update:


重新翻了下K&R,发现书上说的也确实如此! 
下面是stackoverflow上的一个回答(地址:http://stackoverflow.com/questions/2468853/freeing-memory-twice) 
  
Freeing memory does not set the pointer to null. The pointer remains pointing to the memory it used to own, but which has now had ownership transferred back to the heap manager. 
  
The heap manager may have since reallocated the memory your stale pointer is pointing to. 
  
Freeing it again is not the same as saying free(NULL), and will result in undefined behavior. 
  
我的理解: 
  
在第一次free()调用后,堆管理器将我们free()的内存和相邻的块重新组成了新的更大的块,以便下次malloc()调用,这时,这块内存已经不属于malloc出的内存了,对非malloc出的内存进行free,其结果是未定义的(我们这里是double free crash)。 
-- 
  
update: 
  
参考:http://code.woboq.org/userspace/glibc/malloc/malloc.c.html 
malloc出来的内存块结构: 
  
1. An allocated chunk looks like this: 


    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
            |             Size of previous chunk, if allocated            | | 
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
            |             Size of chunk, in bytes                       |M|P| 
      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
            |             User data starts here...                          . 
            .                                                               . 
            .             (malloc_usable_size() bytes)                      . 
            .                                                               | 
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
            |             Size of chunk                                     | 
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+  

空闲块结构: 
2. Free chunks are stored in circular doubly-linked lists, and look like this: 

    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
            |             Size of previous chunk                            | 
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
    `head:' |             Size of chunk, in bytes                         |P| 
      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
            |             Forward pointer to next chunk in list             | 
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
            |             Back pointer to previous chunk in list            | 
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
            |             Unused space (may be 0 bytes long)                . 
            .                                                               . 
            .                                                               | 
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
    `foot:' |             Size of chunk, in bytes                           | 
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

第一次free: 

first_free.png 
第二次free: 

double_free.png 
看double free后出现了2块同样的chunk,堆管理器显然是不能同意的! 


原文:http://blog.youkuaiyun.com/wusuopubupt/article/details/39006561


### C++ 实现 WGS84 和 CGCS2000 坐标转换方法 #### 使用 Proj.4 库进行坐标转换 为了在C++中实现WGS84和CGCS2000之间的坐标转换,可以利用Proj.4库。此库提供了强大的地理空间数据处理功能,并支持多种坐标系统的相互转换。 安装并配置好Proj.4之后,在程序里初始化两个PJ对象分别代表源坐标系(这里是WGS84)和目标坐标系(即CGCS2000)。通过`pj_transform()`函数完成实际的数据变换操作: ```cpp #include <proj_api.h> #include <iostream> void transform_coordinates(double& lon, double& lat){ proj_init(); // 初始化PROJ.4环境 const char* wgs84_def = "+init=epsg:4326"; // 定义WGS84坐标系参数字符串 const char* cgcs2000_def = "+init=epsg:4527"; // 定义CGCS2000坐标系参数字符串 PJ *P_wgs84 = pj_init_plus(wgs84_def); // 创建WGS84投影定义结构体指针 PJ *P_cgcs2000 = pj_init_plus(cgcs2000_def); // 创建CGCS2000投影定义结构体指针 if (!P_wgs84 || !P_cgcs2000) { std::cerr << "Failed to initialize projection definitions." << std::endl; exit(1); } /* Convert from geographic (lat/lon) coordinates in degrees */ lon *= DEG_TO_RAD; // 将输入的经度由角度单位转化为弧度制 lat *= DEG_TO_RAD; // 同上对于纬度做相同的操作 int err = pj_transform(P_wgs84, P_cgcs2000, 1, 1, &lon, &lat, NULL); if (err != 0) { printf("Error transforming point (%d)\n", err); } else { lon /= DEG_TO_RAD; // 输出前再把结果变回角度表示形式 lat /= DEG_TO_RAD; } pj_free(P_wgs84); // 清理资源释放内存 pj_free(P_cgcs2000); } ``` 上述代码展示了如何使用Proj.4库来执行从WGS84到CGCS2000坐标的转换过程[^1]。需要注意的是,这里假设已经正确设置了编译器路径以及链接了必要的动态链接库文件以便能够调用Proj.4的相关API接口。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值