2014-02-28 75 views
0

當我嘗試刪除「z」時,出現堆損壞錯誤。我假設z指向分配的內存,所以我很困惑爲什麼delete []會產生一個錯誤。釋放在返回指向該內存的函數中分配的內存(C++)

char* cpytoheap(const char* y) 
{ 
    char* x = new char; 
    for (int i=0; *(y+i); i++) 
    { 
     *(x+i) = *(y+i); 
     *(x+i+1) = '\0'; 
    } 
    return x; 
} 


int main() 
{ 
    char* z = "asdf"; 
    z = cpytoheap(z); 
    cout << z; //check that "asdf" copied correctly 
    delete[] z; //error doesn't occur if this is taken out 
    char y; //keep window open 
    cin >> y; //... 
    return 0; 
} 

我沒有在cpytoheap中使用下標,因爲練習是複製到免費商店而不使用下標。我通常會繼續前進,但我認爲將來知道如何在這種情況下釋放內存可能很重要。

+1

歡迎來到Stack Overflow。請儘快閱讀[關於]頁面。你爲什麼只分配一個角色?你在哪裏調用'cpytoheap()' - 你的'main()'調用'strdupa()'?你爲什麼不用'x [i] = y [i];'函數中的符號?循環後應該設置空字節;你在循環體內浪費時間做它。 –

+0

你根本沒有使用cpytoheap()。 – Chuck

+1

你似乎沒有調用'cpytoheap'。而且由於'z'沒有用'new []'分配,所以用'delete []'釋放它是個錯誤。 – TypeIA

回答

6

您只分配了1個字符作爲x。將其更改爲

char *x = new char[strlen(y)+1]; 

確保爲內容分配了足夠的內存空間。

+0

'cpytoheap'甚至不叫;這是*不是原因。 (不過,這是一個問題。) – nneonneo

+0

對不起,現在編輯。我把這個帖子的函數名改爲cpytoheap,這樣會更有意義,但是我忘了在main中改變它。無論如何,即使練習說不使用下標,這是一個有用的答案,但我認爲具有未定義的大小是不安全的。 – p1839

+0

@nneonneo鑑於OP的編輯和評論,這*是問題。 – TypeIA

1

您使用strdupa分配z,其分配結果動態堆棧上。因此,應該不能被釋放;它將在當前函數返回時自動解除分配。在這個意義上,strdupa與在當前函數中聲明本地字符串變量類似。

由於您的對象根本沒有在堆中聲明,因此您會收到「堆損壞」錯誤(free查看堆棧分配的內存並且看不到任何分配標記,因此它假定內存區域是損壞)。


而且,在任何情況下,你不會用delete[]釋放從C函數分配的對象;如果您需要釋放這樣的結果,請始終使用free

+0

strdup在堆上分配... – Jekyll

+1

如果您使用**'strdupa' **,則會將內存分配到堆棧並自動解除分配。但是,用**'strdup' **,內存分配在堆上,所以你必須自己「釋放」它。 – nneonneo

+0

(另外,'strdupa'不是標準的C,而是一個非常有用的GNU擴展。) – nneonneo

0

你的程序有兩種錯誤:

  1. 你是你的函數裏面cpytoheap沒有分配足夠的內存()。
  2. 您已經使用new分配了內存,因此您應該使用delete。如果您已使用new []分配,則只能使用delete []。

要理解這些問題,您可以在Windows平臺上使用GNU/Linux或WinDBG/PageHeap上的valgrind。以下報告由valgrind爲您的程序生成。

[email protected]:~$ valgrind ./a.out 
==4575== Memcheck, a memory error detector 
==4575== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al. 
==4575== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info 
==4575== Command: ./a.out 
==4575== 
==4575== Invalid write of size 1 
==4575== at 0x400A12: cpytoheap(char const*) (pratice.cpp:10) 
==4575== by 0x400A4E: main (pratice.cpp:19) 
==4575== Address 0x5a08041 is 0 bytes after a block of size 1 alloc'd 
==4575== at 0x4C2B1C7: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==4575== by 0x4009D5: cpytoheap(char const*) (pratice.cpp:6) 
==4575== by 0x400A4E: main (pratice.cpp:19) 
==4575== 
==4575== Invalid write of size 1 
==4575== at 0x400A00: cpytoheap(char const*) (pratice.cpp:9) 
==4575== by 0x400A4E: main (pratice.cpp:19) 
==4575== Address 0x5a08041 is 0 bytes after a block of size 1 alloc'd 
==4575== at 0x4C2B1C7: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==4575== by 0x4009D5: cpytoheap(char const*) (pratice.cpp:6) 
==4575== by 0x400A4E: main (pratice.cpp:19) 
==4575== 
==4575== Invalid read of size 1 
==4575== at 0x4C2BFB4: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==4575== by 0x4EC7288: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18) 
==4575== by 0x400A63: main (pratice.cpp:20) 
==4575== Address 0x5a08041 is 0 bytes after a block of size 1 alloc'd 
==4575== at 0x4C2B1C7: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==4575== by 0x4009D5: cpytoheap(char const*) (pratice.cpp:6) 
==4575== by 0x400A4E: main (pratice.cpp:19) 
==4575== 
==4575== Invalid read of size 1 
==4575== at 0x53C8132: _IO_default_xsputn (genops.c:485) 
==4575== by 0x53C6069: [email protected]@GLIBC_2.2.5 (fileops.c:1393) 
==4575== by 0x53BBCDC: fwrite (iofwrite.c:45) 
==4575== by 0x4EC6FD4: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18) 
==4575== by 0x4EC7296: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18) 
==4575== by 0x400A63: main (pratice.cpp:20) 
==4575== Address 0x5a08041 is 0 bytes after a block of size 1 alloc'd 
==4575== at 0x4C2B1C7: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==4575== by 0x4009D5: cpytoheap(char const*) (pratice.cpp:6) 
==4575== by 0x400A4E: main (pratice.cpp:19) 
==4575== 
==4575== Mismatched free()/delete/delete [] 
==4575== at 0x4C2A09C: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==4575== by 0x400A76: main (pratice.cpp:21) 
==4575== Address 0x5a08040 is 0 bytes inside a block of size 1 alloc'd 
==4575== at 0x4C2B1C7: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==4575== by 0x4009D5: cpytoheap(char const*) (pratice.cpp:6) 
==4575== by 0x400A4E: main (pratice.cpp:19) 
==4575== 
asdf 
q