簡體   English   中英

Memory 連接字符串泄漏 function

[英]Memory leak in a join string function

我正在嘗試制作一個 function,它將 2 個字符串(str1 和 str2)連接成一個由字符分隔符分隔的新字符串(str3)。 不幸的是,我從這個 function 泄漏了 memory,我真的不知道為什么,因為我最后釋放了 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] != '\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;
} 

我要補充一點,我不能使用任何 function 之類的 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== 

我希望你能幫助我,因為我現在真的迷路了。

------編輯------ 是的,我完全忘記添加呼叫者,這是我釋放 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);
}

對於初學者,function 調用未定義的行為,因為沒有足夠的 memory 分配給結果字符串。

代替

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

你必須寫

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

而且這個聲明

str3[len] = '\0';

還嘗試寫入分配數組之外的 memory。

看來你的意思

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

雖然您可以刪除此語句,因為您正在使用 function calloc將分配的 memory 設置為零。 另一方面,在 function 上下文中使用calloc是低效的。

和 return 語句之后的語句

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

永遠不會被執行。

注意這個for循環中的條件

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

沒有意義。 至少應交換邏輯 AND 運算符的操作數

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

盡管在任何情況下條件str1 != NULL都是多余的,或者您可以在 if 語句的循環之前檢查條件。

下面是一個演示程序,展示了如何定義(不使用標准字符串函數)和調用 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;
}

程序 output 是

ABC|DEF

它是 function 的用戶應提供 arguments 不等於NULL

return str3;
free(str3);

看看這個片段,你認為free()會被調用嗎?

也許是因為您先返回 function 然后釋放緩沖區??

https://learn.microsoft.com/en-us/cpp/c-language/return-statement-c?view=vs-2019

返回語句結束 function 的執行,並將控制返回給調用 function

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM