I have the following code, I wonder what is the difference between the implementation of str2 and str3, they both give the same results, which one is more prone to errors?
EDIT: when I was testing the representation of str2, I have found that one time my code crashed because str2 was a bad pointer!
/* strcpy example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[] = "Sample string";
char str0[] = "Sample String and more";
char* str2;
str2 = new char[40];
char str3[40];
strcpy (str2,str1);
strcpy (str3,str1);
strcpy (str2,str0);// crash happened here str2 is bad pointer!!!
printf ("str1: %s\nstr2: %s\nstr3: %s\n",str1,str2,str3);
delete str2;
return 0;
}
Aside from the fact that str2 is a pointer whereas str3 is an array (and a pointer is a bit more trickier to use, since you may forget to delete it etc), there is another issue: the memory allocated for str2 is on the free space, via operator new. This is a slow operation. In contrast, str3 has automatic storage duration, and most often its memory is allocated on the stack, which is much faster. So in performance critical code this may make a difference.
Related
exception in strcpy();
void recid(string str,int *begin, int *end)
{
char *f,*str2;
const char c1[2]=":",c2[2]="-";
strcpy(str2,str.c_str());
f=strtok(str2,c1);
f=strtok(NULL,c2);
*begin=atoi(f);
f=strtok(NULL,c2);
*end=atoi(f);
}
could you help me to solve it?
str2 is an uninitialised pointer. strcpy does not allocate memory so is currently trying to write to an arbitrary address which you don't own and very likely isn't writable by your code.
You need to point str2 to valid memory before calling strcpy.
str2 = (char*)malloc(str.size()+1);
strcpy(str2,str.c_str());
You should also free the memory later in your program
free(str2); // cannot dereference str2 after this point
The problem is that you write in an uninitialized/random memory location by not initializing str2.
First solution:
str2 = new char[str.size() + 1];
strcpy(str2, str.c_str());
...
delete[] str2.
Second (better solution): Do not use pointers in your code unless you have to:
std::string str2 = str1;
Also, consider using std::ostringstream for tokenization into std::strings and converting to int.
So in attempting to learn how to use C-Strings in C++, I'm running into issues with memory allocation.
The idea here is that a new string is created of the format (s1 + sep + s2)
The text I'm using provided the header, so I can't change that, but I'm running into issues trying to set the size of char str[]. I am getting an error saying that sLength is not constant, and therefore cannot be used to set the size of an array. I'm relatively new to C++ so this is a two part question.
Is this strategy actually allocating memory for the new array?
How do I set the array size correctly if I can't get a constant value using strlen(char*)?
char* concatStrings(char* s1, char* s2, char sep){
int sLength = strlen(s1) + strlen(s2) + 3;
//+1 for char sep +2 for \0 at end of string
char *str = new char[sLength];
strcpy (str, s1);
str [sLength(s1)] = sep;
strcat (str, s2);
return str;
}
Edits made, so now I'm getting no compiler errors but...
The call to the function is here:
char* str = concatStrings("Here is String one", "Here is String two" , c);
cout<< str;
My output becomes:
Here is String onec==================22221/21/21/21/2 /(etc.)/ Here is String two
Error is returning address of local array variable str. Its scope is within function concatStrings() where you declared, and can't be accessed once control returns from the function.
To access it outside, you need to dynamically allocate memory for the string from the heap using the new operator.
char* concatStrings(char* s1, char* s2, char sep){
int s1Length = strlen(s1);
int sLength = s1Length + strlen(s2) + 2;
// +1 for sep and +1 \0 at end of string
char* str = new char[sLength];
strcpy (str, s1);
// Use strlen here instead of sizeof()
str [s1Length] = sep;
str [s1Length + 1] = '\0';
strcat (str, s2);
return str;
}
And after the program is done using the string returned from concatStrings it should ensure to free up the memory by invoking delete
char* str = concatStrings(s1, s2, sep);
// Do something
// Free up memory used by str
delete[] str;
Must use delete[] here instead of delete, or it results in undefined behaviour
I've also edited the concatStrings() function to use strlen instead of sizeof
UPDATE: Thanks for pointing out that we only need to do +2 and not +3 and for making sure a '\0' needs to be appended after str1 and sep before invoking strcat
You can allocate the resulting string memory dynamically (at run-time, on the heap), using new[] in C++ (or malloc for a more C-like style):
char* concatStrings(const char* s1, const char* s2, char sep) // enforced const correctness
{
const size_t totalLength = strlen(s1) + strlen(s2)
+ 2; // +1 for sep char, +1 for '\0'
// Dynamically allocate room for the new string (on the heap)
char* str = new char[totalLength];
strcpy(str, s1);
str[strlen(s1)] = sep; // note that you had a typo with sizeof(s1) here
strcat(str, s2);
return str;
}
Note that this memory must be released somewhere in your code, using delete[] if it was allocated with new[], or free() if it was allocated using malloc().
This is quite complicated.
You will simplify your code a lot if you use a robust C++ string class like std::string, with its convenient constructors to allocate memory, destructor to automatically free it, and operator+ and operator+= overloads to concatenate strings. See how your code is simplified using std::string:
#include <string> // for std::string
std::string str = s1;
str += sep;
str += s2;
(Note that using raw C strings can also make your code more vulnerable to safety problems, since you must pay lot of attention to proper sizing destination strings, avoid buffer overruns, etc. This is another reason to prefer a RAII robust string class like std::string.)
sizeof(s1) returns the size of a pointer variable, not the length of the array which it points to. Since you know that s1 points to a C-string, you should use the strlen() function instead.
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).
Consider the following piece of code:
char* str1 = new char [30];
char* str2 = new char [40];
strcpy(str1, "Memory leak");
str2 = str1;
delete [] str2;
delete [] str1;
Why does the above program cause a memory leak? How do I avoid this?
The above doesn't just lead to a memory leak; it causes undefined behavior, which is much, much worse.
The problem is in the last three lines:
str2 = str1;
delete [] str2;
delete [] str1;
If we ignore this first line, then the last two lines correctly reclaim all the memory allocated in this function. However, this first line sets str2 to point to the same buffer as str1. Since str2 is the only pointer in the program to the dynamic memory it references, this line leaks the memory for that buffer. Worse, when you then execute the next two lines to clean up the two pointers, you delete the same block of memory twice, once through str2 and once through str1. This leads to undefined behavior and often causes crashes. Particularly malicious users can actually use this to execute arbitrary code in your program, so be careful not to do this!
But there's one higher-level issue to take into account here. The whole problem with this setup is that you have to do all your own memory management. If you opt to use std::string instead of raw C-style strings, then you can write the code like this:
string str1 = "Memory leak"; // Actually, it doesn't. :-)
string str2;
str2 = str1; // Okay, make str2 a copy of str1
// All memory reclaimed when this function or block ends
Now, there's no need to explicitly manage the memory, and you don't have to worry about buffer overruns or double-frees. You're saved by the magic of object memory allocation.
Because you're deleting str1 (the memory it points to) twice and you don't delete the memory allocated under where str2 was first pointing to.
EDIT:
I'm not sure what you're trying to achieve.
char* str1 = new char [30];
// str1 = 0x00c06810; (i.e.)
char* str2 = new char [40];
// str2 = 0x00d12340; (i.e.)
strcpy(str1, "Memory leak");
// delete [] str2; should be here
str2 = str1;
// now str2 == str1, so str2 = 0x00c06810 and str1 = 0x00c06810
// deleting 0x00c06810
delete [] str2;
// deleting 0x00c06810 once again
delete [] str1;
// 0x00d12340 not deleted - memory leak
If you want that assignment (str2 = str1) then delete str2 first.
You assign str1 pointer to str2 pointer, so delete[]str1 and delete[]str2 free only memory pointed by str1 (str2 points to the same memory). You need to free str2 memory before loosing pointer to it (before assigning str1 to str2)
The correct way is
char* str1 = new char [30];
char* str2 = new char [40]; //or just don't allocate this if You don;t need it
strcpy(str1, "Memory leak");
**delete [] str2;**
str2 = str1;
delete [] str1;
make pointers to be const pointers
The problem is that you allocate memory for two arrays, you get two pointers, then you overwrite address of the second array with address of first array. So you try to free memory of the first array
Every object needs to be pointed-at in the memory.
The pointers keep track of where the data is (remember that your RAM memory is HUGE compared to the little array).
So in your case, you're losing the second array's place in memory. So there's an array lost somewhere in memory that you can't get to.
When you do str2 = str1; str2 points now to the block of memory that str1 pointed to. So there's nothing left to point at the second array.
I am trying to append two chars but for some reason I am getting a segmentation fault.
My code is like;
#include <string.h>
char *one = (char*)("one");
char *two = (char*)("two");
strcat(one, two);
and I seem to be getting a segmentation fault at strcat(one, two), why is that?
http://www.cplusplus.com/reference/clibrary/cstring/strcat/
the first parameter to strcat, must be big enough to hold the resulting string
try:
//assuming a,b are char*
char* sum = new char[strlen(a) +strlen(b)+1];
strcpy(sum,a);
strcat(sum,b);
There should be enough legal memory to hold the entire string.
char *one = new char[128]; //allocating enough memory!
const char *two = "two"; //"two" is const char*
strcpy(one, "one");
strcat(one, two); //now the variable "one" has enough memory to hold the entire string
By the way, if you prefer using std::string over char* in C++, such thing would be easier to handle:
#include<string>
std::string one = "one";
std::string two = "two";
one = one + two; //Concatenate
std::cout << one;
Output:
onetwo
There are two reasons for this.
If you have a pointer initialized to a string literal, that memory is read-only and modifying it will result in undefined behavior. In this case, if you try to append a string to a string literal, you'll be modifying this sort of memory, which will result in problems.
When using strcat you need to guarantee that space exists for the concatenation of the string at the location you're specifying. In this case, you cannot guarantee that, since a string literal is only guaranteed to have enough space to hold the literal itself.
To fix this, you'll want to explicitly allocate a buffer large enough to hold the concatenation of the two strings, including the null terminator. Here's one approach:
char* buffer = malloc(strlen(one) + strlen(two) + 1);
strcpy(buffer, one);
strcat(buffer, two);
Hope this helps!
The seg fault is because you attempt to write to read only memory. The first action of the strcat is to copy of 't' from the first entry of two into the null at the end of "one". So strictly the seg fault is not due to lack of storage - we never get that far. In fact this code will also likely give you a seg fault:
char* one = "one";
char* two = "";
strcat(one, two);
All this tries to do is copy a null over a null, but in read-only memory. I suppose a optimiser might happen to stop this on some platforms.
Oddly enough the following (incorrect) code will (probably) not give you a seg fault, and even give the "right" answer:
char one[] = "one";
char two[] = "two";
strcat(one, two);
printf("%s\n", one);
This successfully writes "onetwo" to stdout on my machine. We get a stack scribble, which we happen to get away with.
On the other hand this does seg fault:
char* one = "one "; // Plenty of storage, but not writable.
char two[] = "two";
strcat(one,two);
Hence the solution:
const unsigned enoughSpace = 32;
char one[enoughSpace] = "one";
char two[] = "two";
strcat(one,two);
printf("%s\n", one);
The issue with this is of course, how large to make enoughSpace in order to store what ever is coming?
Hence the functions strncat, or strcat_s, or more easily std::string.
Moral of the story: in C++, just like C, you really need to know what your memory layout is.
There are several problems here. Firstly, though you have casted the strings to mutable versions, they really are string literals and hence should not be written. Secondly, you are using strcat which will write into the string buffer, completely ignoring the length of the string buffer (it's better to use strncat which requires you to specify the length of the buffer). Lastly, since this is C++, it would be way better to use:
#include <string>
// ...
string one = "one";
string two = "two";
one.append(two);
You never reserved some space for your strings.
#include <string.h>
#include <stdio.h>
int main(void){
char str[20] = "";
strcat(str, "one");
strcat(str, "two");
printf("%s", str);
}
Would be one correct way to do this. The other (and way better) is to use the std::string class.
#include <string>
#include <cstdio>
int main(void){
std::string str;
str += "one";
str += "two";
std::printf("%s", str.c_str());
}
Your destination string should be large enough to hold both the destination and the source string. So an example would be
char one[10] = "one";
char two[4] = "two";
strcat(one,two);
strcat needs a "writeable" buffer as the target. In your example, it is a pointer to a string constant (or literal), which you cannot write to, thus it results in an exception. The target buffer can be a buffer on the stack or one dynamically allocated (e.g., with malloc).
This is not the problem of "not enough space".
char *a = "str";
Look at the code above, the pointer a is point to "static memory". The string "str" is stored in the static place in the PCB, which means it can't be overwritten.
So, the codes below will be better:
#include <string>
using std::string;
string a = "stra";
string b = "strb";
a += b;