I'm using a dynamic C-style string to read in data from a file, but for some reason when I dynamically allocate the C-style string using the given length, it comes out with four extra characters that can be seen using strlen(). The junk in these empty spaces is added on to the end of the read-in string and is displayed on cout. What on earth could be causing this, and how can I fix it?
The C-style string is declared in the beginning of the code, and is used one time before this. The time it is used before this it is also too large, but in that case it does not add extra information to the end. After use, it is deleted and not used again until this point. I'm pretty confused as I have not had this happen or had a problem with it before.
// Length read as 14, which is correct
iFile.read(reinterpret_cast<char *>(&length), sizeof(int));
tempCstring = new char[length]; // Length still 14
cout << strlen(tempCstring); // Console output: 18
// In tempCstring: Powerful Blockýýýý
iFile.read(reinterpret_cast<char *>(tempCstring), length);
// Custom String class takes in value Powerful Blockýýýý and is
// initialized to that
tempString = String(tempCstring);
// Temp character value takes in messed up string
temp.setSpecial(tempString);
delete[] tempCstring; // Temp cString is deleted for next use
When written to file:
// Length set to the length of the cString, m_special
length = strlen(chars[i].getSpecial().getStr());
// Length written to file. (Should I add 1 for null terminator?)
cFile.write(reinterpret_cast<char *>(&length), sizeof(int));
// String written to file
cFile.write(reinterpret_cast<char *>(chars[i].getSpecial().getStr()), length);
Whenever you see junk at the end of a string, the problem is almost always the lack of a terminator. Every C-style string ends in a byte whose value is zero, spelled '\0'. If you did not place one yourself, the standard library keeps reading bytes in memory until it sees a random '\0' that it sees in memory. In other words, the array is read beyond its bounds.
Use memset(tempCString,0,length) in order to zero out the memory following your allocation. However, this is not the soundest solution, as it is covering the real problem under the rug. Show us the context in which this code is used. Then I will be able to say where in your algorithm you will need to insert the null terminator: tempCString[i] = 0, or something like that. Nonetheless, from what you have posted, I can tell that you need to allocate one more character to make room for the terminator.
Also, since you are using C++, why not use std::string? It avoids these kinds of problems.
Related
char* a = new char[50];
This is for a school assignment. I am not allowed to use strings or vectors or anything else. Just char array.
Lets say I want to do cin >> a; and I don't know the size of the input. How should I put it in char array? The above only works for a small size of input.
Should I do this? char* a = new char[some_large_number]; or is there a better way?
I can only use (dynamic) char arrays.
EDIT: The input can be any string like
abcd or even somelongrandomsentecewithoutspsomelongrandomsentecewithoutspacessomelongrandomsentecewithoutspaces
This is a little tricky with character arrays: what you need to do is tell cin that you do not want to receive more than a certain number of characters (49 for a 50-character buffer, because you need space for null terminator). When the read is finished, check the length of the string. If it is 49, allocate a new, larger, string, copy the old string into it, and continue reading. If it is less than 49, the end of string has been reached.
You can use istream::get to read the data into your buffer:
cin.get(a, 50); // You can specify an optional delimiter as a third parameter
Note that you pass 50 for the length, and get will subtract 1 automatically, because it knows about the space needed for null terminator.
I have a problem and I dont know how to solve it.
The issue is:
char * ary = new Char[];
ifstream fle;
fle.open(1.txt, ios_base::binary);
fle.seekg(fle.end);
long count = fle.tellg();
fle.seek(fle.beg);
here is the problem:
File 1.txt contains: Hello world!.
when I execute:
ary = new char(count);
fle.read(ary, count);
the ary filled like this: Hello world! #T#^#$#FF(garbage)
The file is ookay nothing inside it only what is above.
Platform: Win 7, VS 2012
Any idea how to solve this issue. (Solved)
(Problem 2)
Now I am facing another problem, the fle.read sometimes read more than the size i gave. For Example if i passed like fle.read(buffer, 1000) it ends in some cases (strlen(buffer) = 1500. How can i solve this?
Regards,
char[]-strings in C are usually null-terminated. They are one byte longer than necessary, and the last byte is set to 0x00. That's necessary because C has no way to tell the length of an array.
When you read binary data from a file, no terminating null-character is read into the string. That means a function like printf which operates on char-arrays of unknown length will output the array and any data which happens to come after it in memory until it encounters a null-character.
Solution: allocate the char[]-buffer one byte longer than the length of the data and set the last byte to 0 manually.
Better solution: Don't use C-style char-arrays. Do it the object-oriented way and use the class std::string to represent strings.
I think your problem is not that your array contains garbage, but that you forgot to put the null-terminator character at the end and your print statement doesn't know when to stop.
Also, you wrote new char(count) instead of new char[count]. In the first case, you only instantiate one char with value count while in the second case you create a buffer of count characters.
Try this:
ary = new char[count+1];
fle.read(ary, count);
ary[count] = '\0';
Most of the other answers miss a very important point:
When you do ary = new char(count); you allocate A SINGLE CHARACTER initialized with a symbol with ASCII code count.
You should write this: ary = new char[count + 1];
Well, the most obvious problem is that you are allocating using
new char(count), which allocates a single char, initialized
with count. What you were probably trying to do would be new
char[count]. What you really need is:
std::vector<char> arr( count );
fle.read( &arr[0], count );
Or maybe count + 1 in the allocation, if you want a trailing
'\0' in the buffer.
EDIT:
Since you're still having problems: fle.read will never read
more than requested. What does fle.gcount() return after the
read?
If you do:
std::vector<char> arr( count );
fle.read( &arr[0], count );
arr.resize( fle.gcount() );
you should have a vector with exactly the number of char that
you have read. If you want them as a string, you can construct
one from arr.begin(), arr.end(), or even use std::string
instead of std::vector<char> to begin with.
If you need a '\0' terminated string (for interface with
legacy software), then just create your vector with a size of
count + 1, instead of count, and &arr[0] will be your
'\0' string.
Do not try to use new char[count] here. It's very difficult
to do so correctly. (For example, it will require a try block
and a catch.)
We have to guess a little here, but most likely this comes down to an issue with your debugging. The buffer is filled correctly, but you inspect its contents incorrectly.
Now, ary is declared as char* and I suspect that when you attempt to inspect the contents of ary you use some printing method that expects a null-terminated array. But you did not null-terminate the array. And so you have a buffer overrun.
If you had only printed count characters, then you would not have overrun. Nor would you if you had null-terminated the array, not forgetting to allocate an extra character for the null terminator.
Instead of using raw arrays and new, it would make much more sense to read the buffer into std::string. You should be trying to avoid null-terminated strings as much as possible. You use those when performing interop with non-C++ libraries.
You're reading count characters for a file, you have to allocate one extra character to provide for the string terminator (\0).
ary = new char[count + 1];
ary[count] = '\0';
Try this
ary = new char[count + 1];
fle.read(ary,count);
ary[count] = '\0';
The terminating null character was missing - its not in the file, you have to add it afterwards
When I run the example code, the wordLength is 7 (hence the output 7). But my char array gets some really weird characters in the end of it.
wordLength = word.length();
cout << wordLength;
char * wordchar = new char[wordLength]; //new char[7]; ??
for (int i = 0; i < word.length(); i++) //0-6 = 7
{
wordchar[i] = 'a';
}
cout << wordchar;
The output: 7 aaaaaaa²²²²¦¦¦¦¦ÂD╩2¦♀
Desired output is: aaaaaaa... What is the garbage behind it?? And how did it end up there?
You should add \0 at the end of wordchar.
char * wordchar = new char[wordLength +1];
//add chars as you have done
wordchar[wordLength] = `\0`
The reason is that C-strings are null terminated.
C strings are terminated with a '\0' character that marks their end (in contrast, C++ std::string just stores the length separately).
In copying the characters to wordchar you didn't terminate the string, thus, when operator<< outputs wordchar, it goes on until it finds the first \0 character that happens to be after the memory location pointed to by wordchar, and in the process it prints all the garbage values that happen to be in memory in between.
To fix the problem, you should:
make the allocated string 1 char longer;
add the \0 character at the end.
Still, in C++ you'll normally just want to use std::string.
Use: -
char * wordchar = new char[wordLength+1]; // 1 extra for null character
before for loop and
wordchar[i] ='\0'
after for loop , C strings are null terminated.
Without this it keeps on printing, till it finds the first null character,printing all the garbage values.
You avoid the trailing zero, that's the cause.
In C and C++ the way the whole eco-system treats string length is that it assumes a trailing zero ('\0' or simply 0 numerically). This is different then for example pascal strings, where the memory representation starts with the number which tells how many of the next characters comprise the particular string.
So if you have a certain string content what you want to store, you have to allocate one additional byte for the trailing zero. If you manipulate memory content, you'll always have to keep in mind the trailing zero and preserve it. Otherwise strstr and other string manipulation functions can mutate memory content when running off the track and keep on working on the following memory section. Without trailing zero strlen will also give a false result, it also counts until it encounters the first zero.
You are not the only one making this mistake, it often gets important roles in security vulnerabilities and their exploits. The exploit takes advantage of the side effect that function go off trail and manipulate other things then what was originally intended. This is a very important and dangerous part of C.
In C++ (as you tagged your question) you better use STL's std::string, and STL methods instead of C style manipulations.
Hi my problem is kind of difficult to explain so I'll just post my code section here and explain the problem with an example.
This code here has a big and a small array where the big array gets split up in small parts, is stored in the small array and the small array is outputting its content on the screen. Afterwards I free the allocated memory of the small array and initialize it again with the next part of the big array:
//this code is in a loop that runs until all of the big array has been copied
char* splitArray = new char[50];
strncpy(splitArray, bigArray+startPoint, 50); //startPoint is calculated with every loop run, it marks the next point in the array for copying
//output of splitArray on the screen here
delete splitArray;
//repeat loop here
now my problem is that the outputted string has everytime some random symbols at the end. for example "some_characters_here...last_char_hereRANDOM_CHARS_HERE".
after looking deeper into it I found out that splitArray actually doesnt have a size of 50 but of 64 with the null terminator at 64.
so when I copy from bigArray into splitArray then there are still the 14 random characters left after the real string and of course I dont want to output them.
A simple solution would be to manually set the null terminator in the splitArray at [50] but then the program fails to delete the array again.
Can anybody help me find a solution for this? Preferably with some example code, thanks.
How does the program "fail to delete the array again" if you just set splitArray[49] = 0? Don't forget, an array of length 50 is indexed from 0 through 49. splitArray[50] = 0 is writing to memory outside that allocated for splitArray, with all the consequences that entails.
When you allocate memory for the splitArray the memory is not filled with NULL characters, you need to explictly do it. Because of this your string is not properly NULL terminated. To do this you can do char* splitArray = new char[51](); to initialize with NULL character at the time of allocation itself (note that I am allocating 51 chars to have the extra NULL character at the end). . Also note that you need to do delete[] splitArray; and not delete splitArray;.
The function strncpy has the disadvantage that it doesn't terminate the destination string, if the source string contains more than 50 chars. Seems like it does in your case!
If this really is C++, you can do it with std::string splitArray(bigArray+startPoint, 50).
I see a couple of problems with your code:
If you allocate by using new [], you need to free with delete [] (not delete)
Why are you using freestore anyway? From what I can see you might as well use local array.
If you want to store 50 characters in an array, you need 51 for the terminating null character.
You wanted some code:
while(/* condition */)
{
// your logic
char splitArray[51];
strncpy(splitArray, bigArray+startPoint, 50);
splitArray[50] = '\0';
// do stuff with splitArray
// no delete
}
Just doing this will be sufficient:
char* splitArray = new char[50 + 1];
strncpy(splitArray, bigArray+startPoint, 50);
splitArray[50] = '\0';
I'd really question why you're doing this anyway though. This is much cleaner:
std::string split(bigArray+startPoint, 50);
it still does the copy, but handles (de)allocation and termination for you. You can get the underlying character pointer like so:
char const *s = split.c_str();
it'll be correctly nul-terminated, and have the same lifetime as the string object (ie, you don't need to free or delete it).
NB. I haven't changed your original code, but losing the magic integer literals would also be a good idea.
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.