我对以下功能和内存分配有疑问。
char *strjoin(char const *s1, char const *s2)
{
char *s3;
s3 = NULL;
if (s1 && s2)
{
s3 = (char *)malloc(sizeof(char) * (strlen(s1) + strlen(s2) + 1));
if (!s3)
return (NULL);
strcpy(s3, s1);
strcat(s3, s2);
}
return (s3);
}
int main()
{
char *s1 = "my favorite animal is";
char *s2 = " ";
char *s3 = "the nyancat";
char *res = strjoin(strjoin(s1, s2), s3);
}
strjoins文档如下:
分配(使用malloc(3)),并返回以结尾的“新鲜”字符串 ‘\ 0’,是s1和s2串联的结果。如果分配 失败的函数将返回NULL。
在主函数中,该函数在以下行调用自身:
char * res = strjoin(strjoin(s1,s2),s3);
由于内存是在strjoin(s1,s2)中分配的,但从未分配给任何东西,并且它已在外部函数调用中使用,但从技术上讲从来没有释放过,所以该内存是否泄漏并变为未使用状态?
答案 0 :(得分:1)
是的,内部调用不会泄漏内存。通过将返回值存储在适当的位置,可以轻松避免泄漏:
char *intermediate;
char *res = strjoin(intermediate = strjoin(s1, s2), s3);
free(intermediate);
或
char *intermediate = strjoin(s1, s2);
char *res = strjoin(intermediate, s3);
free(intermediate);
但是,如果这是一个托管系统,则操作系统main
函数/在调用exit
时将释放内存。除非您要对嵌入式设备,设备驱动程序或操作系统进行编程,否则很有可能瞄准的是托管平台。
现在,根据编译器是否聪明,它可能实际上不为该程序分配任何内存,因为不需要结果。
考虑稍作更改的程序:
#include <stdlib.h>
#include <string.h>
static inline __attribute__((always_inline)) char *strjoin(char const *s1, char const *s2)
{
char *s3;
s3 = NULL;
if (s1 && s2) {
s3 = malloc(strlen(s1) + strlen(s2) + 1);
strcpy(s3, s1);
strcat(s3, s2);
}
return s3;
}
int main()
{
char *s1 = "my favorite animal is";
char *s2 = " ";
char *s3 = "the nyancat";
char *res = strjoin(strjoin(s1, s2), s3);
}
我已向函数中添加了static inline __attribute__((always_inline))
,以便只能在文件范围中看到它,而不能从其他.c
文件中看到它(它不会具有外部链接),并且该功能将始终内联;我还删除了 malloc
的返回值检查,因为它似乎阻碍了GCC推断此处将发生的情况的能力。(它以某种方式认为跟踪{{ NULL
的1}}状态是相关的。
如果您使用latest GCC trunk来编译具有最高优化级别的程序,则编译器会注意到所有计算都是无用的,并且会编译a much simpler program:
malloc
(请参阅中间窗格中的相同程序集)将具有same observable behaviour,但甚至不会调用int main(void) {
}
。