Proper use of delete vs delete[ ] with respect to char * in C++ - c++

I have a piece of code:
#include<iostream>
using namespace std;
int main()
{
char * str = new char;
cin >> str;
cout << str;
delete str;
}
vs.
#include<iostream>
using namespace std;
int main()
{
char * str = new char[30];
cin >> str;
cout << str;
delete []str;
}
When I give input to either program using STDIN, which program ensures that there are no memory leaks?
This doubt arose as our professor told us that a char * is basically equivalent to an array of chars only. So if I allocate heap memory as in the first case and let str 'hold' an array of chars, if I then delete str, does it delete the array completely? I know that the second case manages to do so.
I have already been through ->
delete vs delete[] operators in C++
delete vs delete[]
And thus I know that delete[] deletes memory allocated by new[] and delete does the same for new. But what if new itself allocates contiguous memory locations??

Your both first code example is wrong.
char * str = new char;
cin >> str;
You've only allocated memory for a single character. If you read anything other than an empty string, you'll write into unallocated memory and will have undefined behaviour.
if I then delete str, does it delete the array completely?
It will only delete the one character that you allocated. The rest of the string that you wrote in unallocated memory won't be directly affected by the delete. It's not a memory leak, it's a memory corruption.
vs.
char * str = new char[];
This is not legal c++. Array size must be specified.
EDIT: After your fix, the second code is correct as long as you read a string of 29 characters or shorter. If you read a longer string, you'll get undefined behaviour again.
But what if new itself allocates contiguous memory locations?
It doesn't. new (as opposed to new[]) allocates and constructs exactly one object. And delete destroys and deallocates exactly one object.
TLDR Neither program has memory leaks but the first one has undefined behaviour due to memory corruption.

I believe that you are misunderstanding what the difference is between a memory leak and a buffer overflow.
What is a buffer overflow?
A buffer overflow occurs when we have some piece of memory that we are going to store some data in. And when we store that data, we put too much data there. For example:
int x[4];
x[0] = 7;
x[1] = 8;
x[2] = 9;
x[3] = 10;
x[4] = 11; // <-- Buffer Overflow!
Your code exhibits a potential buffer overflow because cin doesn't know how much memory you've allocated. And there's no real method to tell it that when using char * arguments. So in your first example, if you were to write any string longer than the empty string, you would cause a buffer overflow. Likewise, if you were to write more than 30 characters (including the null character) to the second example, you would also cause a buffer overflow.
What is a memory leak?
A memory leak is traditionally represented this way:
char *x = new char[30];
x[0] = 'a';
x[1] = '\0';
x = new char[10]; // <-- Memory Leak!
At this point in the code, you have no ability to call delete[] on the first allocation. You have no variable that points to that pointer. That is a memory leak.
What does delete[] do?
Let's consider that there is some bucket somewhere that can give us chunks of memory. We can grab chunks of memory from that bucket via new and new[]. When we use delete and delete[], we return those chunks of memory back to the bucket.
The agreement that we make with new and delete is that once we call delete on a piece of memory, we don't continue to use it. We don't do this, because the system may reuse that piece of memory, or it may have removed all ability to access that pointer all together.
How could this possibly work?
You have this piece of code:
char *x = new char;
cin >> x;
I'd like to tell you that it's basically the same as this piece of code:
char y;
cin >> &y;
In both cases, you've allocated space for only one char. So when we call delete on x, we're only deleteing one char. The part of the code there that will likely break is that cin will think that there is enough memory allocated for whatever string it is going to try and write to that pointer.
The fact is, there probably isn't enough space. There's only space for one char. And even the string "a", takes up 2 chars.

