🔒 Locked
deallocating char*str = "hello"
Advertisement
Original Post
If you do char* pStr = "hello". The string is allocated on the stack, and will be freed when your function returns.
Here, pStr is a pointer to a char. It points to the first char of the string "hello". The string itself is allocated on the stack when your function starts. To allocate memory on the free store (dynamically), you have to use new (in C++) or malloc() (in C). All memory you allocate on the free store must be deallocated manually with delete (C++) or free() (C).
In C++ delete is meant to delete single elements, while delete [] is meant to delete multiple elements. Here, since your string contains multiple characters (including an invisible null terminating character), so you can assume that any string has multiple elements and should be deleted with delete []. In C, using malloc(), you don't care how many elements there are, you just pass it the pointer.
To allocate a string on the free store, write hello in it, and delete it, you would have to go:
char* pString = new char[20]; // Where 20 is the amount of chars you want to allocate
strcpy(pString, "hello"); // This copies hello into your string
delete [] pString; // This deallocates the string
pString = NULL; // You should set pointers to deleted memory to NULL because they are no longer valid
The rule is simple: don't delete something you didn't new, don't forget to delete everything you allocated.
Here, pStr is a pointer to a char. It points to the first char of the string "hello". The string itself is allocated on the stack when your function starts. To allocate memory on the free store (dynamically), you have to use new (in C++) or malloc() (in C). All memory you allocate on the free store must be deallocated manually with delete (C++) or free() (C).
In C++ delete is meant to delete single elements, while delete [] is meant to delete multiple elements. Here, since your string contains multiple characters (including an invisible null terminating character), so you can assume that any string has multiple elements and should be deleted with delete []. In C, using malloc(), you don't care how many elements there are, you just pass it the pointer.
To allocate a string on the free store, write hello in it, and delete it, you would have to go:
char* pString = new char[20]; // Where 20 is the amount of chars you want to allocate
strcpy(pString, "hello"); // This copies hello into your string
delete [] pString; // This deallocates the string
pString = NULL; // You should set pointers to deleted memory to NULL because they are no longer valid
The rule is simple: don't delete something you didn't new, don't forget to delete everything you allocated.
The C string "hello" is a static string constant, embedded into your program's source code. All you did was to have a pointer point to its address. No memory allocation is involved at all, and therefore, deallocation is neither necessary nor even possible.
Max - The string is not created on the stack, only the pointer is. If you think about it, the text for the string must exists somewhere in the code for it to be copied into a stack variable. All you do is set the address in the pointer to that of the string in the code (that's the difference between char* str="hello"; and char str[] = "hello";, the second does copy the string data). Which means that you really should have const char*, but char* is accepted for historical reasons.
Max - The string is not created on the stack, only the pointer is. If you think about it, the text for the string must exists somewhere in the code for it to be copied into a stack variable. All you do is set the address in the pointer to that of the string in the code (that's the difference between char* str="hello"; and char str[] = "hello";, the second does copy the string data). Which means that you really should have const char*, but char* is accepted for historical reasons.
Quote:
Original post by Max_Payne
If you do char* pStr = "hello". The string is allocated on the stack, and will be freed when your function returns.
That's not true. Literal strings (ones with "" around them) are statically allocated in the "string table", and cannot and should not be deallocated.
Now, to complicate things, if you were to do char[] aStr = "hello", you'd be allocating a character array locally and filling it with that string. Then that array would be on the stack. The original string, though, would still be in the string table.
Quote:
Original post by squicklid
so how do you differentiate between an array allocated at initialization and one allocated with new[] or new?
Short answer, you can't.
There is a long answer which is "you can't easily do it".
If you use std::string and std::vector instead of char* and c-style arrays you'll know that they're always dynamic (behind the scenes) but you won't be the one having to deal with allocation/deallocation as it's all already taken care of. No worries.
Quote:
Original post by Sneftel Quote:
Original post by Max_Payne
If you do char* pStr = "hello". The string is allocated on the stack, and will be freed when your function returns.
That's not true. Literal strings (ones with "" around them) are statically allocated in the "string table", and cannot and should not be deallocated.
Now, to complicate things, if you were to do char[] aStr = "hello", you'd be allocating a character array locally and filling it with that string. Then that array would be on the stack. The original string, though, would still be in the string table.
You can put pretty much all the data you want in your binaries, as long as you jump over it, but it could just as well be copied on the stack before use. Depends on how your compiler implements it.
Quote:
Original post by Max_Payne
You can put pretty much all the data you want in your program, as long as you jump over it, but it could just as well be copied on the stack before use. Depends on how your compiler implements it.
A string literal will not be copied onto the stack, as it would cause mighty lifetime issues: what happens when the function returns?
Quote:
That's not true. Literal strings (ones with "" around them) are statically allocated in the "string table"...
That's not quite true, either. There's no stipulation that string literals need to be allocated in any sort of table or any other coherent data structure. The only guarantee is that string literals are of static duration. Of course, you're correct in that probably all compilers place all string literals together somehow in the executable image, but that's not because the language specification requires it.
Well say you passed the address of a char* to a function, and the function went something like this:
When it gets to if (*ppc) it will be true, and will try to free memory on the stack. Is there some way of telling where this memory is?(stack or freestore)
char* f(char**ppc){ char* pnewc = new char[4]; if (*ppc) delete[] *ppc; *ppc = pnewc; return pnewc;}When it gets to if (*ppc) it will be true, and will try to free memory on the stack. Is there some way of telling where this memory is?(stack or freestore)
Quote:
Original post by Fruny Quote:
Original post by Max_Payne
You can put pretty much all the data you want in your program, as long as you jump over it, but it could just as well be copied on the stack before use. Depends on how your compiler implements it.
A string literal will not be copied onto the stack, as it would cause mighty lifetime issues: what happens when the function returns?
I never did anything like this:
char* GetString() { return "hello"; }
But rather did:
char* GetString(char* pString) { strcpy(pString, "hello"); return pString; }
Because I assumed hello would go poof when the function returned. I didn't know the C++ standards said otherwise... Kind of goes against basic principles of the language to me... Returning a pointer to something that appears only locally, its kind of like:
int* GetInt() { return &125; }
Anyhow, when I design my own language, that won't be possible ;)
Quote:
Original post by squicklid
Well say you passed the address of a char* to a function, and the function went something like this:char* f(char**ppc){ char* pnewc = new char[4]; if (*ppc) delete[] *ppc; *ppc = pnewc; return pnewc;}
When it gets to if (*ppc) it will be true, and will try to free memory on the stack. Is there some way of telling where this memory is?(stack or freestore)
Thats kind of nasty. First, why a pointer to a pointer to a char... You're returning your pnewc anyways. Second, you usually don't want to allocate something in a function and delete it in another... Unless you designed your code so that you know where the memory you are using came from (ie: constructor and destructor calls, functions that perform specific actions on specific object types).
The string literal may only appear locally in the source code, but it does exists statically in the binary - it is part of the program image that is loaded into memory. When you write "hello", the compiler gives you a pointer to that static string. What you don't know is whether all instances of the "hello" literal all point to the same address or not. Within a single translation module, it is conceivable that the compiler would merge them all, which is harder to do when linking multiple translation units, and is why you are told you cannot compare strings with ==. Which is one more reason for string literals to be constant (though gcc has a -fwritable-strings option that ensures all string literals are distinct, and makes them writable, for old programs that assume you can write to string constants (historical reasons again)). In shared libraries (e.g. DLLs), assuming the strings are constants allow them to be shared by all the programs using the library (i.e. there is only one copy of the string in memory, regardless of how many programs use the library).
You should probably use 'const char *string = "whatever";', since writing to a string literal would be a Bad Thing™.
Quote:
Original post by squicklid
The pointer to a pointer to a char is necessary if you want the function to change the original and are changing the pointer.
Well, you could use a reference,
char *weird_function(char *&str) { /* stuff */ }Just a matter of style though; some people like it one way, some like it the other way.
John B
Getting back on topic here, the original poster wanted to know how to differentiate between an array allocated at initialization and one allocated with new[] or new
The answer is, simply look at the variables definition.
If it was in the same function then you would just look how it was declared and do the appropriate thing.
The only time you would want to know it you have to delete the pointers memory or not, is if it is passed into another function where the delete (or not as appropriate) takes place.
This is bad programming practice. A function should not delete something that it didn't allocate, unless it was designed solely for a destroying purpose and does nothing else. In that case there would then be no need to pass this pointer into that function as it is automatically destroyed.
The answer is, simply look at the variables definition.
If it was in the same function then you would just look how it was declared and do the appropriate thing.
The only time you would want to know it you have to delete the pointers memory or not, is if it is passed into another function where the delete (or not as appropriate) takes place.
This is bad programming practice. A function should not delete something that it didn't allocate, unless it was designed solely for a destroying purpose and does nothing else. In that case there would then be no need to pass this pointer into that function as it is automatically destroyed.
use std::string :P
Sorry, but someone had to say it...
Sorry, but someone had to say it...
Quote:
Original post by Max_Payne
Because I assumed hello would go poof when the function returned. I didn't know the C++ standards said otherwise... Kind of goes against basic principles of the language to me...
Strings constants are a bit of a special case in C/C++ because it would be very inconvenient to deal with them otherwise. Writing
int f(){ const char* aCharPointer = "Foo";} is shorthand for
const char gCharArray[] = { 'F', 'o', 'o', '\0' };int f(){ const char* anotherCharPointer = gCharArray;}In fact, any time a string literal appears in your code the compiler effectively creates a global constant character array which is stored in a data section of your executable. Can you see why they chose to introduce this shorthand way of using character constants? It would be pretty painful dealing with strings otherwise.
So what happens in this case:
What gets written to the console?
On a related note, can you somehow modify the string table and cause cross-program borkage? Does the above example do anything to the string table?
#include <iostream>void promethium(){ char* Str = "Hello"; Str[3] = 'j';}int main(){ promethium(); std::cout << "Hello" << std::endl; return 0;}What gets written to the console?
On a related note, can you somehow modify the string table and cause cross-program borkage? Does the above example do anything to the string table?
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement