FILE* file_;
char buffer[5];
file_ = fopen("Data.txt", "a+");
while (!feof(file_))
{
fread(buffer, sizeof(buffer), 1, file_);
cout << buffer<<" ";
BM(buffer, pat);
}
Data.txt="ABCC1ABCC2XXX"
Output:
ABCC1m
ABCC2m
XXXC2m
How can I make buffer stop before it starts generating chars from previous buffer?(bolded font part)
Wanted output:
ABCC1
ABCC2
XXX
You have two problems. Firstly you are not null-terminating buffer at all, (which is why you are getting the m output. Secondly, you are not null-terminating buffer in the right place when there is a short read.
fread will tell you how many characters it has read, and you need to put the '\0' there. Edit That previous description is not accurate. It tells you how many objects it has read, each of size arg2, and you read upto arg3 of them. You need to change the arguments to fread so that you are reading single characters, and as many of them as there room in the buffer. So:
FILE* file_;
char buffer[5+1];
file_ = fopen("Data.txt", "a+");
while (!feof(file_))
{
const size_t nchars = fread(buffer, 1, sizeof(buffer)-1, file_);
buffer[nchars] = '\0';
cout << buffer<<" ";
BM(buffer, pat);
}
Pedantic note: The second argument to fread could also be written as sizeof(buffer[0]) if buffer is of something other than char/signed char/unsigned char - but those three are defined to have a sizeof 1.
OK, I can't find a decent duplicate - maybe someone else will.
The line
fread(buffer, sizeof(buffer), 1, file_);
potentially fills your buffer completely. You need to keep the return value to know how many bytes were actually written, but assuming your file contained at least five bytes, all five bytes of your buffer array are now initialized.
However, to print buffer as a regular C string, it needs a sixth byte, containing the null terminator.
For example, the C string "12345" is actually represented as the char array {'1', '2', '3', '4', '5', 0}.
You don't have room for a terminator in your buffer, and don't write one, so you can't treat it as a simple C string.
Your options are:
add a terminator manually, as in Martin Bonner's answer
don't add a terminator, but track the size - you can use the C++17
std::string_view bufstr(buffer, nchars);
to keep the pointer and size together (and you can print this normally)
stop using the old C I/O library entirely. The C++ I/O library admittedly doesn't have a much better way to read groups of five characters, but reading whole lines, for example, is much easier to do correctly.
Related
I am new to c++ and am still figuring out file streams. I am trying to put a character array into a file that I will be viewing with a hex editor.
I have done different strings, but whenever I put in a null byte, the file ends.
ofstream stream;
char charArray[256];
for (int i = 0; i <= 255; i++)charArray[i] = i;
stream.open("C:\\testfile.myimg");
if (!stream.is_open()) exit(1);
stream << charArray << endl;
return 0;
I want to output bytes with ascending values, but if I start with the null byte, then c++ thinks the character array ends before it starts
Instead of:
stream << charArray << endl;
use:
stream.write(charArray, sizeof(charArray));
stream.write("\n", 1); // this is the newline part of std::endl
stream.flush(); // this is the flush part of std::endl
The first one assumes that you are sending a null-terminated string (because you're passing a char* - see the end of the answer why). That's why when the code encounters the very first char with value 0, which is '\0' (the null-terminator), it stops.
On the other hand, the second approach uses an unformatted output write, which will not care about the values inside charArray - it will take it (as a pointer to its first element) and write sizeof(charArray) bytes starting from that pointer to the stream. This is safe since it's guaranteed that sizeof(char) == 1, thus sizeof(charArray) will yield 256.
What you need to consider is array decaying. It will work in this case (the sizeof thing), but it will not work if you simply pass a decayed pointer to the array's first element. Read more here: what's array decaying?
I'm having a string is not null terminated error, though I'm not entirely sure why. The usage of std::string in the second part of the code is one of my attempt to fix this problem, although it still doesn't work.
My initial codes was just using the buffer and copy everything into client_id[]. The error than occurred. If the error is correct, that means I've got either client_ id OR theBuffer does not have a null terminator. I'm pretty sure client_id is fine, since I can see it in debug mode. Strange thing is buffer also has a null terminator. No idea what is wrong.
char * next_token1 = NULL;
char * theWholeMessage = &(inStream[3]);
theTarget = strtok_s(theWholeMessage, " ",&next_token1);
sendTalkPackets(next_token1, sizeof(next_token1) + 1, id_clientUse, (unsigned int)std::stoi(theTarget));
Inside sendTalkPackets is. I'm getting a string is not null terminated at the last line.
void ServerGame::sendTalkPackets(char * buffer, unsigned int buffersize, unsigned int theSender, unsigned int theReceiver)
{
std::string theMessage(buffer);
theMessage += "0";
const unsigned int packet_size = sizeof(Packet);
char packet_data[packet_size];
Packet packet;
packet.packet_type = TALK;
char client_id[MAX_MESSAGE_SIZE];
char theBuffer[MAX_MESSAGE_SIZE];
strcpy_s(theBuffer, theMessage.c_str());
//Quick hot fix for error "string not null terminated"
const char * test = theMessage.c_str();
sprintf_s(client_id, "User %s whispered: ", Usernames.find(theSender)->second.c_str());
printf("This is it %s ", buffer);
strcat_s(client_id, buffersize , theBuffer);
Methinks that problem lies in this line:
sendTalkPackets(next_token1, sizeof(next_token1) + 1, id_clientUse, (unsigned int)std::stoi(theTarget));
sizeof(next_token1)+1 will always gives 5 (on 32 bit platform) because it return size of pointer not size of char array.
One thing which could be causing this (or other problems): As
buffersize, you pass sizeof(next_token1) + 1. next_token1 is
a pointer, which will have a constant size of (typically) 4 or 8. You
almost certainly want strlen(next_token1) + 1. (Or maybe without the
+ 1; conventions for passing sizes like this generally only include
the '\0' if it is an output buffer. There are a couple of other
places where you're using sizeof, which may have similar problems.
But it would probably be better to redo the whole logic to use
std::string everywhere, rather than all of these C routines. No
worries about buffer sizes and '\0' terminators. (For protocol
buffers, I've also found std::vector<char> or std::vector<unsigned char>
quite useful. This was before the memory in std::string was
guaranteed to be contiguous, but even today, it seems to correspond more
closely to the abstraction I'm dealing with.)
You can't just do
std::string theMessage(buffer);
theMessage += "0";
This fails on two fronts:
The std::string constructor doesn't know where buffer ends, if buffer is not 0-terminated. So theMessage will potentially be garbage and include random stuff until some zero byte was found in the memory beyond the buffer.
Appending string "0" to theMessage doesn't help. What you want is to put a zero byte somewhere, not value 0x30 (which is the ascii code for displaying a zero).
The right way to approach this, is to poke a literal zero byte buffersize slots beyond the start of the buffer. You can't do that in buffer itself, because buffer may not be large enough to accomodate that extra zero byte. A possibility is:
char *newbuffer = malloc(buffersize + 1);
strncpy(newbuffer, buffer, buffersize);
newbuffer[buffersize] = 0; // literal zero value
Or you can construct a std::string, whichever you prefer.
I am trying to read 4 characters at a specific position from a file. The code is simple but the result is really confusing:
fstream dicomFile;
dicomFile.open(argv[1]);
dicomFile.seekg(128,ios::beg);
char * memblock = new char [4];
dicomFile.read(memblock,4);
cout<<"header is "<<memblock<<endl;
Ideally the result should be "DICM" but the actual result from the console was "DICM" plus weird characters, as shown in the picture. What's more, every time I run it, the characters are different. I suppose this may be something about ASCII and Unicode, I tried to change project property from Unicode to multibytes and then change back, no difference.
Does anyone know what's happening here and how do I solve it please? Thanks very much!
C style (char *) strings use the concept of null-terminators. This means strings are ended with a '\0' character in their last element. You are reading in exactly 4 characters into a 4 character buffer, which does not include a null character to end the string. C and C++ will happily run right off the end of your buffer in search for the null terminator that signifies the end of the string.
Quick fix is to create a block of length + 1, read in length data, then set str[length] = '\0'. In your case it would be as below.
char * memBlock = new char [5];
// populate memBlock with 4 characters
memBlock[ 4 ] = '\0';
A better solution is to use std::string instead of char * when working with strings in C++.
You could also initialize the buffer with zeros, putting null-terminators at every location.
char * memblock = new char [5](); // zeros, and one element longer
Fairly inefficient though.
I want to write three characters to a file, then a struct, then one more character.
Finally I would like to read the character before the struct, the struct itself, the character after the struct and display them on the screen.
struct stuff{
int a;
int b;
};
int main(){
FILE * fp = fopen("input.txt", "w+");
char charA = 'z';
char charB = 's';
char charC = 'q';
char charD = 'e';
//create a struct of type stuff
stuff s;
s.a = 123;
s.b = 2111;
//fwrite three first chars
fwrite(&charA, 1, sizeof(char), fp);
fwrite(&charB, 1, sizeof(char), fp);
fwrite(&charC, 1, sizeof(char), fp);
//fwrite the struct
fwrite(&s, 1, sizeof(struct stuff), fp);
//fwrite the last char
fwrite(&charD, 1, sizeof(char), fp);
//read the char before the struct, the struct itself,
// and the char after the struct
char expectedCharC;
stuff expectedStructS;
char expectedCharD;
fseek(fp, sizeof(struct stuff) + sizeof(char), SEEK_END);
fread(&expectedCharC, 1, sizeof(char), fp);
fread(&expectedStructS, 1, sizeof(struct stuff), fp);
fseek(fp, sizeof(char)*3 + sizeof(struct stuff), SEEK_SET);
fread(&expectedCharD, 1, sizeof(char), fp);
cout<<expectedCharC<<" "<<expectedStructS.a<<" ";
cout<<expectedStructS.b<<" "<<expectedCharD<<endl;
fclose(fp);
return 0;
}
Instead of this result:
q 123 2111 e
I get this result:
4197174 0 e
I don't know what I'm doing wrong. I'm writing bytes to the file, reading them back and displaying them on the screen. What goes wrong?
thank you in advance
Wow, lots of problems in your code. Let's tackle them one by one.
As mentioned by unwind, the mode you're using to open the file seems to be incorrect as to what you're trying to do. For one, you're trying to read from a file that is opened for write-only.
You're using fwrite wrongly. It goes fwrite(pointer to data, size of each data, number of data, FILE pointer);.
You're using fseek wrongly. I see you're confused with the offset parameter. This offset defines a signed distance from the origin specified as the last argument to fseek. Therefore, if you're at SEEK_END, you should be moving backwards by having your offset be a negative number.
I've done these changes myself and now it works. Output: q 123 2111 e
Here's a nice little website for you too. Helped me with your problem.
Thank you for reading.
First, as has been pointed out, you must open the file in binary
mode. Even then, just dumping the bytes of a struct means
that you won't be able to read it correctly some time in the
future. But as long as you're reading from the same process, it
should be OK.
The real problem is what you are doing with all of the fseek:
before the first fread, you do an fseek beyond the end of
the file. Any read from that position is guaranteed to fail.
You really should check the status of the file, and ensure that
the fread has succeeded before accessing any of the values you
read. If it failed, accessing the variables (at least those in
stuff) is undefined behavior; most likely, you'll get some
random garbage.
Your first fseek should probably be to the beginning of the file, or
else:
fseek( fp, -(sizeof( stuff ) + 4), SEEK_BEG);
If you've just read the struct, then the second fseek is
unnecessary as well. (In your case, it means that the final
'e' is correctly read.)
You must open your file in binary mode for this to work.
FILE * fp = fopen("input.txt", "wb+");
^
|
blam!
Your wanted result is also a bit unclear, shouldn't it start with the three characters 'z', 's' and 'q', and then have the integers? Note that the integers are likely to appear byte-swapped if you're on a little-endian machine.
To help debug the code, you should add return-value checking to all I/O calls, since I/O can fail. Also note that sizeof (char) is always 1, so it's not very beneficial to write it like that.
I am new to the forum. I have a strange problem. I have a simple code which reads unformatted data from a file using read() function. The code is given below.
int main () {
ifstream meshfile;
char buf[1000], ch;
memset(buf, 0, 1000);
meshfile.open ("sometextfile");
meshfile.read (buf, 1000);//38+62+(19*47) + 7);
cout << strlen(buf) << std::endl;
cout << buf << std::endl;
}
The code when run with the sample input file below gives 1006 as length of buf and prints additional characters for buf. Strangely, this happens only when bufsize is 1000 & 1000 characters are read. Changing the bufsize to > 1000 and reading 1000 chars does not produce this error. Could this be a coding problem?
The sample input file is
fdjgjdskgggggggggggggggggggggggggggggj bvjgdsv dsjkvgds gvdsj gvjdsgvjksdjkfgdsjkgfdsjgfsdjgfjkdsgfkjsdgjfgsdjfgdsjgfsdjgfjsdgfjsgfjsdgfjgsdjfgsdjfgdsjgfsdjgfsdjgfjsdgfjsdgfjsdg
fdjgjdskgggggggggggggggggggggggggggggj bvjgdsv dsjkvgds gvdsj gvjdsgvjksdjkfgdsjkgfdsjgfsdjgfjkdsgfkjsdgjfgsdjfgdsjgfsdjgfjsdgfjsgfjsdgfjgsdjfgsdjfgdsjgfsdjgfsdjgfjsdgfjsdgfjsdg
fdjgjdskgggggggggggggggggggggggggggggj bvjgdsv dsjkvgds gvdsj gvjdsgvjksdjkfgdsjkgfdsjgfsdjgfjkdsgfkjsdgjfgsdjfgdsjgfsdjgfjsdgfjsgfjsdgfjgsdjfgsdjfgdsjgfsdjgfsdjgfjsdgfjsdgfjsdg
fdjgjdskgggggggggggggggggggggggggggggj bvjgdsv dsjkvgds gvdsj gvjdsgvjksdjkfgdsjkgfdsjgfsdjgfjkdsgfkjsdgjfgsdjfgdsjgfsdjgfjsdgfjsgfjsdgfjgsdjfgsdjfgdsjgfsdjgfsdjgfjsdgfjsdgfjsdg
fdjgjdskgggggggggggggggggggggggggggggj bvjgdsv dsjkvgds gvdsj gvjdsgvjksdjkfgdsjkgfdsjgfsdjgfjkdsgfkjsdgjfgsdjfgdsjgfsdjgfjsdgfjsgfjsdgfjgsdjfgsdjfgdsjgfsdjgfsdjgfjsdgfjsdgfjsdg
fdjgjdskgggggggggggggggggggggggggggggj bvjgdsv dsjkvgds gvdsj gvjdsgvjksdjkfgdsjkgfdsjgfsdjgfjkdsgfkjsdgjfgsdjfgdsjgfsdjgfjsdgfjsgfjsdgfjgsdjfgsdjfgdsjgfsdjgfsdjgfjsdgfjsdgfjsdg
You problem is the use of strlen
It expects a string terminated by \0.
read doesn't add a \0 at the end of the buffer, so strlen reads beyond the edge of the buffer.
Make your buffer 1001 chars long, leaving room for a nul termination. Memset 1001 also. Without that nul terminator, strlen will not work.
Better yet, use <array> and do not use memset. A simple buf[1000] = 0 will do.
What's read from the file is not a '\0' terminated string but raw data. You should check the return value of stream.gcount() containing the number of bytes actually read into the buffer and use it in subsequent code. Manual here.
size_t size = meshfile.read(buf, sizeof(buf)/sizeof(*buf)).gcount();
std::cout << size << std::endl;
I think what the guys here and I mean is:
1)read(..) does not add the null terminator.
2)You initialized your buffer to 0 using memset. When you read < 1000 characters, the array elements that comes after the last character read in are all still 0 (effectively null, because they were initialized to that value) hence even if read(..) did not add the null terminator, things did not break. This is why Jive Dadson asks you to resize your buffer to 1001 char and initialize your array to 0, so that even if you read in 1000 characters, the 1001th character is still 0 and will act as the null terminator.
But this is actually a bug. Consider what happens when you read in the last line which has < BUF_SIZE? Hence it is better to check for the number of characters read in at each turn as suggested by some of the posters.
3)When you read > 1000 characters, did you changed to a larger buffer and did you initialize your buffer to '0' for this larger buffer? If so naturally you won't have a problem as the situation will be the same as above. If not, I'm curious how you can read > 1000 characters into a 1000 char buffer.
4)Basically your current method of reading data is unreliable. You should resize your buffer to have 1 more element than the max you intend to read. After each read, you should get the number of characters actually read in and set the null terminator if you intend to pass the buf as a string and perform operations such as copy, printf etc.