Segmentation Fault in deleting char pointer - c++

I'm posting two fragments here.
The first one is giving me Segmentation Fault on deallocating the memory. Second one is working fine.
1)
int main()
{
char* ch = new char;
ch = "hello";
cout << "\n " << ch << endl;
delete[] ch; ////OR delete ch; ---> have tried both
return 0;
}
2)
int main()
{
char* ch = new char;
cin >> ch;
cout << "\n " << ch << endl;
delete[] ch; ///OR delete ch /// Both are working fine....
return 0;
}
Could anybody please tell me why the first one is failing with Segmentation Fault and second one is working fine with both delete and delete[]. Because to me both the program seems to same.

new char generates exactly 1 character (not an array of 1 character, use new char[1] for that)
so delete[] doesn't apply
in the first example, you overwrite your pointer to your allocated 1 character with a pointer to the character string "hello" - deleting this string (as it is static memory) will result in sesgfault
Edit
int main()
{
char* ch = new char; // ch points to 1 character in dynamic memory
ch = "hello"; // overwrite ch with pointer to static memory "hello"
cout<<"\n "<<ch<<endl; // outputs the content of the static memory
delete[] ch; // tries to delete static memory
return 0;
}

There are issues with both examples:
char* ch = new char;`
ch = "hello";`
The new returns an address that points to dynamically allocated memory. You must save this return value so that delete can be issued later. The code above overwrites this value with "hello" (a string-literal). You now have lost the value, and thus can not call delete with the proper value.
The second example, even though you say "works fine" is still faulty.
char* ch = new char;`
delete[] ch; ///OR delete ch /// Both are working fine....`
The wrong form of delete is used. You allocated with new, so you must deallocate with delete, not delete[]. It works this way: new->delete, new[]->delete[].
Unlike most other languages, if you go against the rules of C++, corrupt memory, overwrite a buffer, etc., there is no guarantee that your program will crash, seg fault, etc. to let you know that you've done something wrong.
In this case, you're lucky that simple types such as char* are not affected by you using the wrong form of delete. But you cannot guarantee that this will always work if you change compilers, runtime settings, etc.

There are a couple of problems with each, namely that you're only allocating a single character when you're trying to allocate a character array.
In the first example, you're also allocating a single character and then subsequently reassign the pointer to a character array - ch = "hello" will not copy the string, just reassign the pointer. Your call to delete[] will then attempt to delete a string that is not heap allocated, hence the seg fault. And you're also leaking the char you allocated, too.

In the first one, you change the pointer to point to a string literal:
ch = "hello";
String literals are static arrays, so mustn't be deleted.
The second is wrong for at least two reasons:
you allocate a single character, not an array; a single character would be deleted with delete not delete[]
cin>>ch will (most likely) read more than one character, but you've only allocated space for one.
Both of these cause undefined behaviour, which might manifest itself as a visible error, or might appear to "work fine" - but could fail when you least expect it.
To allocate an array, use new char[SIZE]; but even then, you can't prevent the user from giving too much input and overflowing the buffer.
Unless you're teaching yourself how to juggle raw memory (which is a dark art, best avoided unless absolutely necessary), you should stick to high-level types that manage memory for you:
std::string string;
string = "hello";
std::cout << string << '\n';
std::cin >> string;
std::cout << string << '\n';

there are several errors in your programs.
In the first program you are not deleting something dynamically allocated but the statically allocated string "hello". Infact when you execute ch="hello" you are not copying the string in the wrongly allocated buffer "new char" ( this new just allocates one char, not what you are looking for ) but you makes the pointer ch to point to the start of the string "hello" located somewhere in the non writable memory ( normaly that string are pointed directly into the executable ). So the delete operation is trying to deallocate something that cannot be deallocate. So the first program culd be rewritten like:
int main()
{
const char* ch = "hello";
cout<<"\n "<<ch<<endl;
return 0;
}
or like
int main()
{
char* ch = new char[strlen("hello")+1];
strcpy( ch, "hello");
cout<<"\n "<<ch<<endl;
delete[] ch; // with square brackets, it's an array
return 0;
}

