Will delete[] after strcpy cause memory leak? - c++

char* myChar=new char[20];
char* myChar2="123";
strcpy(myChar, myChar2);
...
delete[] myChar;
My question is if strcpy puts a '\0' at the end of "123", then will delete[] myChar only delete the first 3 chars and fail to delete the rest of myChar?
Thank you...

No, delete [] deallocates all the memory allocated by new [] as long as you pass the same address to delete [] that was returned by new [].
It just correctly remembers how much memory was allocated irrespective of what is placed at that memory.

Your delete[] deallocates all of 20 chars, not only 3+1 that you really did use.

Delete doesn't look for "\n" while deleting a character string.
Rather the compiler looks for "\n" while allocating the memory-chunk for your string.
Hence, deleting both myChar, and myChar2 would hence work in exactly the same way, by looking at the size of memory-chunk that was actually allocated for the particular pointer. This emplies no memory leaks in your situation.

This is a fundamental aspect of C++ that needs understanding. It causes confusion that has its ground. Look a the example:
char* myChar1 = new char[20];
char* myChar2 = (char*)malloc(20);
In spite of the fact that both pointers have the same type, you should use different methods to release objects that they are pointing at:
delete [] myChar1;
free(myChar2);
Note that if you do:
char *tmp = myChar1;
myChar1 = myChar2;
myChar2 = myChar1;
After that you need:
delete [] myChar2;
free(myChar1);
You need to track the object itself (i.e. how it was allocated), not the place where you keep a pointer to this object. And release the object that you want to release, not the place that stores info about this object.

char* myChar=new char[20]; // you allocate 20 space for 20 chars
+-----------------+
myChar -> | x | x | ... | x | // x = uninitialized char
+-----------------+
char* myChar2="123";
+----------------+
myChar2 -> | 1 | 2 | 3 | \0 | // myChar2 points to string
+----------------+
strcpy(myChar, myChar2); // copy string to 20 char block
// strcpy copies char by char until it finds a \0 i.e. 4 chars
// in this case
+----------------------------------+
myChar -> | 1 | 2 | 3 | \0 | x | x | ... | x |
+----------------------------------+
// note that characters after the string 123\0 are
// still uninitialized
delete[] myChar;
// the whole 20 chars has been freed

Related

Order of precedence in C++: & or ()?

Provided that texts is an array of 3 strings, what's the difference between &texts[3] and (&texts)[3]?
The [] subscript operator has a higher precedence than the & address-of operator.
&texts[3] is the same as &(texts[3]), meaning the 4th element of the array is accessed and then the address of that element is taken. Assuming the array is like string texts[3], that will produce a string* pointer that is pointing at the 1-past-the-end element of the array, ie similar to an end iterator in a std::array or std::vector.
----------------------------
| string | string | string |
----------------------------
^
&texts[3]
(&texts)[3], on the other hand, takes the address of the array itself, producing a string(*)[3] pointer, and then increments that pointer by 3 whole string[3] arrays. So, again assuming string texts[3], you have a string(*)[3] pointer that is WAY beyond the end boundary of the array.
---------------------------- ---------------------------- ----------------------------
| string | string | string | | string | string | string | | string | string | string |
---------------------------- ---------------------------- ----------------------------
^ ^
&texts[3] (&texts)[3]

Memory map of what happens when we use command line arguments? [duplicate]

This question already has answers here:
What does int argc, char *argv[] mean?
(12 answers)
Closed 6 years ago.
What I understand is argc holds total number of arguments. Suppose my program takes 1 argument apart from program name. Now what does argv hold? Two pointer eg: 123,130 or ./hello\0 and 5. If it holds 123 how does it know it has read one argument? Does it know because of \0.
If all the above is wrong, can someone help me understand using memory map.
The argv array is an array of strings (where each entry in the array is of type char*). Each of those char* arrays is, itself, NUL-terminated. The argv array, itself, does not need to end in NULL (which is why a separate argc variable is used to track the length of the argv array).
In terms of those arrays being constructed to begin with, this is dependent on the calling program. Typically, the calling program is a shell program (such as BASH), where arguments are separated via whitespace (with various quoting options available to allow arguments to include whitespace). Regardless of how the argc, argv parameters are constructed, the operating system provides routines for executing a program with this as the program inputs (e.g. on UNIX, that method is one of the various variations of exec, often paired with a call to fork).
To make this a bit more concrete, suppose you ran:
./myprog "arg"
Here is an example of how this might look in memory (using completely fake addresses):
Addresss | Value | Comment
========================
0058 | 2 | argc
0060 | 02100 | argv (value is the memory address of "argv[0]")
...
02100 | 02116 | argv[0] (value is the memory address of "argv[0][0]")
02104 | 02300 | argv[1] (value is the memory address of "argv[1][0]")
...
02116 | '.' | argv[0][0]
02117 | '/' | argv[0][1]
02118 | 'm' | argv[0][2]
02119 | 'y' | argv[0][3]
02120 | 'p' | argv[0][4]
02121 | 'r' | argv[0][5]
02122 | 'o' | argv[0][6]
02123 | 'g' | argv[0][7]
02124 | '\0' | argv[0][8]
...
02300 | 'a' | argv[1][0]
02301 | 'r' | argv[1][1]
02302 | 'g' | argv[1][2]
02303 | '\0' | argv[1][3]

