简体   繁体   中英

Freeing memory that was allocated in a function that returns a pointer to that memory (C++)

I get a heap corruption error when I try to delete "z". I assume that z points to the allocated memory, so I'm confused as to why delete[] creates an error.

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;
}

I didn't use subscript in cpytoheap because the exercise is to copy to free store without using subscript. I would normally move on but I feel it may be important in the future to know how to free memory in this type of situation.

You only allocated 1 char for x . Change it into

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

to make sure enough memory space is allocated for the content.

You used strdupa to allocate z , which allocates the result dynamically on the stack . Therefore, it should not be freed ; it will automatically be deallocated when the current function returns. In that sense, strdupa is similar to declaring a local string variable in the current function.

You get a "heap corruption" error because your object isn't declared on the heap at all ( free looks at the stack-allocated memory and doesn't see any allocation markers, so it assumes that the memory region is corrupted).


Also, in any case, you would not use delete[] to free an object allocated from a C function; if you need to free such a result, always use free .

Your program have two error:

  1. You are allocating not sufficient memory inside your function cpytoheap().
  2. You have allocated the memory using new so you should use delete. If you have allocated using new[] then only use delete[].

To understand these problem you can use valgrind on GNU/Linux or WinDBG/PageHeap on Windows platfrom. The following report is generated by valgrind for your program.

mantosh@mantosh4u:~$ 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: _IO_file_xsputn@@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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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