我在主
中有这个电话char* IDQueueString = getIDQueue();
pc.printf("[%9.6f] IDQueue: %s\r\n", t.read(), IDQueueString);
free(IDQueueString);
getIDQueue();是
char* getIDQueue(void)
{
char* returnString;
char idString[6];
uint8_t pointer = 0;
uint8_t queueLength = 0;
returnString = (char*)malloc((uint32_t)(sizeof(char*)*128));
if(returnString != 0){
pc.printf("[%9.6f] MALLOC: %p, len: %d | LINE %d\r\n", t.read(), returnString, (int)(sizeof(char*)*128), __LINE__);
for(uint8_t i = 0; i < ID_QUEUE_LENGTH; i ++){
if(ReceivedIDs[i].id != -1){
queueLength++;
sprintf(idString, "%d", (int)ReceivedIDs[i].id);
for(uint8_t j = 0; j < strlen(idString); j++){
returnString[pointer] = idString[j];
pointer++;
}
returnString[pointer++] = ',';
returnString[pointer++] = ' ';
}
}
if(queueLength > 0){
returnString[pointer-2] = '.';
returnString[pointer-1] = '\0';
}
if(queueLength == 0){
returnString = (char*)"Empty!";
}
return returnString;
}else{
free(returnString);
error("\x1b[31mMALLOC %d!\x1b[0m\r\n", __LINE__);
return (char*)"MALLOC!";
}
}
当它在二进制文件中达到free(IDQueueString);
时,它会在指令链的某处执行:
0x08009d6c: ldr r6, [r1, #8] // *0x2000a208, *0x20008500
0x08009d6e: ldr r0, [r2, #4] // *0x200080d8, *0x1002db40
0x08009d70: cmp r2, r6 // *0x1002db40, *0x2000a208
但是它挂起在0x08009d6e
(或者更确切地说是返回到一个循环自身的WIRQ循环
0x08004ffc: b.n 0x8004ffc
我想知道是什么导致它这样做的?
显然free();
导致问题,但我无法弄清问题是什么。 r1
和r2
的值为0x00000000
,r0
为0x00000009
,r6
为0x5DECC885
。
地址0x20000001-0x2001BFFF (112KB)
是SRAM1的范围,0x2001C000-0x2001FFFF (16KB)
是SRAM2的范围。
我不知道0x5DECC885
的价值是什么,但它可能与USB-OCD接口有关。
我假设我使用free的方式不正确但是因为我返回指向malloc();
的指针,为什么我不能按照我想要的方式释放返回的指针?
答案 0 :(得分:1)
你不能免除那些来自malloc
的东西 - 它是&#34;未定义的行为&#34;这样做,所以取决于运行时的设计方式,实际发生的事情是&#34;一切皆有可能&#34;它可能会挂起,崩溃,通过向特朗普签署的普京发送粗鲁的信息来开始核战争,或者是&#34;很好&#34;。
您的特定情况有两种解决方案:
如果malloc
失败,请返回NULL
(如果我们在C ++中,则返回nullptr
)。如果队列为空,则返回一个malloc
&#39; d字符串,其中包含字符串&#34; Empty!&#34; (通过赋值strcpy
或类似)。
或者,这只有在您知道队列不包含"Empty!"
或"MALLOC!"
等字词时才有效:在您致电free
之前,请检查它是否为&# 39; t其中一个字符串(使用if(strcmp("Emtpy!", ...) != 0 && strcmp("MALLOC!", ...) != 0) free(...);
。
通过在已知字符串列表中包含这些字符串可以使这更容易,并且只返回该条目,然后您可以使用一个函数来检查&#34;它是一个已知的常量字符串&#34;通过比较指针值本身。 [事实上,当您正在处理的内容中存在相同的内容字符串时,这也会起作用,因为如果来自您的代码,内容字符串将具有不同的地址] - 它还有助于避免&#34的问题;哦,我更改了返回字符串的值,但没有更改自由之前的检查&#34;,因为它只是一个可供机器人使用的地方。
答案 1 :(得分:0)
每当我看到拆解列表时,我就会知道它会是愚蠢的。错误的程序逻辑 - 但编译器必须是错误的:)
在函数调用之前分配内存是一件好事。返回前应释放所有本地malloc。它使调试代码变得更容易(特别是内存泄漏)。
你有很多方式与程序的另一部分进行通信,但你选择的那个是最糟糕的。首先,将错误(如失败的mallocs)与应用程序异常(例如空名称)分开是很好的。我自己会让这个函数返回int(例如负数作为系统错误,如果OK则为零,对应用程序异常为正) - 使得处理它们更容易,并且指针通过指针返回指针。 但是你想在函数中使用malloc(并且不要自由) -
if((resultCode = getIDQueue(& IDQueueString) >= 0)
{
// do something (you can have another switch here to deal with application exceptions like empty name for example)
free(IDQueueString);
}
else
{
switch (resultCode)
{
case -1:
// do something malloc failed
break:
case -2:
//deal with another error
break;
//...... etc etc
default:
// ----
break;
}
}