Here's what's wrong with both snippets:
First snippet:
char* ch = new char; ch = "hello";
It's not legal to assign a string literal to a non-const char pointer .
Also, you re-assign the pointer immediately after you call new. The original value returned by new is now lost forever and can not be free for the duration of the program. This is known as a memory leak.
delete[] ch;
You try to deallocate the string literal. This crashes your program. You are only allowed to delete pointers that you get from new and delete[] pointers that you get from new[]. Deleting anything else has undefined behaviour.
Second snippet:
cout<<"\n "<<ch<<endl;
ch points to a single character, not a zero terminated char array. Passing this pointer to cout has undefined behaviour. You should use cout << *ch; to print that single character or make sure that ch points to a character array that is zero terminated.
delete[] ch;
You allocated with new, you must deallocate with delete. Using delete[] here has undefined behaviour.
Both are working fine....
"working fine" is one possible outcome of undefined behaviour, just like a runtime error is.
To answer the question, neither snippet is correct. First one crashes because you got lucky, second one appears to work because you got unlucky.
Solution: Use std::string.

You should use something like:
char* ch = new char[6] ;
strcpy(ch,"hello") ;
...
delete[] ch ;

Related

Dumb questions: strcat and char pointers

I am usually not using pointer chars when working with strings but I usually think they are better in the sense that I can print the whole string without iterating each character.
Anyway since I don't use them I don't really know how these two interact. When running the following code the program crashes, so I've got no clue what to do since there's no error.
int main(){
char s[]="abcde";
char *p;
for(unsigned int i=0;i<strlen(s);i++)
strcat(p,s+i);
cout<<*p;
}
I tried representing both strings as pointers and it didn't change anything. It crashes only if I try to print the second array. I tried *p++=*s or something similar I've found on google but it still crashes, what am I doing wrong?
Pointer p points nowhere, you need to reserve memory for the second array. For example,
char *p = new char [strlen(s) + 1];
Also strcat in a for loop is not the best way to copy a string. Try
strcpy(p, s);
(after allocating memory to p, of course).
Addition: If you need to use strcat instead of strcpy, you need to initialize string p with empty string, that is:
char *p = new char [strlen(s) + 1];
*p = '\0';
You are not allocating memory to a pointer p. When you call strcat without allocating memory of course you will get segmentation fault since strcat will try to write to a memory pointer by the pointer p.
You don't need a for loop for concatenating strings. strcat function does full string copying to memory pointed by p.
If you want print whole string don't deference pointer p fi you want print the whole string, deferencing results in printing only the first character of a string.
#include<iostream>
#include<cstring>
int main(){
char s[]="abcde";
//Allocating memory to so that p points valid memory.
char concatenatedString[50] = "";
//Initializing pointer to allocated memory.
char *p = concatenatedString;
// for(unsigned int i = 0;i < strlen(s); i++) //Not required.
strcat(p,s);
//Here don't dereference if you want to print whole string.
std::cout<<p;
}

Getting a word after a certain character?

