连接字符串函数中的内存泄漏
Memory leak in a join string function
我正在尝试制作一个函数,将 2 个字符串(str1 和 str2)连接到一个新的字符串(str3)中,由字符分隔符分隔。不幸的是,这个函数有内存泄漏,我真的不知道为什么,因为我最后释放了 str3。
示例:str_join_string("ABC","DEF",'|') ---> "ABC|DEF"
代码如下:
char *str_join_string(const char *str1, const char *str2, char separator) {
char *str3;
size_t len = str_length(str1)+ str_length(str2)+1;
size_t i = 0;
size_t j = 0;
str3 = (char * )calloc(len, sizeof(char));
if(str3 == NULL){
printf("Impossible d'allouer la mémoire");
return NULL;
}
while(str1[i] != '[=10=]' && str1 != NULL){
str3[i] = str1[i];
i++;
}
str3[i] = separator;
i+=1;
while(str2[j] != '[=10=]' && str2 != NULL){
str3[i+j] = str2[j];
j++;
}
str3[len] = '[=10=]';
return str3;
}
我要补充一点,我不能使用任何函数,如 strcat() 或来自 string.h 的任何函数。
Valgrind 显示的内容:
==4300== Searching for pointers to 3 not-freed blocks
==4300== Checked 131,560 bytes
==4300==
==4300== 4 bytes in 1 blocks are definitely lost in loss record 1 of 3
==4300== at 0x4C31B25: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4300== by 0x13E3B2: str_join_string (stringslib.c:238)
==4300== by 0x13E545: str_join_array (stringslib.c:283)
==4300== by 0x137065: JoinArrayTest_OneEmpty_Test::TestBody() (stringslib_test.cc:779)
==4300== by 0x1652A9: HandleSehExceptionsInMethodIfSupported<testing::Test, void> (gtest.cc:2611)
==4300== by 0x1652A9: void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (gtest.cc:2647)
==4300== by 0x15A9DE: testing::Test::Run() [clone .part.658] (gtest.cc:2686)
==4300== by 0x15AC61: Run (gtest.cc:2677)
==4300== by 0x15AC61: testing::TestInfo::Run() [clone .part.659] (gtest.cc:2863)
==4300== by 0x15B350: Run (gtest.cc:2837)
==4300== by 0x15B350: testing::TestSuite::Run() [clone .part.660] (gtest.cc:3017)
==4300== by 0x15BAF4: Run (gtest.cc:2997)
==4300== by 0x15BAF4: testing::internal::UnitTestImpl::RunAllTests() (gtest.cc:5709)
==4300== by 0x165769: HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool> (gtest.cc:2611)
==4300== by 0x165769: bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (gtest.cc:2647)
==4300== by 0x15AD82: testing::UnitTest::Run() (gtest.cc:5292)
==4300== by 0x11C08E: RUN_ALL_TESTS (gtest.h:2485)
==4300== by 0x11C08E: main (stringslib_test.cc:799)
==4300==
希望你能帮助我,因为我现在真的很迷茫。
------编辑------
是的,我完全忘了添加调用者,这是我释放内存的地方:
TEST(JoinStringTest, Simple) {
char *buf = str_join_string("ABC", "XYZ", '|');
ASSERT_TRUE(buf != NULL);
EXPECT_EQ(buf[0], 'A');
EXPECT_EQ(buf[1], 'B');
EXPECT_EQ(buf[2], 'C');
EXPECT_EQ(buf[3], '|');
EXPECT_EQ(buf[4], 'X');
EXPECT_EQ(buf[5], 'Y');
EXPECT_EQ(buf[6], 'Z');
EXPECT_EQ(buf[7], '[=12=]');
free(buf);
}
return str3;
free(str3);
看看这个片段,您认为 free()
会被调用吗?
可能是因为您 return 先执行函数然后释放缓冲区!?
https://docs.microsoft.com/en-us/cpp/c-language/return-statement-c?view=vs-2019
A return statement ends the execution of a function, and returns
control to the calling function
对于初学者来说,函数会调用未定义的行为,因为没有为结果字符串分配足够的内存。
而不是
size_t len = str_length(str1)+ str_length(str2)+1;
你必须写
size_t len = str_length(str1)+ str_length(str2)+2;
而且这个声明
str3[len] = '[=12=]';
还尝试写入分配数组之外的内存。
你的意思好像是
str3[i + j] = '[=13=]';
尽管您可以删除此语句,因为您正在使用将分配的内存设置为零的函数 calloc
。另一方面,在函数上下文中使用 calloc
是低效的。
以及 return 语句后的语句
//...
return str3;
free(str3);
str3 = NULL;
永远不会执行。
注意这个for循环中的条件
while(str1[i] != '[=15=]' && str1 != NULL){
没有意义。至少逻辑 AND 运算符的操作数应像
一样交换
while( str1 != NULL && str1[i] != '[=16=]' ){
尽管在任何情况下条件 str1 != NULL
都是多余的,或者您可以在 if 语句的循环之前检查条件。
这是一个演示程序,展示了如何定义(不使用标准字符串函数)和调用函数。
#include <stdio.h>
#include <stdlib.h>
size_t str_length( const char *s )
{
size_t n = 0;
while ( *s++ ) ++n;
return n;
}
char * str_join_string( const char *s1, const char *s2, char separator )
{
size_t n = str_length( s1 ) + str_length( s2 ) + sizeof( separator ) + 1;
char *s3 = malloc( n );
if ( s3 )
{
char *p = s3;
for ( ; *s1; ++s1 ) *p++ = *s1;
*p++ = separator;
for ( ; *s2; ++s2 ) *p++ = *s2;
*p = '[=17=]';
}
return s3;
}
int main(void)
{
char *s = str_join_string( "ABC", "DEF", '|' );
if ( s ) puts( s );
free( s );
return 0;
}
程序输出为
ABC|DEF
函数的使用者应提供不等于NULL
的参数。
我正在尝试制作一个函数,将 2 个字符串(str1 和 str2)连接到一个新的字符串(str3)中,由字符分隔符分隔。不幸的是,这个函数有内存泄漏,我真的不知道为什么,因为我最后释放了 str3。
示例:str_join_string("ABC","DEF",'|') ---> "ABC|DEF"
代码如下:
char *str_join_string(const char *str1, const char *str2, char separator) {
char *str3;
size_t len = str_length(str1)+ str_length(str2)+1;
size_t i = 0;
size_t j = 0;
str3 = (char * )calloc(len, sizeof(char));
if(str3 == NULL){
printf("Impossible d'allouer la mémoire");
return NULL;
}
while(str1[i] != '[=10=]' && str1 != NULL){
str3[i] = str1[i];
i++;
}
str3[i] = separator;
i+=1;
while(str2[j] != '[=10=]' && str2 != NULL){
str3[i+j] = str2[j];
j++;
}
str3[len] = '[=10=]';
return str3;
}
我要补充一点,我不能使用任何函数,如 strcat() 或来自 string.h 的任何函数。
Valgrind 显示的内容:
==4300== Searching for pointers to 3 not-freed blocks
==4300== Checked 131,560 bytes
==4300==
==4300== 4 bytes in 1 blocks are definitely lost in loss record 1 of 3
==4300== at 0x4C31B25: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4300== by 0x13E3B2: str_join_string (stringslib.c:238)
==4300== by 0x13E545: str_join_array (stringslib.c:283)
==4300== by 0x137065: JoinArrayTest_OneEmpty_Test::TestBody() (stringslib_test.cc:779)
==4300== by 0x1652A9: HandleSehExceptionsInMethodIfSupported<testing::Test, void> (gtest.cc:2611)
==4300== by 0x1652A9: void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (gtest.cc:2647)
==4300== by 0x15A9DE: testing::Test::Run() [clone .part.658] (gtest.cc:2686)
==4300== by 0x15AC61: Run (gtest.cc:2677)
==4300== by 0x15AC61: testing::TestInfo::Run() [clone .part.659] (gtest.cc:2863)
==4300== by 0x15B350: Run (gtest.cc:2837)
==4300== by 0x15B350: testing::TestSuite::Run() [clone .part.660] (gtest.cc:3017)
==4300== by 0x15BAF4: Run (gtest.cc:2997)
==4300== by 0x15BAF4: testing::internal::UnitTestImpl::RunAllTests() (gtest.cc:5709)
==4300== by 0x165769: HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool> (gtest.cc:2611)
==4300== by 0x165769: bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (gtest.cc:2647)
==4300== by 0x15AD82: testing::UnitTest::Run() (gtest.cc:5292)
==4300== by 0x11C08E: RUN_ALL_TESTS (gtest.h:2485)
==4300== by 0x11C08E: main (stringslib_test.cc:799)
==4300==
希望你能帮助我,因为我现在真的很迷茫。
------编辑------ 是的,我完全忘了添加调用者,这是我释放内存的地方:
TEST(JoinStringTest, Simple) {
char *buf = str_join_string("ABC", "XYZ", '|');
ASSERT_TRUE(buf != NULL);
EXPECT_EQ(buf[0], 'A');
EXPECT_EQ(buf[1], 'B');
EXPECT_EQ(buf[2], 'C');
EXPECT_EQ(buf[3], '|');
EXPECT_EQ(buf[4], 'X');
EXPECT_EQ(buf[5], 'Y');
EXPECT_EQ(buf[6], 'Z');
EXPECT_EQ(buf[7], '[=12=]');
free(buf);
}
return str3;
free(str3);
看看这个片段,您认为 free()
会被调用吗?
可能是因为您 return 先执行函数然后释放缓冲区!?
https://docs.microsoft.com/en-us/cpp/c-language/return-statement-c?view=vs-2019
A return statement ends the execution of a function, and returns control to the calling function
对于初学者来说,函数会调用未定义的行为,因为没有为结果字符串分配足够的内存。
而不是
size_t len = str_length(str1)+ str_length(str2)+1;
你必须写
size_t len = str_length(str1)+ str_length(str2)+2;
而且这个声明
str3[len] = '[=12=]';
还尝试写入分配数组之外的内存。
你的意思好像是
str3[i + j] = '[=13=]';
尽管您可以删除此语句,因为您正在使用将分配的内存设置为零的函数 calloc
。另一方面,在函数上下文中使用 calloc
是低效的。
以及 return 语句后的语句
//...
return str3;
free(str3);
str3 = NULL;
永远不会执行。
注意这个for循环中的条件
while(str1[i] != '[=15=]' && str1 != NULL){
没有意义。至少逻辑 AND 运算符的操作数应像
一样交换while( str1 != NULL && str1[i] != '[=16=]' ){
尽管在任何情况下条件 str1 != NULL
都是多余的,或者您可以在 if 语句的循环之前检查条件。
这是一个演示程序,展示了如何定义(不使用标准字符串函数)和调用函数。
#include <stdio.h>
#include <stdlib.h>
size_t str_length( const char *s )
{
size_t n = 0;
while ( *s++ ) ++n;
return n;
}
char * str_join_string( const char *s1, const char *s2, char separator )
{
size_t n = str_length( s1 ) + str_length( s2 ) + sizeof( separator ) + 1;
char *s3 = malloc( n );
if ( s3 )
{
char *p = s3;
for ( ; *s1; ++s1 ) *p++ = *s1;
*p++ = separator;
for ( ; *s2; ++s2 ) *p++ = *s2;
*p = '[=17=]';
}
return s3;
}
int main(void)
{
char *s = str_join_string( "ABC", "DEF", '|' );
if ( s ) puts( s );
free( s );
return 0;
}
程序输出为
ABC|DEF
函数的使用者应提供不等于NULL
的参数。