why do you need to add one on new char (str.length())?

Code:
string str = "Whats up";
char *c = new char[str.length() + 1];
I can still write char *c = new char[str.length()];
What is the point of adding +1 on length?
Your code:
string str = "Whats up";
char *c = new char[str.length() + 1];
Your question:
What is the point of adding +1 on length?
The real question should be: What is the point of using C-style strings at all in your C++ program? Are you sure you need them?
Let me explain what exactly happens in your two code lines:
"Whats up" is a string literal, i.e. a constant series of characters, a char const[9] to be precise. The 9th character is the null character, '\0', automatically added by the compiler. So the array actually looks like this:
{ 'W', 'h', 'a', 't', 's', ' ', 'u', 'p', '\0' }
In fact, you could as well write:
char const array[9] = { 'W', 'h', 'a', 't', 's', ' ', 'u', 'p', '\0' };
std::string s = array;
So you have a char const[9] array which is used to initialize a std::string. Which constructor of std::string is actually used here? If you take a look at http://en.cppreference.com/w/cpp/string/basic_string/basic_string, you will find this one:
basic_string( const CharT* s,
const Allocator& alloc = Allocator() );
Remember, std::string is actually a typedef for std::basic_string<char>, so your CharT in this case is a char, and the constructor reads as:
string( const char* s,
const Allocator& alloc = Allocator() );
Also ignore the alloc parameter. It's too complicated to explain to a beginner, and it has a default argument precisely so that you can ignore it almost all the time. Which means that you end up with:
string( const char* s);
Which is itself another way of writing:
string(char const *s);
So you can initialize std::string with a char const *, and your code passes the constructor a char const[9]. This works because the array is automatically converted to a pointer to its first element.
So std::string takes your array, treats it as a pointer and copies the 9 characters. The array size information, 9, is lost, but it doesn't matter, because you have the terminating '\0', so the std::string knows where to stop.
So far, so good. You have a std::string object which contains a copy of "Whats up". Your next line goes like this:
char *c = new char[str.length() + 1];
First of all, consider str.length(). The length function returns string size, not array size. So although you passed 9 characters to construct the string, length returns 8. This makes sense, because std::string is designed to let you forget about pointers, arrays and memory operations. It's text, and the text here has 8 characters.
Thus, str.length() + 1 equals 8 + 1 = 9, so your line of code is equivalent to:
char *c = new char[9];
You have created a pointer named c, initialised to point to a memory location where there is enough room for 9 characters, although what's currently stored there is undefined, so you must not try to read from there yet:
c
|
|
+------+
|
v
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
...| | | | | | | | | | | | ...
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
0 1 2 3 4 5 6 7 8
And there is no relationship between the std::string you created and the memory c points to. They live in completely different places:
c
|
|
+------+
|
v 0 1 2 3 4 5 6 7 8
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
... | | | | | | | | | | | | ... |W |h |a |t |s | |u |p |\0| ...
+-+-+-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
0 1 2 3 4 5 6 7 8 ^
|
|
str -------( c_str() )-----------+
But if you use a C function like strcpy to copy the contents of the std::string to those 9 characters, then it becomes clear why you need space for 9 characters:
strcpy(c, str.c_str());
strcpy looks at the source (str.c_str()) and copies one character after the other to c until it finds '\0'. str internally ends with \0, so all is good. The function goes from 0 to 8 on the right of this picture and copies everything to 0 to 8 on the left.
And this finally answers your question: There must be space for 9 characters on the left. Otherwise, strcpy will attempt to write the final character (\0) to a memory location you are not allowed to touch. Which results in undefined behaviour and may cause e.g. crashes or random crashes.
With room for 9 characters, strcpy finished successfully:
c
|
|
+------+
|
v 0 1 2 3 4 5 6 7 8
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
... | |W |h |a |t |s | |u |p |\0| | ... |W |h |a |t |s | |u |p |\0| ...
+-+-+-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
0 1 2 3 4 5 6 7 8 ^
|
|
str -------( c_str() )-----------+
Moral of the story:
Use std::string. Copying a std::string may use very similar mechanism inside but frees you (among other annoying things) from having to remember the "+ 1" rule:
std::string s1 = "Whats up";
std::string s2 = "...";
s2 = s1;
Unlike std::string, C-style strings use a special character to indicate its end, which is the null character '\0', the extra one character is used to store the terminating '\0'.
There is a flaw in your code.
It should be
c* = new char[str.length()+1];
s.length()+1 wouldn't do anything.
Although the compiler will automatically set the c string size for you, it's good practice to specify the exact size so you get to see the mechanics of everything.
C strings always need one more space than the std::string value because c strings are character arrays that have a terminating null value at the end of the array. That is why you always give room for the NULL at the end.

