动态分配的内存是否需要在周期数不确定的循环中释放?

Does dynamically-allocated memory need to be freed inside a loop of undetermined number of cycles?

提问人:nik 提问时间:2/9/2023 更新时间:2/10/2023 访问量:65

问:

尝试将字符串缓冲区保留在 C 循环中的未定义行为。

大家好!在引入任何分配方法时,我似乎得到了未定义的行为,尽管我试图遵循我发现的有关释放和解除分配的所有内容。这是一段代码在无限循环中运行,所以我想这可能与它有关?callocmalloc

上下文:尝试在仿真NIOS II处理器的FPGA板上更新数字滤波器的系数。

目前,我已经稍微简化了代码,只是在发送字符后开始将字符收集到中,并在发送字符后停止收集。在这种情况下,可以假设在 和 之间发送的字符不超过 30 个字符,该字符由经过测试的 python 脚本在主机端处理。buffercxcx

} 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:尝试保留每个循环周期中附加的字符缓冲区。

结果是未定义的行为,有时它有效,但更多时候,程序只是跳过了打印语句。

c 管理 泄漏 malloc 动态内存分配

评论

1赞 dbush 2/9/2023
buffer[30]是超过已分配数组末尾的 1。
0赞 Jabberwocky 2/9/2023
除了错误之外(参见之前的评论),它也是无用的,因为已经用 0 填充了分配的缓冲区。并且关联的注释在字符串末尾设置一个空指针是没有意义的。您没有在此处设置指针。只需删除整行,您应该没问题(除非代码中的其他地方有更多问题)buffer[30] = '\0'callloc
0赞 Tom Karzes 2/9/2023
您应该阅读描述 C 数组的教程。如果数组包含元素,则有效索引为 through ,包括 。在本例中,您正在分配元素,因此有效索引通过 。那么你认为写入索引会做什么呢?这是未定义的行为,会导致您在此处发帖寻求帮助。n0n-13002930
0赞 Tom Karzes 2/9/2023
如果需要存储 30 个字符(不包括终止 null 字符),则需要为 31 个字符分配空间,多余的字符用于 null 字符。
0赞 nik 2/9/2023
谢谢,这是我这边的愚蠢错误,但我已经尝试了有和没有,它没有区别。

答:

0赞 nik 2/9/2023 #1

这里的问题不在于内存分配,而在于打印。 出于某种原因,偶尔会阻止缓冲区打印语句。将其替换为并打印到文件可以修复它。不知道为什么这只会对某些打印语句产生影响,特别是因为 配置为 .printffprintf/dev/jtag_uartjtag_uartstdout

0赞 Harith 2/10/2023 #2

偏离一个错误:

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 */
}