I'm reading a book where the following code appears.
TTextInBuffer::TTextInBuffer(const char *pInputFileName, TAbortCode ac)
: pFileName(new char[strlen(pInputFileName) + 1])
pFileName is declared as a const char, so I'm assuming that the second line creates a new char in pFileName. I would just like to know the specifics of what is happening. Thanks.
When this constructor is called, the initializer list here is executed:
: pFileName(new char[strlen(pInputFileName) + 1])
The strlen() call finds the length of the pInputFileName string based on its contents. It basically walks it as a char array until it finds a NULL and then returns the result. This is being done in order to compute the space needed for the new string within pFileName.
The + 1 is there to make sure there's room for the extra NULL termination character at the end.
Finally, whatever number pops out of that expression is fed into a memory allocation call using the keyword new. This gets memory dynamically allocated on the heap where the string data will end up. The new call returns the address of where that memory has been allocated, and that is passed to the pFileName pointer variable so that it will point to it.
So, to summarize:
The length of pInputFileName is computed
The computed length is increased by 1 to cater for NULL in the copy
new is called to request space for the copy
The address returned by new is assigned to pFileName
The one thing that's missing from your code is the actual copy over of the contents of the input string to the destination, but perhaps that happens within the constructor body (between the { and } characters).
Second line allocates memory area (array of chars) by calling operator new[].
Argument of new is size of array to allocate. So, in this snippet the length is set to length of string pInputFileName + 1. This + 1 serves to fit null character that is used in C and C++ to determine where strings ends.
Related
I am recreating the string class using char arrays. My problem is, when I allocate memory for a larger array, it generates an array that is completely the wrong size.
For example:
int allocated = 4;
char * reservedString = new char[allocated];
cout << strlen(reservedString);
Instead of creating a character array of size 4, reservedString points to a character array with 14 spots containing random characters.
This is what the debug shows me. Reserved string is now the wrong size with a bunch of random characters in it. When I try to use strcpy or strcpy_s it is writing memory out of bounds because the new array sizes are wrong.
How can I create a char array with an unknown length, which is provided by a variable, that is right size.
I can not use the std::string class or std::vector.
When you are creating an object with the new operator, your data remains not initialized. The code you provide is basically an array of bytes.
The documentation about strlen says:
computes the length of the string str up to, but not including the terminating null character.
There is no null terminator here.
You should do:
int allocated = 4;
char * reservedString = new char[allocated]();
This will initialize your array and set all the elements to \0
strlen expects a null-terminated string, which means a string that ends in a null character (\0). You're passing to it a pointer pointing to newly allocated memory, which contains uninitialized values and reading it causes undefined behavior. So when strlen searches for a null character in order to determine the length of the string, stuff is going to go wrong.
You cannot determine the size of an array given only a pointer to it unless you know it's going to be terminated by a null character or something similar. So either properly initialize the array with a null-terminated string or keep track of the length yourself.
I have a custom String class that I've built. I'm trying to build a custom insert function that inserts a string into a specified position.
For Example:
String str("test");
str.insert(2, "animal");
would return:
"tesanimalt"
What i have so far:
String& String::insert(int pos, const String& str) {
char newString[100];
strncpy(newString, chars, pos);
newString[pos] = '\0';
strcat(newString, str.chars);
strcat(newString, chars + pos);
return *this;
}
There are a lot of problems with the code, one of which is that your String doesn’t seem to contain any actual storage. You instead allocate a local array as a temporary variable, then let it be discarded.
It’s not possible to fix this without a MCVE, as we cannot see how String is supposed to work. There seems to be some kind of member called chars, and you probably want to copy to that. However, if it contains a buffer allocated with malloc() or new[], you might, if m is the length of the enclosing string, and n the length of the intercalated string, and you insert at position i:
Reallocate the buffer of the destination string to its new size (The sum of the sizes of the two strings without their terminating nulls, plus one byte for a terminating null). Alternatively, allocate a new buffer and copy the first i elements of the enclosing string.
Shift elements i through n of the enclosing string n elements to the right of the resized buffer.
Copy the string to insert to positions i through i+n-1.
Write a terminating null to position m+n.
Since you appear to want to modify the enclosing string, if you created a new buffer, deallocate the old one. If you reallocated the buffer, set chars to the possibly-changed value.
This is my code
char *t = type1[j];
int ln = strlen(t);
char *s = new char[ln];
cout<<"ln "<<ln<<" s "<<strlen(s)<<endl;
When I run it:
Why are the lengths different?
When you dynamically allocate an array with new[], you get a pointer to an uninitialized block of memory. You can't call strlen on it, as that function expects a pointer to a character array that contains a null-terminated string. It works by reading each byte in the array until it finds a null byte and returning the count of how many bytes it read before it found a null byte. And since the array is uninitialized, calling strlen does make sense. In fact, it invokes undefined behavior.
There's no way to look at a dynamically allocated buffer and find out how big that buffer is. You need to keep track of the size of the buffer separately. Since you used new char[ln] to create the buffer, you know that you have a buffer large enough to hold ln variables of type char.
As we know, the strcat function concatinates one c-string onto another to make one big c-string containing two others.
My question is how to make a strcat function that works with two dynamically allocated arrays.
The desired strcat function should be able to work for any sized myStr1 and myStr2
//dynamic c-string array 1
char* myStr1 = new char [26];
strcpy(myStr1, "The dog on the farm goes ");
//dynamic c-string array 2
char* myStr2 = new char [6];
strcpy(myStr2, "bark.");
//desired function
strcat(myStr1,myStr2);
cout<<myStr1; //would output 'The dog on the farm goes bark.'
This is as far as I was able to get on my own:
//*& indicates that the dynamic c-string str1 is passed by reference
void strcat(char*& str1, char* str2)
{
int size1 = strlen(str1);
int size2 = strlen(str2);
//unknown code
//str1 = new char [size1+size2]; //Would wipe out str1's original contents
}
Thanks!
You need first to understand better how pointers work. Your code for example:
char* myStr1 = new char [25];
myStr1 = "The dog on the farm goes ";
first allocates 25 characters, then ignores the pointer to that allocated area (the technical term is "leaks it") and sets myStr1 to point to a string literal.
That code should have used strcpy instead to copy from the string literal into the allocated area. Except that the string is 25 characters so you will need to allocate space for at least 26 as one is needed for the ASCII NUL terminator (0x00).
Correct code for that part should have been:
char* myStr1 = new char [26]; // One more than the actual string length
strcpy(myStr1, "The dog on the farm goes ");
To do the concatenation of C strings the algorithm could be:
measure the lengths n1 and n2 of the two strings (with strlen)
allocate n1+n2+1 charaters for the destination buffer (+1 is needed for the C string terminator)
strcpy the first string at the start of the buffer
strcat the second string to the buffer (*)
delete[] the memory for the original string buffers if they are not needed (if this is the right thing to do or not depends on who is the "owner" of the strings... this part is tricky as the C string interface doesn't specify that).
(*) This is not the most efficient way. strcat will go through all the characters of the string to find where it ends, but you already know that the first string length is n1 and the concatenation could be done instead with strcpy too by choosing the correct start as buffer+n1. Even better instead of strcpy you could use memcpy everywhere if you know the count as strcpy will have to check each character for being the NUL terminator. Before getting into this kind of optimization however you should understand clearly how things work... only once the string concatenation code is correct and for you totally obvious you are authorized to even start thinking about optimization.
PS: Once you get all this correct and working and efficient you will appreciate how much of a simplification is to use std::string objects instead, where all this convoluted code becomes just s1+s2.
You allocate memory and make your pointers point to that memory. Then you overwrite the pointers, making them point somewhere else. The assignment of e.g. myStr1 causes the variable to point to the string literal instead of the memory you allocated. You need to copy the strings into the memory you have allocated.
Of course, that copying will lead to another problem, as you seem to forget that C-strings need an extra character for the terminator. So a C-string with 5 characters needs space for six characters.
As for your concatenation function, you need to do copying here too. Allocate enough space for both strings plus a single terminator character. Then copy the first string into the beginning of the new memory, and copy the second string into the end.
Also you need a temporary pointer variable for the memory you allocate, as you otherwise "would wipe out str1's original contents" (not strictly true, you just make str1 point somewhere else, losing the original pointer).
I saw that a potential job interview for a C++ programmer position could ask you this question:
Explain what the following C++ code segment does.
char *aryA = "Data Structures";
char *aryB, *aryC;
aryB = new char[20];
aryC = aryB;
while (*aryB++ = *aryA++);
cout << aryC << endl;
I've been looking at it for a while, but I don't think I am understanding the while loop. So to me it would seem that the while loop is saying to cout aryC so long as the two pointers are equal. But, both pointers are being incremented by one, which I take to mean which char value in the array is being looked at. But if they are the same and both are being increased by one, wouldn't they always be equal? And there's another thing. The values for the array of chars aryB is not defined; we only know there are 20 values in the array. So how can you compare aryA and aryC in the first place?
If anyone can take the time to explain this code segment to me, I would really appreciate it. I am having issues running visual studio, so I can't just run it myself, but even if I could I think I would still benefit from someone teaching me.
It's quite easy, *aryB++ = *aryA++ can be seen as
*aryB = *aryA;
aryB++;
aryA++;
which just assign the character pointed by aryA to aryBand then increment both (to move on next character. The while is executed until the NUL terminating character is found, which is caught by the fact that the = operator (which is not ==) returns the assigned value.
Saving aryB to aryC before the while is just a way to keep the pointer to the beginning of the copied string, since you lose it by then incrementing aryB.
aryB = new char[20]; sets aryB to a new character array.
aryC = arB; sets aryC as a reference to aryB.
while (*aryB++ = *aryA++); This one is more complicated. It will set the current value at aryB to the current value at aryA while the current value at aryA is not false (0), then move where both pointers forward one (remember that all c strings end with \0, which evaluates to 0). This also changes the value of aryC, but not what it points to. In the end, aryA is copied into aryC.
aryB is a pointer that points to an address in memory. By placing * in front of pointer (*aryB), you access the actual data at that memory address. ++ increments the pointer by 1, which makes it to point to the next memory address. Inside while() you do not compare (the operator is not ==), the assignment operator is used (=). This means that you will be copying data from memory aryA to aryB. Also aryC = aryB means that aryC points to the same memory address as aryB (points to the first element of the array). In other words by modifying data at aryB, you also modify it for aryC.
char *aryA = "Data Structures";
char *aryB, *aryC;
aryB = new char[20];
aryC = aryB;
We can visualise the memory use and pointer contents like this:
[(char*)aryA]--------------------------v
["Data Structures\0"]
[(char*)aryB]-------------v
[ 20 uninitialised chars ]
^
|
[(char*)argC]-------------/
Then:
while (*aryB++ = *aryA++);
Is processed like this:
*aryB = *aryA - assigns *aryB (the first uninitialised char),
with *aryA (the 'D' in Data)
aryB++, aryA++ - post-increments add one to each pointer
(i.e. move to the 'a' in Data, the 2nd uninitialised value
while (...) - evaluates the assignment, exiting if false
the assignment evaluates to the copied character
only character code 0 / '\0' / NUL converts to false; others to true
We now have:
[(char*)aryA]---------------------------v
["Data Structures\0"]
[(char*)aryB]--------------v
[D ]
^
|
[(char*)argC]-------------/
Repeat. This keeps copying character by character until the data from *aryA is the NUL character, which gets copied but then the assignment evaluates to false and the loop terminates.
While that was all happening, aryC stayed pointing at the start of the new-ed buffer, so it can now be used to stream out the content:
cout << aryC << endl;