C语言中动态分配内存的问题

名人堂再聚首 2014-05-28 10:59:16
各位好!

我现在有一个单片机项目,使用stm32f103系列单片机,并使用RS485和无线2.4G(nRF24L01)两种通信方式和客户端通信,一台MCU作服务端,其他作为客户端(每个客户端都有一个唯一识别的设备ID)。
我的设计是这样的:

服务端使用lwip网络协议栈和上位机通信,接收上位机的指令,然后服务端将上位机发来的数据发送到RS485总线或者通过无线2.4G直接发送到客户端。服务端保存了每个客户端设备的信息,包括:设备ID,通信方式,通道地址。其中设备ID用于唯一标识某个客户端设备,通信方式表示客户端设备是RS485方式通信还是无线2.4G方式通信,通道地址表示无线2.4G设备地址。每个客户端设备的信息都保存在服务端MCU的AT24C04中,客户端设备信息采用了一个结构体来保存,定义如下:


/**************** Device Structure *******************/
struct device {
u16 DeviceID; //Device Identifier
//char Name[10]; //Device Name which can be customized
u8 IsRS485; //Is this device using RS485 bus to send out data? 1:RS485 bus,0:nRF24L01 wireless 2.4G
u8 Address[5]; //Device address, for each nRF24L01 has a unique device address which consists of 5 bytes
};

typedef struct device DEVICE; //Define a new type replacing "struct device"

并且我使用宏定义了客户端设备最大数量(默认不超过30个):

#define MAX_DEVICE_CNT 0x1E /* Maximum Devices Available */


我定义了一个全局指针变量用来保存所有的客户端设备,在程序初始化时从AT24C04得到所有的设备:
全局指针变量和实际客户端设备的总数量:

u8 DEVICE_NBR=0; //全局变量保存已有的保存在AT24C04中的设备数量
DEVICE* ALL_DEVICE; //全局变量保存所有的设备信息


在初始化得到所有的客户端设备:

/*
* 函数名:Get_Devices
* 描述 :从AT24C02中得到全部的设备信息
* 输入 :无
* 输出 :无
* 调用 :外部调用
*/
void Get_Devices(void)
{
u8 dev_num=0; //从AT24C04读取设备数量
I2C_EE_BufferRead(&dev_num, EEPROM_BASE_ADDR_DEVICE, 1);
if (dev_num!=0xff && dev_num<=MAX_DEVICE_CNT){//判断是否超出最大数量
u8 * result;
u8 i=0, j=0;
DEVICE *device;
DEVICE_NBR = dev_num; //保存总的设备数量

//DEVICE_DATA_LEN是结构体的数据长度,应该就是sizeof(DEVICE)

//动态分配内存保存从AT24C04中读取出来的所有设备数据
result=(u8*)malloc(dev_num * DEVICE_DATA_LEN); //最大30个设备,每个8字节数据,就是DEVICE_DATA_LEN
//result=(u8*)calloc(dev_num, DEVICE_DATA_LEN); //为一维数分配dev_num个元素,每个元素占8个字节

//分配ALL_DEVICE所需要的内存空间
ALL_DEVICE=(DEVICE*)malloc(dev_num * sizeof(DEVICE));
device=ALL_DEVICE;

//根据设备数量从AT24C04读取指定长度的数据并保存在result中
I2C_EE_BufferRead(result, EEPROM_BASE_ADDR_DEVICE+1, dev_num*DEVICE_DATA_LEN);

for(i=0;i<dev_num * DEVICE_DATA_LEN;i=i+DEVICE_DATA_LEN){
device->DeviceID=((result[i+1]&0x00FF)<<8)|(result[i]&0x00FF); //设备序号
device->IsRS485=result[i+2]; //通讯方式
for(j=0;j<5;j++){ //无线2.4G通道地址,5个字节
device->Address[j]=result[i+3+j];
}
device++;
}

free(result); //释放分配的空间
free(ALL_DEVICE);
}
}