I'm trying to make myself a program that will take a String and give me the word after a certain character. So, for example:
String theString = "hello \t world"; // or "borld \t bello";
After the tab, I only want "world" and not "hello." This keeps crashing on me for some reason.
size_t delimiter = theString.find_last_of('\t');
char *test;
if (theString.find("hello") != string::npos) {
strcpy(test, theString.substr(delimiter + 1).c_str());
else if (theString.find("borld") != string::npos) {
strcpy(test, theString.substr(delimiter + 1).c_str());
}
cout << test;
From strcpy manual:
char *strcpy(char *dest, const char *src);
The strcpy() function copies the string pointed to by src, including
the terminating null byte ('\0'), to the buffer pointed to by dest.
In your code, you declare test as a pointer to char* but you never initialize it.
test is therefore a pointer to indeterminate value. You then attempt to copy data to that inderminate location, resulting in the crash.
You can fix this easily by initializing test to point to memory you can strcpy to. Be sure to allow enough to not write beyond the buffer.
always the same mistake why you write to test without initializing it?
char *test; // no memory allocated so using it will cause a segfault
char test[50]; // just for explaining we allocate 50 bytes for pointer test
// char* test = new char[50]; // the same above but here dynamic memory
// delete[] test; // free up memory because dynamic memory is not automatically freed

C++ substring from string

I'm pretty new to C++ and I'm need to create MyString class, and its method to create new MyString object from another's substring, but chosen substring changes while class is being created and when I print it with my method.
Here is my code:
#include <iostream>
#include <cstring>
using namespace std;
class MyString {
public:
char* str;
MyString(char* str2create){
str = str2create;
}
MyString Substr(int index2start, int length) {
char substr[length];
int i = 0;
while(i < length) {
substr[i] = str[index2start + i];
i++;
}
cout<<substr<<endl; // prints normal string
return MyString(substr);
}
void Print() {
cout<<str<<endl;
}
};
int main() {
char str[] = {"hi, I'm a string"};
MyString myStr = MyString(str);
myStr.Print();
MyString myStr1 = myStr.Substr(10, 7);
cout<<myStr1.str<<endl;
cout<<"here is the substring I've done:"<<endl;
myStr1.Print();
return 0;
}
And here is the output:
hi, I'm a string
string
stri
here is the substring I've done:
♦
Have to walk this through to explain what's going wrong properly so bear with me.
int main() {
char str[] = {"hi, I'm a string"};
Allocated a temporary array of 17 characters (16 letters plus a the terminating null), placed the characters "hi, I'm a string" in it, and ended it off with a null. Temporary means what it sound like. When the function ends, str is gone. Anything pointing at str is now pointing at garbage. It may shamble on for a while and give some semblance of life before it is reused and overwritten, but really it's a zombie and can only be trusted to kill your program and eat its brains.
MyString myStr = MyString(str);
Creates myStr, another temporary variable. Called the constructor with the array of characters. So let's take a look at the constructor:
MyString(char* str2create){
str = str2create;
}
Take a pointer to a character, in this case it will have a pointer to the first element of main's str. This pointer will be assigned to MyString's str. There is no copying of the "hi, I'm a string". Both mains's str and MyString's strpoint to the same place in memory. This is a dangerous condition because alterations to one will affect the other. If one str goes away, so goes the other. If one str is overwritten, so too is the other.
What the constructor should do is:
MyString(char* str2create){
size_t len = strlen(str2create); //
str = new char[len+1]; // create appropriately sized buffer to hold string
// +1 to hold the null
strcpy(str, str2create); // copy source string to MyString
}
A few caveats: This is really really easy to break. Pass in a str2create that never ends, for example, and the strlen will go spinning off into unassigned memory and the results will be unpredictable.
For now we'll assume no one is being particularly malicious and will only enter good values, but this has been shown to be really bad assumption in the real world.
This also forces a requirement for a destructor to release the memory used by str
virtual ~MyString(){
delete[] str;
}
It also adds a requirement for copy and move constructors and copy and move assignment operators to avoid violating the Rule of Three/Five.
Back to OP's Code...
str and myStr point at the same place in memory, but this isn't bad yet. Because this program is a trivial one, it never becomes a problem. myStr and str both expire at the same point and neither are modified again.
myStr.Print();
Will print correctly because nothing has changed in str or myStr.
MyString myStr1 = myStr.Substr(10, 7);
Requires us to look at MyString::Substr to see what happens.
MyString Substr(int index2start, int length) {
char substr[length];
Creates a temporary character array of size length. First off, this is non-standard C++. It won't compile under a lot of compilers, do just don't do this in the first place. Second, it's temporary. When the function ends, this value is garbage. Don't take any pointers to substr because it won't be around long enough to use them. Third, no space was reserved for the terminating null. This string will be a buffer overrun waiting to happen.
int i = 0;
while(i < length) {
substr[i] = str[index2start + i];
i++;
}
OK that's pretty good. Copy from source to destination. What it is missing is the null termination so users of the char array knows when it ends.
cout<<substr<<endl; // prints normal string
And that buffer overrun waiting to happen? Just happened. Whups. You got unlucky because it looks like it worked rather than crashing and letting you know that it didn't. Must have been a null in memory at exactly the right place.
return MyString(substr);
And this created a new MyString that points to substr. Right before substr hit the end of the function and died. This new MyString points to garbage almost instantly.
}
What Substr should do:
MyString Substr(int index2start, int length)
{
std::unique_ptr<char[]> substr(new char[length + 1]);
// unique_ptr is probably paranoid overkill, but if something does go
// wrong, the array's destruction is virtually guaranteed
int i = 0;
while (i < length)
{
substr[i] = str[index2start + i];
i++;
}
substr[length] = '\0';// null terminate
cout<<substr.get()<<endl; // get() gets the array out of the unique_ptr
return MyString(substr.get()); // google "copy elision" for more information
// on this line.
}
Back in OP's code, with the return to the main function that which was substr starts to be reused and overwritten.
cout<<myStr1.str<<endl;
Prints myStr1.str and already we can see some of it has been reused and destroyed.
cout<<"here is the substring I've done:"<<endl;
myStr1.Print();
More death, more destruction, less string.
Things to not do in the future:
Sharing pointers where data should have been copied.
Pointers to temporary data.
Not null terminating strings.
Your function Substr returns the address of a local variable substr indirectly by storing a pointer to it in the return value MyString object. It's invalid to dereference a pointer to a local variable once it has gone out of scope.
I suggest you decide whether your class wraps an external string, or owns its own string data, in which case you will need to copy the input string to a member buffer.

Resizing char array not always working

In a custom string class called Str I have a function c_str() that just returns the private member char* data as const char* c_str() const { return data; }. This works when called after I create a new Str but if I then overwrite the Str using cin, calling c_str() on it only sometimes works, but always works if I cin a bigger Str than the original.
Str b("this is b");
cout << b.c_str() << endl;
cin >> b;
cout << b.c_str() << endl;
Here the first b.c_str() works but if I attempt to change Str b to just 'b' on the cin >> b; line then it outputs 'b' + a bit of garbage. But if I try to change it to 'bb' it usually works, and if I change it to something longer than "this is b", it always works.
This is odd because my istream operator (which is friended) completely deallocates the Str and ends up allocating a new char array only 1 char larger for each char it reads in (just to see if it would work, it doesn't). So it seems like returning the array after reading in something else would return the new array that data is set it.
Relevant functions:
istream& operator>>(istream& is, Str& s) {
delete[] s.data;
s.data = nullptr;
s.length = s.limit = 0;
char c;
while (is.get(c) && isspace(c)) ;
if (is) {
do s.push_back(c);
while (is.get(c) && !isspace(c));
if (is)
is.unget();
}
return is;
}
void Str::push_back(char c) {
if (length == limit) {
++limit;
char* newData = new char[limit];
for (size_type i = 0; i != length; ++i)
newData[i] = data[i];
delete[] data;
data = newData;
}
data[length++] = c;
}
With push_back() like this, the array never has a capacity larger than what it holds, so I don't see how my c_str() could output any memory garbage.
Based on the push_back() in the question and the c_str() in the comment, there is no guarantee that the C-string returned from c_str() is null-terminated. Since a char const* doesn't know the length of the string without the null-terminator this is the source of the problem!
When allocating small memory objects you probably get back one of the small memory object previously used by you string class and that contains non-null characters, causing the printed character appear as if it is of what is the length to first null byte found. When allocating bigger chunks you seem to get back "fresh" memory which still contains null character, making the situation appear as if all is OK.
There are basically two ways to fix this problem:
Add a null-terminator before returning a char const* from c_str(). If you don't care multi-threading for now, this can be done in the c_str() function. In contexts where multi-threading matters it is probably a bad idea to make any mutations in const member functions as these would introduce data races. Thus, the C++ standard string classes add the null-terminator in one of the mutating operations.
Do not support a c_str() function at all but rather implement an output operator for your string class. This way, no null-termination is needed.

const char* 's in C++

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.