char myStr[] = "Hello World";
char *p = strchr(myStr, 'W');
*p = '\0';
// Now myStr would be "Hello ";
If I do something like this, would this leak memory for "orld" part?
No, because in C, strings are just pre-defined char arrays that are terminated with the '\0' character. All the space for the string of characters is pre-allocated at run time and is inflexible unless you reassign the variable to point to a different section of memory, which is outside of the scope of this question.
In your example you initialize a char array to "Hello World" which is 12 bytes counting the \0 character at the end. Those 12 bytes are yours to use until the program finishes and will not be lost by conventional means. Resetting the contents of the string is as simple as writing different values to the char array. As long as your data does not exceed the limits of the array, you will not run into any issues or memory leaks.
Hope this helps.
Would setting a char to '\0' leak memory?
Generally, no.
A resource leak happens when you lose a handle to the resource. For example, when you allocate memory with malloc, you get a pointer that must be passed to free in order to release the memory. If you lose the pointer value, then you can never free the memory. That is a memory leak.
In the example program, you have an array with automatic storage, which contains the elements ['H','e','l','l','o',' ','\0','o','r','l','d','\0'. It is destroyed and its memory is released automatically when it goes out of scope.
Consider:
char myStr[] = "Hello World";
char *p = strchr(myStr, 'W');
*p = '\0';
printf( "Length of myStr = %d\n", strlen( myStr ) ) ;
printf( "Size of myStr = %d\n", sizeof( myStr ) ) ;
The output will be:
Length of myStr = 0
Size of myStr = 12
The size of an array and the length of a string are not the same thing. A string in C is not a data type, it is merely adjacent characters terminated by NUL. A string in C is contained in an array or block of contiguous memory that must be at least as long as the string plus 1 (to accommodate the NUL).
There is no memory leak or even "loss" because you can at any time access the entirety of the myStr array's 12 bytes.
In any event a memory leak occurs when you fail to return a dynamically allocated memory block to the heap. Since myStr is not dynamically allocated, it cannot "leak". Even if it were, modifying its content cannot cause a leak - although over/under running the allocation might by corrupting the heap.
Memory leak occurs when you no longer have a reference to an allocated memory that is not automatically freed.
Assigning a value to an array element does not cause memory leak because that doesn't lose you the reference to the array.
In your case, the array has automatic storage duration if it has function scope, so when it runs out of scope, it is de-allocated automatically.
But even if you had a dynamically allocated array, the assignment won't lose you the address of the allocated memory, so no leak.
Related
In C++, what's the difference between this:
char example[10];
and this:
char* example = new char[10];
in both cases, I'm not initializing the content of the arrays, but just wanting to get 10-bytes in memory allocated to the character array. In both cases, I intend to then use sprintf() to assign a string value to them with no intermediate step.
This:
char example[10];
Declares example as an array of char containing 10 elements. If declared at file scope, this array will typically reside in the data segment, while if it is declared at block scope it will typically reside on the stack.
In contrast, this:
char* example = new char[10];
Declares example as a pointer to char, and initializes it with a pointer to dynamically allocated memory which points to the first member of a 10 member array of char. This dynamically allocated memory typically resides on the heap.
Note also that new is specific to C++.
char example[10];
example is an array of 10 chars. Depending on context, it has automatic or static storage. The size can only be compile time constant. The array is destroyed and deallocated automatically.
char* example = new char[10];
example is a pointer. It is not an array. It points to first element of an array in dynamic storage. The size of dynamic array can be determined at runtime. The array is not destroyed and deallocated automatically. If not deallocated, the memory will leak.
Dynamic allocation is generally slower than static or automatic. On the other hand, the amount of memory available for automatic storage is typically very limited.
Bare owning pointers should be avoided. Best practice is to use a smart pointer or a RAII container such as std::vector when dynamic array is needed.
The main difference is that, in your first example you are have to already know at declare this char array his size, but in your second example, you are declare char array with pointer, which points on some value. That means you can only declare some char pointer without knowing the size of the char array. It is very usefull for programs, where the user has to write his nickname as input, maximal lenght of nickname can be 10 characters, but it can be less then 10 characters, that means you have to use pointers for dynamic allocating memory so as not to use too much unused memory.
For example:
int main()
{
char nm[10]; //Create char array, where you will save an input
char* nickname; //Declare pointer
std::cout << "Nickname: " << std::endl;
fflush(stdin);
gets(nm); //Save input
// Here we go find the size of used memory in char array nm
int size_of_nm = 0;
for (char i : nnnn)
{
if (i == '\0') //If char i is equal to zero character, we find the size of used
{ //memory in char array nm
break;
}
else //If i is not equal to zero character, we do not find the size of used
{ //memory in char array nm and loop will continue
size_of_nm++; //Size counter plus one
}
}
nickname = new char[size_of_nm + 1]; //Create new pointer on char array and set the
//size of used memory in char array
//plus one, because the char array is always
//ending with zero character
}
But I recommend using a strings. It is more safer, because you dont have to know the size of used memory, memory of string is allocated automatically.
My question arises from one of my c++ exercises (from Programming Abstraction in C++, 2012 version, Exercise 12.2). Here it is:
void strcpy(char *dst, char *src) {
while (*dst++ = *src++);
}
The definition of strcpy is dangerous. The danger stems from the fact
that strcpy fails to check that there is sufficient space in the
character array that receives the copy, thereby increasing the chance
of a buffer-overflow error. It is possible, however, to eliminate much
of the danger by using dynamic allocation to create memory space for
the copied string. Write a function
char *copyCString(char *str);
that allocates enough memory for the C-style string str and then
copies the characters—along with the terminating null character—into
the newly allocated memory.
Here's my question:
Is this new method really safe? Why it's safe?
I mean, to be a little bit radical, what if there isn't enough space in the heap?
Is the new operator able to check for space availability and fall in an elegant way if there isn't enough space?
Will that cause other kind of "something-overflow"?
If new fails to allocate the requested memory, it's supposed to throw a std::bad_alloc exception (but see below for more). After that, the stack will be unwound to the matching exception handler, and it'll be up to your code to figure out what to do from there.
If you really want/need to assure against an exception being thrown, there is a nothrow version of new you can use that will return a null pointer to signal failure--but this is included almost exclusively for C compatibility, and not frequently used (or useful).
For the type of situation cited in the question, you normally want to use std::string instead of messing with allocating space yourself at all.
Also note that on many modern systems, the notion of new either throwing or returning a null pointer in case of failure, is really fairly foreign. In reality, Windows will normally attempt to expand the paging file to meet your request. Linux has an "OOMKiller" process that will attempt to find "bad" processes and kill them to free up memory if you run out.
As such, even though the C++ standard (and the C standard) prescribe what should happen if allocation fails, that's rarely what happens in real life.
New operator will throw bad_alloc exception if it cannot alocate memory, unless nothrow specified. If you specify constant nothrow you will get NULL pointer back if it cannot alocate memory.
The code for strcpy is unsafe because it will try copying outside of the allocated memory for the dst pointer. Example:
int main()
{
const char* s1 = "hello"; // allocated space for 6 characters
char* s2 = new char[ 2 ]; // allocated space for 2 characters.
strcpy( s2, s1 );
cout << s2 << endl;
char c; cin >> c;
return 0;
}
This prints the correct value "hello", but remember that the pointer s2 was allocated to only have space for 2 characters. So we can assume that the other characters were written to the subsequent memory slots, which is unsafe as we could be overwriting data or accessing invalid memory.
Consider this solution:
char* e4_strdup( const char*& c )
{
// holds the number of space required for the c-string
unsigned int sz{ 0 };
// since c-style strings are terminated by the '\0' character,
// increase the required space until we've found a '\0' character.
for ( const char* p_to_c = c; *p_to_c != '\0'; ++p_to_c )
++sz;
// allocate correct amount of space for copy.
// we do ++sz during allocation because we must provide enough space for the '\0' character.
char* c_copy{ new char[ ++sz ] }; // extra space for '\0' character.
for ( unsigned int i{ 0 }; i < sz; ++i )
c_copy[ i ] = c[ i ]; // copy every character onto allocated memory
return c_copy;
}
The new operator will still return a std::bad_alloc exception if you run out of memory.
I have a small confusion in the dynamic memory allocation concept.
If we declare a pointer say a char pointer, we need to allocate adequate memory space.
char* str = (char*)malloc(20*sizeof(char));
str = "This is a string";
But this will also work.
char* str = "This is a string";
So in which case we have to allocate memory space?
In first sample you have memory leak
char* str = (char*)malloc(20*sizeof(char));
str = "This is a string"; // memory leak
Allocated address will be replaced with new.
New address is an address for "This is a string".
And you should change second sample.
const char* str = "This is a string";
Because of "This is a string" is write protected area.
The presumably C++98 code snippet
char* str = (char*)malloc(20*sizeof(char));
str = "This is a string";
does the following: (1) allocates 20 bytes, storing the pointer to that memory block in str, and (2) stores a pointer to a literal string, in str. You now have no way to refer to the earlier allocated block, and so cannot deallocate it. You have leaked memory.
Note that since str has been declared as char*, the compiler cannot practically detect if you try to use to modify the literal. Happily, in C++0x this will not compile. I really like that rule change!
The code snippet
char* str = "This is a string";
stores a pointer to a string literal in a char* variable named str, just as in the first example, and just as that example it won't compile with a C++0x compiler.
Instead of this sillyness, use for example std::string from the standard library, and sprinkle const liberally throughout your code.
Cheers & hth.,
In the first example, you dynamically allocated memory off the heap. It can be modified, and it must be freed. In the second example, the compiler statically allocated memory, and it cannot be modified, and must not be freed. You must use a const char*, not a char*, for string literals to reflect this and ensure safe usage.
Assigning to a char* variable makes it point to something else, so why did you allocate the memory in the first place if you immediately forget about it? That's a memory leak. You probably meant this:
char* str = (char*)malloc(20*sizeof(char));
strcpy(str, "This is a string");
// ...
free(str);
This will copy the second string to the first.
Since this is tagged C++, you should use a std::string:
#include <string>
std::string str = "This is a string";
No manual memory allocation and release needed, and assignment does what you think it does.
String literals are a special case in the language. Let's look closer at your code to understand this better:
First, you allocate a buffer in memory, and assign the address of that memory to str:
char* str = (char*)malloc(20*sizeof(char));
Then, you assign a string literal to str. This will overwrite what str held previously, so you will lose your dynamically allocated buffer, incidentally causing a memory leak. If you wanted to modify the allocated buffer, you would need at some point to dereference str, as in str[0] = 'A'; str[1] = '\0';.
str = "This is a string";
So, what is the value of str now? The compiler puts all string literals in static memory, so the lifetime of every string literal in the program equals the lifetime of the entire program. This statement is compiled to a simple assignment similar to str = (char*)0x1234, where 0x1234 is supposed to be the address at which the compiler has put the string literal.
That explains why this works well:
char* str = "This is a string";
Please also note that the static memory is not to be changed at runtime, so you should use const char* for this assignment.
So in which case we have to allocate memory space?
In many cases, for example when you need to modify the buffer. In other words; when you need to point to something that could not be a static string constant.
I want to add to Alexey Malistov's Answer by adding that you can avoid memory leak in your first example by copying "This is a string" to str as in the following code:
char* str = (char*)malloc(20*sizeof(char));
strcpy(str, "This is a string");
Please, note that by can I don't mean you have to. Its just adding to an answer to add value to this thread.
In the first example you're just doing things wrong. You allocate dynamic memory on the heap and let str point to it. Then you just let str point to a string literal and the allocated memory is leaked (you don't copy the string into the allocated memory, you just change the address str is pointing at, you would have to use strcpy in the first example).
How does string expressions in C++ work?
Consider:
#include <iostream>
using namespace std;
int main(int argc, char *argv[]){
const char *tmp="hey";
delete [] tmp;
return 0;
}
Where and how is the "hey" expression stored and why is there segmentation fault when I attempt to delete it?
Where it's stored is left to the compiler to decide in this (somewhat special) case. However, it doesn't really matter to you - if you don't allocate memory with new, it's not very nice to attempt to deallocate it with delete. You cannot delete memory allocated in the way you have allocated it.
If you want to control the deallocation of that resource, you should use a std::string, or allocate a buffer using malloc().
When you assign a const char * pointer to a constant string like "hey" in the example, the hey\0 sequence is stored as a static variable inside the binary itself. It cannot be deleted, and should not be manipulated. Depending on the architecture/operating system, it may segfault when manipulated.
If you were to do const char[] tmp = "hey" then the data would be stored on the stack, and may be manipulated (but not deleted, as it will be freed once the stack clears: when the function returns).
Do not delete[] anything that isn't new[]'d.
The "hey" is a string literal and is stored in the executable's data segment, which is mapped into memory of the process at load time. The particular part where literals live is mapped read-only. Here's a snippet of the assembly produced from your code with g++ -S:
...
.section .rodata
.LC0:
.string "hey"
.text
.align 2
...
So the data is indeed read-only, and attempt to manipulate it with delete leads to segfault.
const char *tmp="hey";
"hey" is stored in a read-only area of the Data Segment.
When the application starts up "hey" will be mapped to the READ-ONLY memory page.
const char *tmp="hey";
delete [] tmp;
delete will access and change some allocation metadata.,
but "hey" in the READ-ONLY memory page.
Changing value in READ-ONLY is not allowed, so segmentation fault happened.
You can't delete static resources: those are Read-Only.
What happens is this.
"hey" means put string 'hey' into binary image somewhere and give me an address of it, which is the value of the expression ("hey"). It has type char*. At this address, you have 4 bytes. 'h', 'e', 'y', and 0 (0 is called conventional null-terminator. (nothing to do with the movie terminator) This is how string literals work in C.
You can pass this literal as such: "an address of a string".
You cannot delete it.
when you construct std::string("hey"), it takes this pointed string, and copies it elsewhere - into a newly allocated memory.
You can't delete constant data. You would only call delete[] tmp if you had previously called new char[stringSize].
You did not call new on the string. That is a potential memory leak anyway, for every new there is a delete, likewise same for malloc and free. You deleted a memory reference to a pointer that simple is a static array of chars, in the sense of the word.
Hope this helps,
Best regards,
Tom.
The string "hey" has its space pre-allocated as part of the program, so it just appears when the program starts and disappears when the program ends.
If you want to see a program that allocates memory, uses it, then deletes it, then look at this:
#include <iostream>
using namespace std;
int main(int argc, char *argv[]){
const char *hey="hey";
char* tmp=new char[4]; // NB allocate 4 chars for "hey" plus a null terminator
strcpy(tmp,hey); // copies the string and null terminator
cout << tmp << endl;
delete [] tmp;
// must not use tmp now as it points to deallocated memory
// must not delete hey
return 0;
}
Notice how I happened to delete the new'd memory using tmp. I could have done this:
cout << tmp << endl;
hey = tmp;
delete [] hey;
It doesn't matter whether, in the end, we point to the new'd memory with hey or tmp, just as long as we delete it properly to avoid memory leaks.
I'm relatively novice when it comes to C++ as I was weened on Java for much of my undergraduate curriculum (tis a shame). Memory management has been a hassle, but I've purchased a number books on ansi C and C++. I've poked around the related questions, but couldn't find one that matched this particular criteria. Maybe it's so obvious nobody mentions it?
This question has been bugging me, but I feel as if there's a conceptual point I'm not utilizing.
Suppose:
char original[56];
cstr[0] = 'a';
cstr[1] = 'b';
cstr[2] = 'c';
cstr[3] = 'd';
cstr[4] = 'e';
cstr[5] = '\0';
char *shaved = shavecstr(cstr);
// various operations, calls //
delete[] shaved;
Where,
char* shavecstr(char* cstr)
{
size_t len = strlen(cstr);
char* ncstr = new char[len];
strcpy(ncstr,cstr);
return ncstr;
}
In that the whole point is to have 'original' be a buffer that fills with characters and routinely has its copy shaved and used elsewhere.
To clarify, original is filled via std::gets(char* buff), std::getline(char* buff, buff_sz), std::read(char* buff, buff_sz), or any in-place filling input reader. To 'shave' a string, it's basically truncated down eliminating the unused array space.
The error is a heap allocation error, and segs on the delete[].
To prevent leaks, I want to free up the memory held by 'shaved' to be used again after it passes through some arguments. There is probably a good reason for why this is restricted, but there should be some way to free the memory as by this configuration, there is no way to access the original owner (pointer) of the data.
I assume you would replace original by cstr, otherwise the code won't compile as cstr is not declared.
The error here is that the size of the allocated array is too small. You want char* ncstr = new char[len+1]; to account for the terminating \0.
Also, if you delete shaved right after the function returns, there is no point in calling the function...
[*] To go a bit deeper, the memory used for cstr will be released when the containing function returns. Usually such static strings are placed in constants that live for the entire duration of the application. For example, you could have const char* cstr="abcde"; outside all your functions. Then you can pass this string around without having to dynamically allocate it.
Assuming you meant to use cstr instead of cstrn...
You should not be deleting cstr. You should be deleting shaved.
You only delete the memory that was allocated with new. And delete[] memory that was allocated with new[].
shaved is simply a variable that holds a memory address. You pass that memory address to delete[] to get rid of the memory. shaved holds the memory address of the memory that was allocated with new[].