简体   繁体   English

Memory 连接字符串泄漏 function

[英]Memory leak in a join string function

I'm trying to make a function that join 2 strings (str1 & str2) into a new one (str3) seperated by a char seperator.我正在尝试制作一个 function,它将 2 个字符串(str1 和 str2)连接成一个由字符分隔符分隔的新字符串(str3)。 Unfortunately I have a memory leak from this function and I don't really know why since I free str3 at the end.不幸的是,我从这个 function 泄漏了 memory,我真的不知道为什么,因为我最后释放了 str3。

Example: str_join_string("ABC","DEF",'|') ---> "ABC|DEF"示例:str_join_string("ABC","DEF",'|') ---> "ABC|DEF"

Here's the code:这是代码:

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] != '\0' && str1 != NULL){
    str3[i] = str1[i];
    i++;
  }
  str3[i] = separator;
  i+=1;

  while(str2[j] != '\0' && str2 != NULL){
    str3[i+j] = str2[j];
    j++;
  }
  str3[len] = '\0';
  
  return str3;
} 

I will add that I can't use any function like strcat() or anything that comes from string.h.我要补充一点,我不能使用任何 function 之类的 strcat() 或来自 string.h 的任何内容。

What Valgrind shows: 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== 

I hope that you can help me because I'm really lost right now.我希望你能帮助我,因为我现在真的迷路了。

------EDIT------ Yes I completely forgot to add the caller which is where I free the memory: ------编辑------ 是的,我完全忘记添加呼叫者,这是我释放 memory 的地方:

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], '\0');
  free(buf);
}

For starters the function invokes undefined behavior because there is not enough memory allocated for the result string.对于初学者,function 调用未定义的行为,因为没有足够的 memory 分配给结果字符串。

Instead of代替

size_t len = str_length(str1)+ str_length(str2)+1;

you have to write你必须写

size_t len = str_length(str1)+ str_length(str2)+2;

Moreover this statement而且这个声明

str3[len] = '\0';

also tries to write to the memory outside the allocated array.还尝试写入分配数组之外的 memory。

It seems you mean看来你的意思

str3[i + j] = '\0';

Though you could remove this statement because you are using the function calloc that sets the allocated memory with zeroes.虽然您可以删除此语句,因为您正在使用 function calloc将分配的 memory 设置为零。 On the other hand, using calloc is inefficient in the function context.另一方面,在 function 上下文中使用calloc是低效的。

And statements after the return statement和 return 语句之后的语句

//...
return str3;
free(str3);
str3 = NULL;

are never executed.永远不会被执行。

Pay attention to that conditions like in this for loop注意这个for循环中的条件

while(str1[i] != '\0' && str1 != NULL){

do not make a sense.没有意义。 At least the operands of the logical AND operator shall be exchanged like至少应交换逻辑 AND 运算符的操作数

while( str1 != NULL && str1[i] != '\0' ){

Though in any case the condition str1 != NULL is redundant or you could check the condition before the loop in an if statement.尽管在任何情况下条件str1 != NULL都是多余的,或者您可以在 if 语句的循环之前检查条件。

Here is a demonstrative program that shows how the function can be defined (without using standard string functions) and called.下面是一个演示程序,展示了如何定义(不使用标准字符串函数)和调用 function。

#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 = '\0';
    }
    
    
    return s3;
}

int main(void) 
{
    char *s = str_join_string( "ABC", "DEF", '|' );
    
    if ( s ) puts( s );
    
    free( s );
    
    return 0;
}

The program output is程序 output 是

ABC|DEF

It is the user of the function shall provide arguments not equal to NULL .它是 function 的用户应提供 arguments 不等于NULL

return str3;
free(str3);

Looks at this snippet, do you think free() is ever going to get called?看看这个片段,你认为free()会被调用吗?

Maybe because you return your function first and THEN free your buffer??也许是因为您先返回 function 然后释放缓冲区??

https://learn.microsoft.com/en-us/cpp/c-language/return-statement-c?view=vs-2019 https://learn.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返回语句结束 function 的执行,并将控制返回给调用 function

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM