I have a difficulty in understanding how strcat works.
char A[] = "H";
char B[] = "L";
char C[] = "12345678901234567890"; // 20 digits => 20 bytes
cout<< &A <<" "<< &B <<" "<< &C <<endl;
strcat(A,C);
cout<< &A <<" "<< &B <<" "<< &C <<endl;
Output is
0x7ffd98b99f80 0x7ffd98b99f90 0x7ffd98b99fa0
0x7ffd98b99f80 0x7ffd98b99f90 0x7ffd98b99fa0
According to my understanding, before running strcat, difference in A's location and B's location is 0x10. This means, they have 16 bytes of space in between. After strcat, A has 20 more characters which means it should occupy 20 bytes more. To accommodate these additional characters, I thought that either A or B is shifted to a new location. But neither happens. Where is A storing all its bytes now? How does strcpy work?
strcat does not allocate new memory for you, it is your job to make sure the destination buffer is big enough. It will simply append to the original string assuming it can.
This is clearly stated in every documentation.
When you use strcat, you are responsible for providing adequate space. If you neglect to do so (as in your example), you write into unreserved space, which is undefined behavior.
What's happening is that you are lucky.
strcat() copies the contents of B to the end of A.
In your case, that appears to be exactly where B already exists. You are lucky that your implementation didn't fail on that alone.
strcat() will never (re)allocate memory for a string -- the memory must already exist and be sufficient for the additional string data. Otherwise you are overwriting other objects in memory -- which may cause disastrous results.
Related
I have this code,
char a[0];
cout << "What is a? " << a << endl;
char *word = itoa(123,a,10);
string yr = string(word);
but i have trouble comprehending the array a[0]. I tried to change its value and see if there is any changes, but it seems to make no differences at all.
example, even if a change a[0] to a[1], or any other integer, the output still make no difference
char a[1];
cout << "What is a? " << a << endl;
char *word = itoa(123,a,10);
string yr = string(word);
What is its purpose here?
Since itoa function is non-standard, this is a discussion of a popular signature itoa(int, char*, int).
Second parameter represents a buffer into which a null-terminated string representing the value is copied. It must provide enough space for the entire string: in your case, that is "123", which takes four characters. Your code passes a[] as the buffer, but the size of a[] is insufficient to accommodate the entire "123" string. Hence, the call causes undefined behavior.
You need to make a large enough to fit the destination string. Passing a buffer of size 12 is sufficient to accommodate the longest decimal number that can be produced by itoa on a 32-bit system (i.e. -2147483648). Replace char a[0] with char a[12] in the declaration.
What is its purpose here?
A zero-length array is an array with no elements in it.
You can't [legally] print or modify its contents, because it doesn't have any.
There are arcane reasons to want to use one, but speaking generally it has no purpose for you. It's not even allowed by the standard (although compilers tend to support it for those arcane reasons).
even if a change a[0] to a[1], or any other integer, the output still make no difference
Well, if you have an array with n elements in it, and you write more than n elements' worth of data to it, that's a "buffer overrun" and has undefined behaviour. It could appear to work as you overwrite somebody else's memory, or your program could crash, or your dog could suddenly turn into a zombie and eat you alive. Best avoided tbh.
The following piece of code:
string a = "abc";
cout << a.capacity();
a.erase(a.begin() + 1, a.end());
cout << a.capacity();
...outputs:
33
Even if I remove some elements from the string, the capacity remains the same. So my questions are:
Is some memory being held up because of capacity? What if I have not explicitly reserve()'d?
If I use reserve() and don't end up using the entire capacity, am I wasting memory?
Will this extra memory (which I am not using) be allocated to something else if required?
EDIT:
Suppose i have
string a= "something";
a = "ab";
Now I know that a won't ever have more than two characters. So is it wise to call reserve(2) so that memory is not wasted?
I'll answer your questions first:
The memory belongs to the string, but isn't used entirely. If you don't reserve, you can't control the capacity. You just know it is sufficiently large.
Correct.
As said in 1): no. It belongs to the string. Nothing else can use this memory. The string itself could use it for additional characters though.
For further details I'd recommend the documentation of string::reserve.
One final remark: If you don't ever reserve, everything will work fine - it might be unnecessarily slow though. That is only ever the case if you were to frequently add few characters and the string has to re-alloc alot (much like a vector). Reserving is basically intended to bypass this situation.
On the addendum: Calling reserve can help to save memory. If you call reserve(n), this ensures the string has an internal capacity for at least n characters. Note that reserve is not required to set the capacity to exactly n nor to reduce the capacity at all for small n (cf. reserve documentation).
Back to your example: If you call reserve it can never do any harm. It's the best you can do in general. (In case you have C++11 features, I'd recommend shrink_to_fit).
I tested with (older) versions of gcc / clang in which cases the capacity of a got changed to exactly 2. Since I'm not 100% sure what the added question referes to, here is what I ran:
auto a = string{"something"};
a = "ab";
cout << a << " " << a.capacity() << endl;
a.reserve(2);
cout << a << " " << a.capacity() << endl;
Which produces:
ab 9
ab 2
1) Is some memory being held up because of capacity? What if i have not
explicitly reserve()'d?
Even if you did not call reserve, the std::string object can still hold up some memory1 for (even a default constructed) std::string. And this is true with std::string implementations that uses Short String Optimization
2)If i use std::reserve() and dont end up using the entire capcity
then am i wasting memory?
It depends on what you mean by wasting memory; std::string dynamically resizes its buffer to accommodate changes in the size of the string. Well, in the case of Short String Optimized std::string implementations, there is nothing you can do about it. The memory is in the string object itself.
3)Will this extra memory which i am not using be allocated to
something else, if required?
No. A std::string object manages the memory it allocated, and it may or may not give it up2 wholly or partly, until its destroyed. See David Schwartz's comment
EDIT: Suppose i have
string a= "something";
Now i edit the string and know that a won't have more than two
characters.So is it wise to call a.reserve(2) so that memory is not
wasted?
If you modified a in a way that changes a.size(), such as calling resize method or assigning it to a new string of length 2, then the proceeding reserve call can2 be beneficial.
Note that, calling reserve would not reduce the string's contents. std::string::reserve is not permitted to truncate the string. It is only permitted to work on unused memory. If you call std::string::reserve(new_capacity_intended) with new_capacity_intended less than the size() of the string, the best that could possibly happen is the same effect of std::string::shrink_to_fit.
To reduce the string's memory (if the implementation does a binding shrink_to_fit request) and shrink it to the first two characters:
string a= "something";
//resize it first
a.resize(2); //or by some assignment such as a = "so";
//then
a.reserve(2); // or better still a.shrink_to_fit();
1: by memory, I assume Virtual Memory
2: std::string::reserve or std::string::shrink_to_fit may or may not give up the string's unused memory.
I have a code
char s[5];
cin >> s;
cout << strlen(s);
cout << endl;
cout << s;
It works even if I input more than 5 chars, for example "qwertyui". Does it mean that I am using not allocated memory?
strlen(s)
is something, but has nothing to do with 5. strlen applies to C strings, which are char arrays, but their length is defined as the numbers of characters until the first zero byte happens.
Now, cin in your second line cannot know how long your char[] is, so it just accepts as much input as there is. You must never use char buffers for input you don't know is well-formed. What you're seeing is a buffer overflow in action. Writing over memory that doesn't belong to any variable you allocated results in undefined behaviour, so your program might just work, crash with e.g. a segfault (accessing memory that the OS never gave you), or overwriting existing part's of your processes' memory, or … just do anything, because it's really undefined.
So, you're writing C++, not C. just
string s;
cin >> s;
cout << s.length()
<< endl
<< s;
to avoid dealing with the (very dangerous) C strings.
You're right, it might still echo correctly if you write more than 5 characters. You're simply writing off the end of the buffer, and just blasting the memory that's next to the memory allocated for char s[5]. This is bad for many reasons, including security vulnerabilities. See here for details.
If you can't use string (for whatever reason), use fgets. See here for the documentation on fgets and how it is used. NEVER USE gets. It's almost equivalent to what you've done above, see here for why gets is so dangerous.
This question already has answers here:
No out of bounds error
(7 answers)
Closed 8 years ago.
I have the next code:
char arr[6] = "Hello";
strcpy(arr, "Hello mellow");
cout << strlen(arr) << ", " << arr << endl; // 12, Hello mellow
char arr1[] = "Hello";
strcpy(arr1, "Hello mellow");
cout << strlen(arr1) << ", " << arr1 << endl; // 12, Hello mellow
So, why does that work? Why doesn't it get limited somehow? Whatever I put instead of "Hello mellow", it works and prints it out.
It works because strcpy doesn't check that the destination array is at least as large as the source one. Your code invokes undefined behavior as you call strcpy with invalid arguments, and because the behavior is undefined, anything can happen; In your case, the memory is silently overwritten. Your program could crash as well.
In general, C and C++ don't check for boundaries (unlike other higher-level languages: Java, PHP, Python, Javascript, etc).
This means that if you try to strcopy, say, a 13-bytes string such as "Hello mellow" to a character array, it won't check whether or not the given array has been instantiated with enough memory to contain the string. It will just copy the given string, character by character, to the given memory pointer.
What happens here, is that you write at some places in memory you are not supposed to access; once in a while, this program might just crash, with no other indication than: segmentation fault.
If you happen to try this...
char arr1[8];
char arr2[8];
strcpy(arr1,"Hello mellow");
printf("%s\n", arr1);
printf("%s\n", arr2);
...it is very likely (but not 100% sure, see comments) you would get the following output:
Hello mellow
llow
Why? Because the second char[] would have been overwritten by the data you tried to put in the first one, without it having enough reserved space for it.
See: http://en.wikipedia.org/wiki/Stack_buffer_overflow
Native arrays in C/C++ are very low-level abstractions that are treated as pointers to memory locations in many use cases. So, when passing arr to strcpy, all strcpy knows is the address of arr[0]. As a result, there is no possibility of bounds checking. This is a very good thing for performance reasons. It is up to the programmer to ensure that he/she uses these low-level constructs safely, for instance by using strncpy and giving an appropriate bound, or using std::vector and checking for bounds explicitly or using std::vector::at to check bounds when accessing a location.
I think that's because there's no check runtime nor compile time and if you're Lucky, you won't get a segmentation fault;)
Can some one tell me what's wrong with this code???
char sms[] = "gr8";
strcat (sms, " & :)");
sms is an array of size 4 1. And you're appending more char literals, which is going outside of the array, as the array can accommodate at max 4 chars which is already occupied by g, r, 8, \0.
1. By the way, why exactly 4? Answer : Because that there is a null character at the end!
If you mention the size of array as shown below, then your code is valid and well-defined.
char sms[10] = "gr8"; //ensure that size of the array is 10
//so it can be appended few chars later.
strcat (sms, " & :)");
But then C++ provides you better solution: use std::string as:
#include <string> //must
std::string sms = "gr8";
sms += " & :)"; //string concatenation - easy and cute!
Yes, there is no room for the extra characters. sms[] only allocates enough space to store the string that it is initialized with.
Using C++, a much better solution is:
std::string sms = "gr8";
sms += " & :)";
You're copying data into unallocated memory.
When you do this: char sms[] = "gr8"; you create a char array with 4 characters, "gr8" plus the 0 character at the end of the string.
Then you try to copy extra characters to the array with the strcat call, beyond the end of the array. This leads to undefined behaviour, which means something unpredictable will happen (the program might crash, or you might see weird output).
To fix this, make sure that the array that you are copying the characters to is large enough to contain all the characters, and don't forget the 0 character at the end.
In C, arrays don't automatically grow.
sms has a specific length (4, in this case - three letters and the terminating NULL). When you call strcat, you are trying to append characters to that array past its length.
This is undefined behavior, and will break your program.
If instead you had allocated an array with a large enough size to contain both strings, you would be okay:
char sms[9] = "gr8";
strcat (sms, " & :)");
C++ has the (basically) the same restrictions on arrays that C does. However, it provides higher level facilities that make it so you don't have to deal with arrays a lot of the time, such as std::string:
#include <string>
// ...
std::string sms = "gr8";
sms += " & :)";
The reason this is nicer is that you don't have to know ahead of time exactly how long your string will be. C++ will grow the underlying storage in memory for you.
Buffer overflow for character array followed by crash somewhere!
Your sms buffer is only 4 characters long. strcat will copy 5 more characters over the end of it and corrupt the stack.