You can't do such things.
char *ptr = new char;
means that you have allocated sizeof(char) bytes.
If you will execute cin >> ptr, and pass there more than 1 character, you will get segfault as the memory isn`t allocated.
To allocate an array of chars you need to do it in next way:
char *ptr = new char[ size ];
It will allocate size * sizeof(char) bytes.
And then you can use cin >> ptr to fill it with data.

Related

Memory leak on deallocating char * set by strcpy?

I have a memory leak detector tool which tells me below code is leaking 100 bytes
#include <string>
#include <iostream>
void setStr(char ** strToSet)
{
strcpy(*strToSet, "something!");
}
void str(std::string& s)
{
char* a = new char[100]();
setStr(&a);
s = a;
delete[] a;
}
int main()
{
std::string s1;
str(s1);
std::cout << s1 << "\n";
return 0;
}
According to this point number 3 it is leaking the amount I allocated (100) minus length of "something!" (10) and I should be leaking 90 bytes.
Am I missing something here or it is safe to assume the tool is reporting wrong?
EDIT: setStr() is in a library and I cannot see the code, so I guessed it is doing that. It could be that it is allocating "something!" on the heap, what about that scenario? Would we have a 90 bytes leak or 100?
This code does not leak and is not the same as point number 3 as you never overwrite variables storing pointer to allocated memory. The potential problems with this code are that it is vulnerable to buffer overflow as if setStr prints more than 99 symbols and it is not exception-safe as if s = a; throws then delete[] a; won't be called and memory would leak.
Updated: If setStr allocates new string and overwrites initial pointer value then the pointer to the 100 byte buffer that you've allocated is lost and those 100 bytes leak. You should initialize a with nullptr prior to passing it to setStr and check that it is not null after setStr returns so assignment s = a; won't cause null pointer dereference.
Summing up all the comments, it is clear what the problem is. The library you are using is requesting a char **. This is a common interface pattern for C functions that allocate memory and return a pointer to that memory, or that return a pointer to memory they own.
The memory you are leaking is allocated in the line char* a = new char[100]();. Because setStr is changing the value of a, you can no longer deallocate that memory.
Unfortunately, without the documentation, we cannot deduce what you are supposed to do with the pointer.
If it is from a call to new[] you need to call delete[].
If it is from a call to malloc you need to call std::free.
If it is a pointer to memory owned by the library, you should do nothing.
You need to find the documentation for this. However, if it is not available, you can try using your memory leak detection tool after removing the new statement and see if it detects a leak. I'm not sure if it is going to be reliable with memory allocated from a library function but it is worth a try.
Finally, regarding the question in your edit, if you leak memory you leak the whole amount, unless you do something that is undefined behavior, which is pointless to discuss anyway. If you new 100 chars and then write some data on them, that doesn't change the amount of memory leaked. It will still be 100 * sizeof(char)

How to manage memory in functions C++

How to manage memory in function, which returns dynamically allocated variable?
What happens with buffer, when function returns?
char * getStr(){
char * buffer = new char[12];
sprintf_s(buffer, 12 , "abcdef");
return buffer;
}
buffer stays allocated, but luckily you're returning the pointer.
You must delete[] that pointer at some point, else you'll leak memory.
Notice how I've used []: that's important. This balances your allocation of an array of chars. (Conceptually the runtime stores the length of an array allocated with new something[], and delete[] informs the runtime to free the correct number of elements.)
When function returns, your buffer still exists. There is nothing like embedded memory manager, you MUST free all the memory you allocated manualy. That is about C.
In C++ standart library, there is objects called smart pointers. With the pressence of exceptions, they are totally recommended to use. There is fine answer on SO about them: What is a smart pointer and when should I use one?
Nothing.
The address which is stored in *buffer will be returned to the caller and it is up to the caller to delete the memory again.
buffer is a pointer that means it addresses a point in memory.
new will allocate a bloc of memory, for the command new char[12] it will allocate 12 chars worth of memory.
new returns the address of the memory and that is assigned to your pointer buffer.
Note that because you only have a pointer to the memory, you need to clean that up before buffer goes out of scope. If the address contained in buffer buffer goes out of scope you will have "leaked" memory. Because it cannot be reclaimed. You clean up the memory allocated by new char[12] with the command: delete[].
Thank to Bathsheba for his answer.
My vision of a solution to the problem:
char * getStr(){
char * buffer = new char[12];
sprintf_s(buffer, 12 , "abcdef");
return buffer;
}
int _tmain(int argc, _TCHAR* argv[]){
char * p = getStr();
std::cout << p << std::endl;
delete[] p;
return 0;
}

Usage of number object in malloc

I am new to programming and I am trying to understand the difference between
A = (char * ) malloc(sizeof(char)*n);
and
A = (char * ) malloc(sizeof(char));
or
A = new char [n];
and
A = new char;
What is the default memory that a compiler is allocating to this pointer, when I do not specify the number of objects of particular data type.
Also when I declare
A = new char [n];
cout << A[n+1];
it does not give me a segmentation fault.
Should It not give segmentation fault because I am trying to access memory beyond what has been allocated for the Array.
Memory is not "allocated to this pointer", it's allocated and then you get a pointer to the memory.
This:
char *a = malloc(sizeof(char) * n);
is the same as
char *a = malloc(n);
since sizeof(char) is always 1. They both allocate space for n characters worth of data, and return a pointer to the location where the first character can be accessed (or NULL on failure).
Also, the casts are not needed in C, you should not have any.
Since sizeof(char) is 1, the second call is equivalent to:
char *a = malloc(1);
which means it allocates a memory block of size 1. This is of course distinct from the pointer to that memory block (the value that gets stored in the pointer variable a). The pointer is most likely larger than 1 char, but that doesn't affect the size of the block.
The argument to malloc() specifies how many chars to allocate space for.
I ignored the new usage, since that is C++ and the question is tagged C.
A = (char * ) malloc(sizeof(char)*n);
This allocates space for n characters.
A = (char * ) malloc(sizeof(char));
This allocates memory for 1 character.
Every call to malloc allocates memory in the heap.
The other code is C++, and it's exactly the same, except that it will use stack memory if A is a local variable. Accessing A[n+1] may or may not yield a segfault. A[n+1] can reference a memory address that you are allowed to use. Segfault happens when you go out of the region of memory you can access, and the way it works is that there is a "red zone" from which it is considered you accessed invalid memory. It may be the case that A[n+1] just isn't "invalid enough" to trigger a segfault.
allocate space for N characters (N should be some positive integer value here)
char *ma = (char * ) malloc(N);
char *na = new char [N];
don't forget to release this memory ...
delete [] na;
free(ma);
allocate space for a single character
char *mc = (char * ) malloc(sizeof(char));
char *nc = new char;
Now, as the others have pointed out, you tagged this C, but half your code is C++. If you were writing C, you couldn't use new/delete, and wouldn't need to cast the result of malloc.
Oh, and the reason you don't get a segmentation fault when you read off the end of your array is that this is undefined behaviour. It certainly could cause a SEGV, but it isn't required to check, so may appear to work, at least some of the time, or fail in a completely different way.
Well, the compiler doesn't allocate memory for the data. Only the pointer which is either 4 or 8 bytes depending on your architecture.
There is no difference between the first two and the last two in terms on functionality. Most C++ libraries I've seen use malloc internally for new.
When you run the code to allocate n characters and you print out the n + 1th character, you aren't getting a segmentation fault most likely because n isn't a multiple of some number, usually 8 or 16. Here's some code on how it might do that:
void* malloc(size_t size) {
if (size & 0x7 != size)
size = size & 0x7 + 1;
return _malloc(size);
}
So, if you requested, say, 5 bytes, malloc would actually allocate, with that code, 8 bytes. So, if you request the 6th byte (n + 1), you would get garbage, but it is still valid memory that your program can access.

Does null in a character array prevent memory being deleted beyond it?

Is there any memory leak ?
const char * pname = "NAME";
char * temp = new char[strlen(Name) + 64];
sprintf(temp,"%s", pname);
delete [] temp; // is there any memory leaks because now length of temp is 4.
It is undefined behavior to delete(modify) string literal(pname).
Also new/delete, new []/delete[] are only used in pair.
Suggest use std::string if you could, let std::string manage the memory allocation/deallocation for you.
std::string pname("NAME");
std::string temp(pname);
std::cout << pname << std::endl;
No, no matter where the trailing 0 of temp is the allocated memory for it is still the initial strlen(Name) + 64 so the delete frees the whole block of memory which is correct.
As #billz pointed out you should not free pname.
No there won't be any memory leak. sprintf will only use the bytes of temp that it requires, BUT, all of the bytes initially created will remain allocated (even though some are unused).
The call to delete[] temp will then deallocate all the bytes originally allocated.
As others have pointed out though, do not free pname. You should only call delete and delete[] on pointers which were created with new and new[] respectively.
Additional information:
When you created temp, new[] allocated an array of contiguous bytes in memory PLUS an additional (small) space where it stores the information about the allocation (how large the allocation is, for instance). When you called delete[] it examined that information and found that strlen(Name)+64 bytes were allocated, and so it knows it has to deallocate all of them. The fact that you only used a small fraction of the allocated space does not make a difference.

Pointers pointing contiguous memory

Consider the following code
struct foo
{
const int txt_len;
const int num_len;
char * txt;
int * num;
foo(int tl, int nl): txt_len(tl), num_len(nl)
{
char * tmp = new char[txt_len * sizeof(char) + num_len * sizeof(int)];
txt = new (tmp) char [txt_len * sizeof(char)];
num = new (tmp + txt_len * sizeof(char)) int[num_len * sizeof(int)];
// is this the same as above?
// txt = tmp;
// num = (int *) (tmp + txt_len * sizeof(char));
}
~foo()
{
delete[] txt; // is this the right way to free the memory?
}
};
I want *txt and *num to be contiguous, is that the best way to do it?
also is there any difference between placement new and pointer arithmetic? which one should I use?
If you want a contiguous block of memory, you have to allocate it whole with a single call to operator new[] or malloc() or similar. Multiple calls to these functions do not guarantee any contiguity of allocated blocks whatsoever. You may allocate a big block and then carve parts from it as needed.
And you should delete and free() all blocks previously allocated with new and malloc(), otherwise you'll leak memory and probably make your program unstable (it will fail to allocate more memory at some point) and exert unnecessary pressure on memory in the OS, possibly slowing down other programs or making them unstable as well.
Placement new, however, does not actually allocate any memory. It simply constructs an object at the specified location and so you don't need to free that memory twice.
One problem that I see in your code is that it doesn't align ints. On some platforms reading or writing integers bigger than 1 byte from/to the memory must be aligned and if it's not, you can either read/write values from/to wrong locations or get CPU exceptions leading to termination of your program. The x86 is very permissive in this regard and won't mind, though may tax you with degraded performance.
You'll need to put the int data first, due to the alignment issues. But we can't then do delete num[] as the type is wrong - it must be cast to a char* before deleting.
char * tmp = new char[num_len * sizeof(int) + txt_len * sizeof(char)];
num = new (tmp) int[num_len];
txt = new (tmp + num_len * sizeof(int)) char [txt_len];
(This makes liberal use of the fact that sizeof(char)==1)
You might be tempted to do delete[] num, but num is of type int*, and it was new'ed as a char*. So you need to do;
delete[] (char*) num;
This is the same as long as you use POD types. And your delete is fine.
However, as David's comment states, you need to consider alignment problems.
Placement new is mostly use when you want to call constructor of class/struct on some preallocated memory blocks.
But for native types it makes no different to use placement new & pointer arithmetic.
Please correct me if I was wrong.
If txt and num always point to int and char, other built in types or other types not requiring construction, then no. You don't need placement new.
If on the other hand you were to change one of them to a class which requires construction, i.e. changes txt to type std::string, then using placement new is necessary.
Placement new allows you to call the constructor, building, if you like, the object at that address. Built in types have default constructors that do nothing if your not initializing.
In both cases you need to do pointer arithmetic, just one way you store the answer in a pointer, the other you pass the answer to placement new which gives it back to you for storage in the pointer, and then calls the constructor.