This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Modifying a C string: access violation
int main()
{
char str_1[7] = "string";
char* str_2 = new char[7];
str_2 = "string";
str_1[2] = 'a'; //ok
str_2[2] = 'a'; //error
return 0;
}
i get "access violation" error here str_2[2] = 'a';
I don't understand why i can't access dynamic string via index here? (VS2010) Thanks.
You can not assign to a string like you do. Instead of copying the strings contents you copy the pointer. Thus str_2 now points to a string literal and can not be modified. To copy string's contents use strcpy.
Even worse- in your version of the code there is a memory leak for the memory allocated for str_2 in the line where you call new.
Instead str_2 = "string"; write strcpy(str_2, "string"), since in your case you are trying to modify string literal.
Allocates memory
char* str_2 = new char[7];
Disregards the previous allocation (and results in a memory leak), and makes str_2 point to a immutable string literal:
str_2 = "string";
str_2 will now actually point to a const char[], the implicit cast to char* is there just for backwards-compatibility. In fact it's pointing to read-only memory.
The problem is that you do not do any "hard copy" of the memory cells anywhere, you just change pointers to point at different places. Strings are arrays and therefore have to be copied using the strcpy or memcpy functions.
char* str_2 = new char[7]; allocates dynamic memory. str_2 = "string"; lets the pointer str_2 point at a completely different memory cell, forgetting that it used to point at the allocated dynamic memory. Since there is no remaining reference to that memory, you know how a memory leak bug.
str_2 now points at a constant string literal "string" which resides in read-only memory.
str_2[2] = 'a'; attempts to modify that memory, which is undefined behavior and you get a crash.
To understand why the str_1 case works, it is important to grasp the programming concepts intialization and assignment. The case of 'str_1' works because you allocate 7 bytes and then initialize those bytes to contain "string". At variable initialization is the only place where = will result in a hard copy from the read-only memory where the actual string literal "string" resides, to the stack in RAM where str_1 is allocated.
Related
I have created a char* str_1 and have allocated 64 bytes to it.
Then I created another char* str_2 and referenced it to the initial string.
char* str_1 = new char[64];
char* str_2 = str_1; // does it reference the object created with the new statement.
My question is, does str_2 contain the reference to the allocated memory? In which case, could I do something like this?
char* str_1 = new char[64];
char* str_2 = str_1;
delete[] str_2;
Is calling delete[] str_2 actually deleting the allocated memory? Or, is it causing a memory leak?
After the declaration of the pointer str_2, both pointers str_1 and str_2 are pointing to the same dynamically allocated memory (character array).
char* str_1 = new char[64];
char* str_2 = str_1;
After calling the operator delete []:
delete[] str_2;
Both pointers become invalid, because they both do not point to an existing object.
There is no memory leak. You may use either pointer to delete the allocated array. But you may not delete the same dynamically allocated memory twice.
A memory leak occurs when a memory was allocated dynamically and was not freed at all.
str_1 and str_2 are pointing to the same piece of allocated memory, so you could use either str_1 or str_2 to free that memory.
However, don't use both to free the memory, that would be a double delete. And don't use either pointer after you have freed the memory.
Is here a memory leak?:
#include <iostream>
#include <string>
class A{
std::string value;
public:
A(){
char *tmp = new char[3];
tmp[0] = 'a';
tmp[1] = 'b';
tmp[2] = 'c';
value = std::string(tmp);
}
std::string const& getValue() const {
return value;
}
};
int main(){
A a;
std::cout << a.getValue() << '\n';
}
since the value is constructed from pointer to newed memory, and thus the std::string is taking the ownership of it, will it also destroy? Or is it my responsibility to take care of that temporary object? And if so, the only way to destroying it is via having it as private variable, otherwise it goes out of scope (since the pointer is with auto storage created in constructor function).
So how is here the buffer managed?
The answer is no. I mean imagine if it did and you did this (ignoring the missing 0)
char *tmp = new char[3];
tmp[0] = 'a';
tmp[1] = 'b';
tmp[2] = 'c';
std::string value1 = std::string(tmp);
std::string value2 = std::string(tmp);
You would be very upset if the second string creation failed
Also std::string(const char*s) cannot tell that the memory for s is on the heap, stack or static. All it can see is a pointer. Even if it wanted to steal the memory it has no way of knowing if its doable
thus the std::string is taking the ownership of it
This assumption is incorrect. std::string doesn't take ownership of any pointer, constructor taking char* copies the data into internal storage. So yes, you have to delete[] what you new[]'ed.
Also, if you are passing char* to std::string, it must be null terminated:
A(){
char *tmp = new char[4];
tmp[0] = 'a';
tmp[1] = 'b';
tmp[2] = 'c';
tmp[3] = '\0';
value = std::string(tmp);
}
And thus the std::string is taking the ownership of it, will it also destroy?
If you take ownership of a resource, that means that you will eventually release the resource (unless you transfer it to some other owner, and unless the ownership is shared). If you don't release the resource (or the mentioned exceptions apply), then either you have not taken ownership, or you have a bug.
std::string will only delete a buffer that std::string has created. std::string will not take ownership of a buffer that you have created. Your assumption of "std::string is taking the ownership" is wrong.
Never try to guess whether some function / constructor takes ownership or not. Always rely on documentation to find that out.
Or is it my responsibility to take care of that temporary object?
Yes. You are responsible for freeing the allocations that you create (until you transfer the onwership to something like a smart pointer).
The dynamic allocation that you created leaks, because you don't deallocate it.
And if so, the only way to destroying it is via having it as private variable, otherwise it goes out of scope
You can simply delete it after the std::string has been created and thus your buffer is no longer used.
Important! std::string constructor that accepts char* requires that the pointed string is null terminated. Your string doesn't contain the null terminator character, and thus the call violates the precondition. The behaviour of your program is undefined.
Furthermore, the allocation is entirely unnecessary. You can achieve the intended behaviour and fix both the undefined behaviour and the memory leak by writing the constructor like this:
A(): value("abc") {}
but what if I get the char pointer from another function that malloced it
Primarily, try to avoid calling such functions.
But in case you have no other option, then you must understand that the function is transferring the ownership of the allocation to you (I cannot think of any other reason the function would document that it used std::malloc). You must deallocate it using std::free once you no longer need it. Ideally, you should use something like a smart pointer to do so.
I used uuid_unparse which gives char pointer generated from malloc (see its documentation)
According to the documentation of uuid_unparse, it doesn't do such thing. It doesn't allocate anything. If you want to use it with std::string, you can do this:
uuid_t some_uuid = example_uuid();
constexpr std::size_t uuid_size = 36;
std::string str(uuid_size, '\0');
uuid_unparse(some_uuid, str.data());
The 5th constructor explained in the documentation takes the char* argument. It means it takes the pointer pointing the c-style string, calculates its length and then converts to std::string. The memory of original c-style char* string isn't released, so you have memory leak unless you later delete the char* string somewhere in code.
Most interesting comment:
#MarekR the point was, I tried to replicate the error I got. I used
uuid_unparse which gives char pointer generated from malloc (see its
documentation), but in class handling uuid I had std::string. And
since the std::string does not have ownership, I had to change the
implementation of the class to handle char pointers only –
milanHrabos
Apparently you are using uuid_unparse with c++ in wrong way and when problem appeared you asked question which do not reflect actual problem.
I would use this API in following way:
std::string uuid_to_string(uuid_t uu)
{
char buff[37];
uuid_unparse(uu, buff);
return buff; // implicit conversion to std::string is done here.
}
or more fancy way to do it:
std::string uuid_to_string(uuid_t uu)
{
std::string buff(size_t{36}, '\0');
uuid_unparse(uu, buff.data()); // since C++17 data returns `char *`
return buff;
}
About your code:
char *tmp = new char[3];
tmp[0] = 'a';
tmp[1] = 'b';
tmp[2] = 'c';
value = std::string(tmp);
this has 3 issues:
you are allocating memory which is not freed (string doesn't take over ownership of it) - so memory leak
your buffer do not contain terminating zero, so when it is passed to std::string this leads to undefined behavior since and of string can't be determined
code is simply over-complicated. After understudying what was its purpose I was able to provide simple solution.
void setCString(char* s){
char* t = new char[strlen(s) + 1];
strcpy(t, s);
delete[] m_cstring; //del old contents from member var
m_cstring = t;
}
rA.setCString("Bii");
Isn't this a memory leak? "Bii" is created in memory and a pointer to it (s) is passed to the function. In the function a new allocation is made and the contents of the s array are copied to the new t array.
When the function ends, s goes out of scope and is deleted but the initial original array that s pointed to is not deleted.
If this is a memory leak, how can it be fixed (sticking to c string as array... no std::string)?
"Loosing" the (probably sole) pointer to a string literal is not considered a memory leak, because string literals cannot be "freed" and its "allocated memory" reused. Actually freeing a string literal is undefined behaviour. So no "leak" in its common sense; just a string literal which might not be used any more.
I am initializing a char pointer with some random values, and when I am trying to delete it, I am unable to. Why is that?
Here is what I am doing:
int main()
{
char *s = new char[50]; /*
* I know there is no reason for
* using new if initializing, but
* in order to use delete we need
* to allocate using new.
*/
s = "Harry";
delete s;
return 0;
}
If you really want to practice with pointer, you need to fix your code. The main problem is you are trying to assign string literal( which is const char[6] in here) to pointer s then try to modify it by calling delete which invoke undefined behavior(UB).
char *s = new char[50];
strcpy(s, "Harry"); // don't assign string literal to it
// re-assign pointer to string literal,
// lost pre-allocated memory position and caused delete to fail
// it's UB to modify string literal
delete []s; // new[]/delete[], new/delete need to be called in pair.
Just use std::string instead.
#include <string>
std::string s("Harry"); // no worries
The problem is that after this assignment:
s = "Harry";
Then your s is no longer pointing to the memory you have allocated. It is pointing to a different array, or a const char[6] to be precise. The other array isn't dynamically allocated, and isn't on the heap. You can't delete variables that aren't on the heap.
In addition, by changing the s pointer to point at something else before the dynamically allocated memory has been freed, you introduce a memory leak.
To fix your code, either copy "Harry" into the s array by using strcpy, or use std::string instead.
You should never initialize a pointer with a string constant this way. It creates memory leaks which can be very dangerous.
When you allocated the memory using new, a 50 char memory was allocated in heap and its pointer is returned in s. when you were trying to initializing this value (wrong way) using s="Harry" , a new space is allocated in stack, initialized with this value and returned in s.
This memory allocated in stack cannot be deleted using delete call because it works only on heap.
Also, the memory initially allocated using new can no longer be accessed using s. Thus, you have a memory leak over here.
You can notice a different address in your pointer s after this wrong initialization by making small changes in your program:
#include <stdio.h>
int main()
{
char *s = new char[50];
printf("\n %u",s); // print address before init
s = "Harry";
printf("\n %u",s); // print address after init
// delete s; // cannot delete from stack
return 0;
}
Like others have already suggested, an array of character should be initialized using
strcpy(s, "Harry");
A char* is not actually a string. It is a pointer to some character with more characters to follow and ending with '\0'.
A character literal in C (and thus in C++) like "abc" is just an array of characters, with the compiler silently adding a '\0'. When you assign an array to a pointer, the array silently converts a pointer to the first element.
s = "Harry" means, the pointer s is assigned the address of the first character in the string literal "Harry". So the old value is lost and as this was the address of a dynamically allocated character array, leakage is supposed to happen.
std::strcpy, on the other hand, copies a string character by character from one array to another array. No pointers will be changed, only pieces of memory are copied. The pointer to the target array still points to the target array afterwards, only the data in that array has changed.
I don't think this occurs with initialized pointers.
When using a pointer, you can only delete (free) the memory it's pointing to, not the pointer itself, since it's an automatic object and will be deleted at the end of the block.
My code converts C++ strings to C strings somewhat often, and I am wondering if the original string is allocated on the stack. Will the C string be allocated on the stack as well? For instance:
string s = "Hello, World!";
char* s2 = s.c_str();
Will s2 be allocated on the stack, or in the heap? In other words, will I need to delete s2?
Conversely, if I have this code:
string s = new string("Hello, mr. heap...");
char* s2 = s.c_str();
Will s2 now be on the heap, as its origin was on the heap?
To clarify, when I ask if s2 is on the heap, I know that the pointer is on the stack. I'm asking if what it points to will be on the heap or the stack.
string s = "Hello world";
char* s2 = s.c_str();
Will s2 be allocated on the stack, or in the heap? In other words... Will I need to delete s2?
No, don't delete s2!
s2 is on the stack if the above code is inside a function; if the code's at global or namespace scope then s2 will be in some statically-allocated dynamically-initialised data segment. Either way, it is a pointer to a character (which in this case happens to be the first 'H' character in the null-terminated string_ representation of the text content of s). That text itself is wherever the s object felt like constructing that representation. Implementations are allowed to do that however they like, but the crucial implementation choice for std::string is whether it provides a "short-string optimisation" that allows very short strings to be embedded directly in the s object and whether "Hello world" is short enough to benefit from that optimisation:
if so, then s2 would point to memory inside s, which will be stack- or statically-allocated as explained for s2 above
otherwise, inside s there would be a pointer to dynamically allocated (free-store / heap) memory wherein the "Hello world\0" content whose address is returned by .c_str() would appear, and s2 would be a copy of that pointer value.
Note that c_str() is const, so for your code to compile you need to change to const char* s2 = ....
You must notdelete s2. The data to which s2 points is still owned and managed by the s object, will be invalidated by any call to non-const methods of s or by s going out of scope.
string s = new string("Hello, mr. heap...");
char* s2 = s.c_str();
Will s2 now be on the heap, as its origin was on the heap?
This code doesn't compile, as s is not a pointer and a string doesn't have a constructor like string(std::string*). You could change it to either:
string* s = new string("Hello, mr. heap...");
...or...
string s = *new string("Hello, mr. heap...");
The latter creates a memory leak and serves no useful purpose, so let's assume the former. Then:
char* s2 = s.c_str();
...needs to become...
const char* s2 = s->c_str();
Will s2 now be on the heap, as its origin was on the heap?
Yes. In all the scenarios, specifically if s itself is on the heap, then:
even if there's a short string optimisation buffer inside s to which c_str() yields a pointer, it must be on the heap, otherwise
if s uses a pointer to further memory to store the text, that memory will also be allocated from the heap.
But again, even knowing for sure that s2 points to heap-allocated memory, your code does not need to deallocate that memory - it will be done automatically when s is deleted:
string* s = new string("Hello, mr. heap...");
const char* s2 = s->c_str();
// <...use s2 for something...>
delete s; // "destruct" s and deallocate the heap used for it...
Of course, it's usually better just to use string s("xyz"); unless you need a lifetime beyond the local scope, and a std::unique_ptr<std::string> or std::shared_ptr<std::string> otherwise.
c_str() returns a pointer to an internal buffer in the string object. You don't ever free()/delete it.
It is only valid as long as the string it points into is in scope. In addition, if you call a non-const method of the string object, it is no longer guaranteed to be valid.
See std::string::c_str
std::string::c_str() returns a const char*, not a char *. That's a pretty good indication that you don't need to free it. Memory is managed by the instance (see some details in this link, for example), so it's only valid while the string instance is valid.
Firstly, even your original string is not allocated on the stack, as you seem to believe. At least not entirely. If your string s is declared as a local variable, only the string object itself is "allocated on the stack". The controlled sequence of that string object is allocated somewhere else. You are not supposed to know where it is allocated, but in most cases it is allocated on the heap. I.e. the actual string "Hello world" stored by s in your first example is generally allocated on the heap, regardless of where you declare your s.
Secondly, about c_str().
In the original specification of C++ (C++98) c_str generally returned a pointer to an independent buffer allocated somewhere. Again, you are not supposed to know where it is allocated, but in general case it was supposed to be allocated on the heap. Most implementations of std::string made sure that their controlled sequence was always zero-terminated, so their c_str returned a direct pointer to the controlled sequence.
In the new specification of C++ (C++11) it is now required that c_str returns a direct pointer to the controlled sequence.
In other words, in general case the result of c_str will point to a heap-allocated memory even for local std::string objects. Your first example is not duifferent from your second example in that regard. However, in any case the memory pointed by c_str() is not owned by you. You are not supposed to deallocate it. You are not supposed to even know where it is allocated.
s2 will be valid as long as s remains in scope. It's a pointer to memory that s owns. See e.g. this MSDN documentation: "the string has a limited lifetime and is owned by the class string."
If you want to use std::string inside a function as a factory for string manipulation, and then return C-style strings, you must allocate heap storage for the return value. Get space using malloc or new, and then copy the contents of s.c_str().
Will s2 be allocated on the stack, or in the heap?
Could be in either. For example, if the std::string class does small string optimization, the data will reside on the stack if its size is below the SSO threshold, and on the heap otherwise. (And this is all assuming the std::string object itself is on the stack.)
Will I need to delete s2?
No, the character array object returned by c_str is owned by the string object.
Will s2 now be on the heap, as its origin was on the heap?
In this case the data will likely reside in the heap anyway, even when doing SSO. But there's rarely a reason to dynamically allocate a std::string object.
That depends. If I remember correctly, CString makes a copy of the input string, so no, you wouldn't need to have any special heap allocation routines.