簡體   English   中英

從動態分配的數組中獲取內存泄漏

[英]Getting a memory leak from dynamically allocated arrays

我正在嘗試編寫一個可以反轉用戶輸入字符串的程序。 如果他們輸入“ book”,則應返回“ koob”。 我必須調用函數reverseit(char * inputString,char * outputString)並在其中編寫我的算法。

我一切正常,但最后返回一個malloc錯誤

:malloc: *** error for object 0x7fff5c8a5bc0: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

我寫的代碼:

void reverseit(char *inputString, char* outputString);

int main()
{
    char input[100];
    cin.getline(input, 10);
    int lenn = strlen(input); 
    char* usrinput = new char[lenn+1];
    usrinput = input;
    int len = strlen(usrinput);
    char* inputString = new char[len+1];
    inputString = usrinput;
    char* outputString = new char[len+1];
    reverseit(inputString, outputString);
    for (int o = 0; o < len; o++)
    {
        cout << outputString[o];
    }
    cout << endl;
    delete [] usrinput;
    delete [] inputString;
    delete [] outputString;
    return 0;

}

void reverseit(char *inputString, char *outputString)
{
    size_t length = strlen(inputString);
    char temp;
    int k = 0;
    for(int i = length - 1; i >= 0 ; i--)
    {
        temp = inputString[i];
        outputString[k] = temp;
        k++;
    }
}

有幾個限制實際上使這比實際要困難得多,因為除兩個char指針外,不允許我將任何其他變量調用為反向變量。

我的具體問題是,如果要刪除所有動態數組,內存泄漏仍將如何發生,是否會因為我沒有為每個數組輸入正確的大小而發生泄漏? 謝謝

usrinput = input;
inputString = usrinput;

要復制字符串,您需要復制每個char ,而不僅僅是重新分配指針。 使用=會丟棄動態分配的內存(這是內存泄漏),並使所有指針指向內存中的同一位置。 這意味着usrinputinputString最終都指向input ,因此由於沒有為new分配input ,最后的delete[]調用失敗。

strcpy(userinput, input);
strcpy(inputString, usrinput);

您對usrinputinput設置不正確。 input的類型為char[]usrinput的類型為char * 當您執行此操作時,它usrinput重新指向由new()[]運算符分配的另一個存儲位置。
現在,當您嘗試delete[] ,變量將指向靜態分配的char[]類型,而不是動態分配的類型。

int main(){

    char input[100];                   // Statically Allocated
    cin.getline(input, 10);
    int lenn = strlen(input); 
    char* usrinput = new char[lenn+1]; // DYNAMICALLY allocated
    usrinput = input;                  // setting statically allocated into variable that
                                       // previously held address of dynamically allocated
                                       // here is where your dynamic pointer gets LOST

    int len = strlen(usrinput);
    char* inputString = new char[len+1];  // Another Dynamic Allocation
    inputString = usrinput;               // This WOULD be OK except that now you are losing the
                                          // where inputString used to point to which was 
                                          // dynamically allocated

    char* outputString = new char[len+1];
    reverseit(inputString, outputString);
    for (int o = 0; o < len; o++)
    {
        cout << outputString[o];
    }
    cout << endl;
    delete [] usrinput;                    // usrinput now doesn't point to a dynamically
                                           // allocated space in memory, neither does inputString
    delete [] inputString;
    delete [] outputString;
    return 0;
}

問題是這些行:

usrinput = input;
/* ... */
inputString = usrinput;

這不是復制字符串的正確方法。 使用strcpy()代替:

strcpy(usrinput, input);

由於您更改了usrinput的值, usrinput您在與使用new[]分配的指針不同的指針(特別是堆棧分配的數組input )上調用delete[] new[]

不能通過將一個指針分配給另一個來復制字符數組中包含的字符串。 您需要使用諸如strcpy類的函數來搜索指針所指向的內存,直到它到達空終止符( '\\0' ),然后將內容復制到目標所指向的內存中。

例:

// Initialize an array of characters which contain the string "Foo bar\0";
char input[] = "Foo bar";
// Allocate a character array on the heap and assign it to the pointer pDest
char *pDest = new char[100];
// Reassign the pointer to the first element of input
pDest = input;
delete [] pDest; // Oops: Deleting the first element of input!

相反,您應該這樣做:

char input[] = "Foo bar";
char *pDest = new char[100];
// Copy all chars in the memory at input to the memory pointed to by pDest
strcpy(pDest, input);
delete [] pDest; // pDest still points to the dynamic memory, everything's fine

請注意,使用strcpy可能很危險,它只會將找到的所有內容復制到到達終止null的位置,直到目的地為止,它不會(無法!)檢查目的地是否足夠大。 在您的示例中,您已經通過使用strlen避免了這種情況,這很好。 只是作業無法按照您的想法工作。

除了此錯誤,您的代碼中還有其他可以改進的地方:

  • 根本不需要制作任何副本,使用getline獲取用戶輸入,為該用戶輸入的strlen + 1分配一個新數組就可以了,您可以將這兩個變量都傳遞給reverseit(記住要添加reverseit末尾的'\\0'分隔符。
  • 不需要在reverseit使用臨時char ,只需將inputString[i]直接分配給outputString[k]
  • 您可以將ik都放入for聲明中,而不必以其他方式處理k
  • cout可以處理char*形式的字符串,您不需要循環就可以將結果寫入控制台,只需將cout << outputString寫入即可

使用std::string類可以更輕松地在C ++中處理字符串,但是我想這是某種家庭作業,您必須堅持基礎知識。

您正在釋放堆棧中的數組:

char input[100];      
...
usrinput = input;
...
delete [] usrinput;

我不完全確定您要在這里完成什么,但肯定不是您在做什么。 如果要分配的內存將字符串的值保存在堆棧上,則必須執行以下操作:

my_buffer[100];
set_my_buffer(my_buffer);
char *my_allocated_buffer = new char [100];
strncpy(my_allocated_buffer, my_buffer, 100);

您分配了新的內存位置,但是將指針重新分配回了原始位置。

例:

int * pointer1 = new int[1];
pointer1[0] = 10;
int * pointer2 = new int[1];
pointer2[0] = 20;
cout << pointer2[0]; // 20
pointer2 = pointer1; 
cout << pointer2[0]; // 10
cout << pointer1[0]; // 10
delete [] pointer2;
cout << pointer1[0]; // Oh no! Garbage Value! But we didn't delete pointer1 did we?
delete [] pointer1; // FATAL ERROR!

此代碼的問題在於,當指針2 =指針1時,它僅為指針2提供了指針1的地址。 沒有拷貝任何值了。 這也意味着分配給指針2的原始空間永遠處於混亂狀態。 從未釋放。 這是導致您的代碼行出現問題的原因:

char* usrinput = new char[lenn+1];
usrinput = input;

您要復制所有值。 使用strcpy()

strcpy(usrinput, input)

暫無
暫無

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

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