Explaining a string trimming function

I came across the code below but need some help with understanding the code. Assume that the string s has spaces either side.
string trim(string const& s){
auto front = find_if_not(begin(s), end(s), isspace);
auto back = find_if_not(rbegin(s), rend(s), isspace);
return string { front, back.base() };
}
The author stated that back points to the end of the last space whereas the front points to the first non-white space character. So back.base() was called but I don't understand why.
Also what do the curly braces, following string in the return statement, represent?
The braces are the new C++11 initialisation.
.base() and reverse iterators
The .base() is to get back the the underlying iterator (back is a reverse_iterator), to properly construct the new string from a valid range.
A picture. Normal iterator positions of a string (it is a little more complex than this regarding how rend() works, but conceptually anyway...)
begin end
v v
-------------------------------------
| sp | sp | A | B | C | D | sp | sp |
-------------------------------------
^ ^
rend rbegin
Once your two find loops finish, the result of those iterators in this sequence will be positioned at:
front
v
-------------------------------------
| sp | sp | A | B | C | D | sp | sp |
-------------------------------------
^
back
Were we to take just those iterators and construct a sequence from them (which we can't, as they're not matching types, but regardless, supposed we could), the result would be "copy starting at A, stopping at D" but it would not include D in the resulting data.
Enter the back() member of a reverse iterator. It returns a non-reverse iterator of the forward iterator class, that is positioned at the element "next to" the back iterator; i.e.
front
v
-------------------------------------
| sp | sp | A | B | C | D | sp | sp |
-------------------------------------
^
back.base()
Now when we copy our range { front, back.base() } we copy starting at A and stopping at the first space (but not including it), thereby including the D we would have missed.
Its actually a slick little piece of code, btw.
Some additional checking
Added some basic checks to the original code.
In trying to keeping with the spirit of the original code (C++1y/C++14 usage), adding some basic checks for empty and white space only strings;
string trim_check(string const& s)
{
auto is_space = [](char c) { return isspace(c, locale()); };
auto front = find_if_not(begin(s), end(s), is_space);
auto back = find_if_not(rbegin(s), make_reverse_iterator(front), is_space);
return string { front, back.base() };
}

Does a char* when assigned a value terminates the String With a null?

suppose i have in my code written following :-
char *abc = " Who cares";
int len= strlen(abc);
This provides me the length of abc . My Doubt is how does Strlen determines the length of
abc here . Certainly it looks for null termination and returns the value . But that does that mean that abc is assigned Null at the place where i am initializing it with value " Who cares " ?
char *abc = " Who cares";
declares a pointer abd to a string literal "Who Cares" located somewhere in read only(Implementation defined) location. Yes, it is NULL terminated.
Do not try to modify this string literal though because it will lead to an Undefined Behavior.
Also, in C++ the correct way to declare this is:
const char *abc = " Who cares";
Yes, strlen walks through the memory pointed to by abc until it finds a null termination character.
abc is not initialized with null. The compiler places the string somewhere in memory (including an implicit null termination character); abc is then initialized with the address of the first character in the string.
So:
0x1234 0x123E (example addresses)
+--+--+--+--+--+--+--+--+--+--+--+
| |W |h |o | |c |a |r |e |s |\0|
+--+--+--+--+--+--+--+--+--+--+--+
^
|
|
abc = 0x1234