我没有使用数组,是使用的动态分配内存的方式,原因是:AT24C04中保存了多少条设备信息就开辟多少内存来保存,而不用定义一个固定大小的数组,数组大小为设备最大总数量,也就是MAX_DEVICE_CNT。另外使用 ALL_DEVICE全局变量来保存所有的设备信息,需要用时就可以直接访问它。
可是问题来了,为什么我使用了free(ALL_DEVICE)之后,(ALL_DEVICE)还可以使用呢?
调用它的代码如下:

u8 i=0; //循环计数器
u8 rs485=0; //设备通信方式1:RS485总线,0:nRF24L01无线2.4G
u8 *addr=NULL; //保存设备地址
u16 device_id=0; //保存网络传来的设备信息
DEVICE * d=ALL_DEVICE; //根据网络传来的设备信息从列备列表中查找
device_id=((arg[2]&0x00FF)<<8)|(arg[1]&0x00FF); //得到要操作的设备ID
//for(d=ALL_DEVICE;d<ALL_DEVICE+DEVICE_NBR;d++)
for(i=0;i<DEVICE_NBR;i++)
{
if (device_id==d->DeviceID) //如果找到匹配的设备信息
{
rs485=d->IsRS485; //得到当前设备的数据传输方式
addr=d->Address; //得到当前设备的nRF24L01无线2.4G模块地址
break;
}
d++;
}
if (rs485==1)//使用RS485方式通信
{
//服务端处理
}
else //无线2.4G方式
{
//服务端 处理
}


麻烦各位帮我看下,这样使用动态分配内存有没有问题,如果我不想使用固定长度的数组,有其他更好的方法吗?为什么我使用了free函数后,ALL_DEVICE还能用呢?谢谢各位了!
...全文
209 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
pathletboy 2014-05-28
  • 打赏
  • 举报
回复
上楼打错,多手误了,看这个 申明时候 DEVICE* ALL_DEVICE = NULL;这么申明,然后malloc之前判断下 if (ALL_DEVICE) { free(ALL_DEVICE); } ALL_DEVICE = (DEVICE*)malloc(dev_num * sizeof(DEVICE));
pathletboy 2014-05-28
  • 打赏
  • 举报
回复
引用 2 楼 jmmx 的回复:
那如果我要保持一个指向动态分配内存的全局指针,那么在调用malloc后是不是不能调用free,如果下次再重新调用Get_Devices()函数时是不是先调用free,先释放,然后再分配内存给ALL_DEVICE?
申明时候 DEVICE* ALL_DEVICE = NULL;这么申明,然后malloc之前判断下 if (!ALL_DEVICE) { free(ALL_DEVICE); } ALL_DEVICE = (DEVICE*)malloc(dev_num * sizeof(DEVICE));
名人堂再聚首 2014-05-28
  • 打赏
  • 举报
回复
那如果我要保持一个指向动态分配内存的全局指针,那么在调用malloc后是不是不能调用free,如果下次再重新调用Get_Devices()函数时是不是先调用free,先释放,然后再分配内存给ALL_DEVICE?
pathletboy 2014-05-28
  • 打赏
  • 举报
回复
free后只是标记内存空闲,这时候你的指针就是野指针,虽然可以访问,但是不是合法的。举个简单例子,火车上座位,你是站票,但是偶尔有座位你也可以坐下,但是来人你得让,不让打架就出事了。
名人堂再聚首 2014-05-28
  • 打赏
  • 举报
回复
引用 4 楼 pathletboy 的回复:
上楼打错,多手误了,看这个 申明时候 DEVICE* ALL_DEVICE = NULL;这么申明,然后malloc之前判断下 if (ALL_DEVICE) { free(ALL_DEVICE); } ALL_DEVICE = (DEVICE*)malloc(dev_num * sizeof(DEVICE));
好的,谢谢你,我先试下!

27,374

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 单片机/工控
社区管理员
  • 单片机/工控社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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