Here is the code:
int main()
{
char str[] = {'a','b','c',' ','d','e',' ',' ','f',' ',' ',' ','g','h','i',' ',' ',' ',' ','j','k'};
cout << "Len = " << strlen(str) << endl;
char* cstr = new char[strlen(str)];
strcpy(cstr, str);
cstr[5] = '\0';
cout << "Len= " << strlen(cstr) << endl;
return 0;
}
//---------------
Result console:
Len = 21
Len= 5
As you see the Len of cstr changed. It mean that remain memory area of cstr is free. Is it right?
No. All strlen() does is look for the first null character ('\0') in the string. It doesn't free memory. It doesn't even care if the memory it examines is properly allocated. It will happily walk past the end of allocated memory in search of a null character if none is found starting from the pointer you give it.
The code is broken from the starts. str is not a nul-terminated string, and as such can't be used with functions expecting those strings, such as strlen or strcpy.
As you see the Len of cstr changed. It mean that remain memory area of
cstr is free. Is it right?
No. It's not. You allocated memory for array on heap and then inserted \0 at place between array. Because of this, strlen is reporting length of array equals to 5 (because it computes length of char array by looking \0 character) but memory past that index still exists on heap. To free memory, You need to call delete [] cstr.
No. new just allocates a chunk of memory of the size you specified. The only way to release it is to call delete on it.
strlen is a function that parses memory from a starting address and counts the number of non NUL bytes, such a thing is called a C-string.
Putting a NUL byte somewhere in memory is no different from putting any other value for the memory management.
As you see the Len of cstr changed. It mean that remain memory area of cstr is free. Is it right?
No. strlen only returns the length of the string stored within the array, not the size of the array itself. The length of the string may be anywhere from 0 to strlen(str) - 1, but the size of cstr is always going to be strlen(str).
The size of the array does not change just because you stored a smaller string to it, any more than a glass gets smaller if you only fill it half way. The only way to release the memory pointed to by cstr is to use the delete operator.
No, it does not mean that remain memory area of str is free.
strlen(cstr) calculates the length of the string upto a point when a NUL \0 character is encountered.
In the beginning you allocated a char array of length 22 char. Replacing a char in between with a NUL \0 is only going to make strlen believe that the string is upto 5 char long. It will not free the other 17 char that were allocated for the local char array after that replaced char.
The memory for char array str will get get unallocated once the function main() exits (since it is a local array).
Related
Can anyone explain to me why the following code causing segmentation fault? buff should be long enough to hold 128 characters.
int main () {
char buff[16384];
char buff2[128];
sprintf(buff2, "MinPer(PatternName_Equal27_xxxxxxx_MasterPatSetup.PatternName_Equal27_xxxxxxx__default_WFT___WFTRef.ActualT0Period.UserPeriod_2_1)" );
strcat(buff, buff2);
std::cout << buff2 << endl;
std::cout << buff << endl;
return 0;
}
You have two major problems:
Your sprintf is shoving 131 bytes (130 characters plus a NUL) into a 128 byte buffer, meaning three unrelated stack bytes are getting overwritten with garbage. You need a larger buffer, or a smaller initialization string.
You call strcat to append said 131 characters to a buffer with undefined contents (no NUL to indicate where the string being concatenated to ends). This is trivially fixable, by either zero-initializing all of buff (char buff[16384] = {0};) or by inserting the NUL in the first byte (which is all you really need) adding buff[0] = '\0'; just before you strcat to it. Equivalently, you could replace strcat (which assumes a string to concatenate new data to exists in the destination) with strcpy (which ignores the existing contents of the destination) to avoid the problem.
Basically, your code is full of undefined behavior and buffer overruns. Given you're using C++, can I recommend just using std::string to avoid the hassle of C strings?
buff is uninitialized. It needs to contain a null terminated string so that strcat knows where to begin the concatenation. One way to do this is with strcpy:
strcpy(buff, ""); // initialize with empty null terminated string
strcat(buff, buff2); // add to it
strcat needs 'dest' to be a string ending with '\0'. So buff should be initialized manually.
Why does this code produce runtime issues:
char stuff[100];
strcat(stuff,"hi ");
strcat(stuff,"there");
but this doesn't?
char stuff[100];
strcpy(stuff,"hi ");
strcat(stuff,"there");
strcat will look for the null-terminator, interpret that as the end of the string, and append the new text there, overwriting the null-terminator in the process, and writing a new null-terminator at the end of the concatenation.
char stuff[100]; // 'stuff' is uninitialized
Where is the null terminator? stuff is uninitialized, so it might start with NUL, or it might not have NUL anywhere within it.
In C++, you can do this:
char stuff[100] = {}; // 'stuff' is initialized to all zeroes
Now you can do strcat, because the first character of 'stuff' is the null-terminator, so it will append to the right place.
In C, you still need to initialize 'stuff', which can be done a couple of ways:
char stuff[100]; // not initialized
stuff[0] = '\0'; // first character is now the null terminator,
// so 'stuff' is effectively ""
strcpy(stuff, "hi "); // this initializes 'stuff' if it's not already.
In the first case, stuff contains garbage. strcat requires both the destination and the source to contain proper null-terminated strings.
strcat(stuff, "hi ");
will scan stuff for a terminating '\0' character, where it will start copying "hi ". If it doesn't find it, it will run off the end of the array, and arbitrarily bad things can happen (i.e., the behavior is undefined).
One way to avoid the problem is like this:
char stuff[100];
stuff[0] = '\0'; /* ensures stuff contains a valid string */
strcat(stuff, "hi ");
strcat(stuff, "there");
Or you can initialize stuff to an empty string:
char stuff[100] = "";
which will fill all 100 bytes of stuff with zeros (the increased clarity is probably worth any minor performance issue).
Because stuff is uninitialized before the call to strcpy. After the declaration stuff isn't an empty string, it is uninitialized data.
strcat appends data to the end of a string - that is it finds the null terminator in the string and adds characters after that. An uninitialized string isn't gauranteed to have a null terminator so strcat is likely to crash.
If there were to intialize stuff as below you could perform the strcat's:
char stuff[100] = "";
strcat(stuff,"hi ");
strcat(stuff,"there");
Strcat append a string to existing string. If the string array is empty, it is not going go find end of string ('\0') and it will cause run time error.
According to Linux man page, simple strcat is implemented this way:
char*
strncat(char *dest, const char *src, size_t n)
{
size_t dest_len = strlen(dest);
size_t i;
for (i = 0 ; i < n && src[i] != '\0' ; i++)
dest[dest_len + i] = src[i];
dest[dest_len + i] = '\0';
return dest;
}
As you can see in this implementation, strlen(dest) will not return correct string length unless dest is initialized to correct c string values. You may get lucky to have an array with the first value of zero at char stuff[100]; , but you should not rely on it.
Also, I would advise against using strcpy or strcat as they can lead to some unintended problems.
Use strncpy and strncat, as they help prevent buffer overflows.
So in c++ a normal c-style string can be initiated like this:
char cString[] = "my string";
How can I do the same thing using dynamic memory?
Why doesn't this work?
char *charPtr;
charPtr = new char("make this the value of the c string");
You can't just initialize a c-style string like that.
First of all you need a pointer, that points to the beginning of the string. Then need to allocate enough memory to hold that string, which is the number of characters + the terminating '\0'. You should include cstring header, for strlen and strcpy. At last you need to copy the string to the memory block.
char *str; //pointer to string
str = new char[strlen("The string to copy")+1]; //allocate memory
//strlen returns the number of charaters of a string exluding the '\0', so we need to add 1
//either use a string constant, or another cstyle string, or input the length manually
strcopy(str, "The string to copy");//strcpy copies the content of the string constant to str
//be sure to set the last element of the string to '\0'
str[strlen(str)] = 0; // or '\0'
//if str has 5 char it returns 4 because the last is \0
//but the array goes from 0 to 4, so 4 is the last element
And dont forget to use delete [ ] str; if you get rid of the string!
I always get a garbage value like this 'Íýýýý««««««««îþîþ' at the end when i output my array. What am I doing wrong?
void func()
{
const int size = 100;
char * buffer = new char[size];
for(int i=0; i<size; i++)
buffer[i] = ' ';
cout<<buffer;
}
However if I use a for loop to output the buffer, there is no garbage value.
Because you don't null terminate your buffer, std::cout.operator<<(char*) will try to find \0 as its terminating character.
As pointed out in comments, feel free to append that \0 to the end of your buffer :).
ScarletAmaranth is right. C style strings (an array of char) must finish with the char '\0'. That's the way functions that play with char arrays (cout in this case) know when the string finish in memory. If you forget the '\0' character at the end of the array, cout prints all the chars in the array and then goes on printing any data in memory after the array. These other data is rubbish, and that's why you see these strange characters.
If you use the string type (more C++ style) instead of char arrays, you won't have this problem because string type don't use '\0' as a string delimiter.
On the other hand, you don't see rubbish when use a loop to iterate over the 100 elements of the array just because you only print these 100 chars. I mean, you control exactly what you are printing and know when to stop, instead of leaving the cout function figure out when to stop printing.
NoobQuestion:
I heard that filling a char array can be terminated early with the null char. How is this done?
I've searched every single google result out there but still have come up empty handed.
Do you mean something like this:
char test[11] = "helloworld";
std::cout << test << std::endl;
test[2] = 0;
std::cout << test;
This outputs
helloworld
he
?
That's a convention called "null-terminated string". If you have a block of memory which you treat as a char buffer and there's a null character within that buffer then the null-terminated string is whatever is contained starting with the beginning of the buffer and up to and including the null character.
const int bufferLength = 256;
char buffer[bufferLength] = "somestring"; //10 character plus a null character put by the compiler - total 11 characters
here the compiler will place a null character after the "somestring" (it does so even if you don't ask to). So even though the buffer is of length 256 all the functions that work with null-terminated strings (like strlen()) will not read beyond the null character at position 10.
That is the "early termination" - whatever data is in the buffer beyond the null character it is ignored by any code designed to work with null-terminated strings. The last part is important - code could easily ignore the null character and then no "termination" would happen on null character.