提问人:nik 提问时间:2/9/2023 更新时间:2/10/2023 访问量:65
动态分配的内存是否需要在周期数不确定的循环中释放?
Does dynamically-allocated memory need to be freed inside a loop of undetermined number of cycles?
问:
尝试将字符串缓冲区保留在 C 循环中的未定义行为。
大家好!在引入任何分配方法时,我似乎得到了未定义的行为,尽管我试图遵循我发现的有关释放和解除分配的所有内容。这是一段代码在无限循环中运行,所以我想这可能与它有关?calloc
malloc
上下文:尝试在仿真NIOS II处理器的FPGA板上更新数字滤波器的系数。
目前,我已经稍微简化了代码,只是在发送字符后开始将字符收集到中,并在发送字符后停止收集。在这种情况下,可以假设在 和 之间发送的字符不超过 30 个字符,该字符由经过测试的 python 脚本在主机端处理。buffer
c
x
c
x
} else if (prompt == 'c') { // check that control signal = c
// let host know that 'c' is received
printf("BOARD: preparing for coefficient update\n");
// MEMORY ALLOCATION
char *buffer = calloc(30, sizeof(char));
buffer[30] = '\0'; // set a null pointer at the end of string
// check, this should print a blank character
printf("buffer init is : %c\n", buffer[0]);
int count = 0;
prompt = getc(fp); // reads from jtag_uart interface (tested and working)
while (prompt != 'x'){
buffer[count] = prompt;
printf("buffer inside loop is : %s\n", buffer);
printf("BOARD >> Received: %c\n", prompt);
prompt = getc(fp);
count++;
}
free(buffer);
buffer=NULL;
}
“未定义”行为仅与以下方面有关: 有时它会在终端中打印(这就是我希望它做的):buffer
MESSAGE STREAM:
['1', '.', '2', ',', '3', '.', '5', ',']
BOARD: preparing for coefficient update
buffer init is : // <----------------------------
initiating transmission....
HOST: sending 1
buffer inside loop is : 1
BOARD >> Received: 1
HOST: sending .
buffer inside loop is : 1.
BOARD >> Received: .
HOST: sending 2
buffer inside loop is : 1.2
BOARD >> Received: 2
HOST: sending ,
buffer inside loop is : 1.2,
BOARD >> Received: ,
HOST: sending 3
buffer inside loop is : 1.2,3
BOARD >> Received: 3
HOST: sending .
buffer inside loop is : 1.2,3.
BOARD >> Received: .
HOST: sending 5
buffer inside loop is : 1.2,3.5
BOARD >> Received: 5
HOST: sending ,
buffer inside loop is : 1.2,3.5,
BOARD >> Received: ,
end of transmission
有时它不会:
MESSAGE STREAM:
['3', '.', '4', '5', ',', '2', '.', '4', '4', ',']
BOARD: preparing for coefficient update
initiating transmission....
HOST: sending 3
BOARD >> Received: 3
HOST: sending .
BOARD >> Received: .
HOST: sending 4
BOARD >> Received: 4
HOST: sending 5
BOARD >> Received: 5
HOST: sending ,
BOARD >> Received: ,
HOST: sending 2
BOARD >> Received: 2
HOST: sending .
BOARD >> Received: .
HOST: sending 4
BOARD >> Received: 4
HOST: sending 4
BOARD >> Received: 4
HOST: sending ,
BOARD >> Received: ,
end of transmission
我假设这是一个问题,因为我对内存分配的概念很陌生,并且该项目的所有其他功能都运行良好 - 并且在不工作时是可以预测的。c
有没有人能够在这里发现任何明显的问题?或者让我知道我是否应该发布其他内容?任何帮助将不胜感激:)
TLDR:尝试保留每个循环周期中附加的字符缓冲区。
结果是未定义的行为,有时它有效,但更多时候,程序只是跳过了打印语句。
答:
这里的问题不在于内存分配,而在于打印。
出于某种原因,偶尔会阻止缓冲区打印语句。将其替换为并打印到文件可以修复它。不知道为什么这只会对某些打印语句产生影响,特别是因为 配置为 .printf
fprintf
/dev/jtag_uart
jtag_uart
stdout
偏离一个错误:
char *buffer = calloc(30, sizeof(char));
buffer[30] = '\0';
“除了 buffer[30] = '\0' 是错误的之外,它也是无用的,因为 calloc
已经用 0 填充了分配的缓冲区。而关联的注释在字符串末尾设置一个空指针是没有意义的。— 贾伯沃基
“如果一个数组有 n 个元素,则有效索引为 0 到 n-1(含)。在本例中,您分配了 30 个元素,因此有效索引为 0 到 29。那么,您认为写入索引 30 会做什么呢?这是未定义的行为。— 汤姆·卡泽斯
“回复:但我尝试过有和没有,都没有区别。”*
因为这是未定义的行为。它可能有效,也可能无效。依赖它不是一个好主意。
不要丢弃 calloc()
的返回值:
char *buffer = calloc (30);
if (!buffer) {
/* ENOMEM, handle error here */
}
评论
buffer[30]
是超过已分配数组末尾的 1。buffer[30] = '\0'
callloc
n
0
n-1
30
0
29
30