I have a strings like this:
315c4eeaa8b5f8aaf9174145bf43e1784b8fa00dc71d885a804e5ee9fa40b16349c146fb778cdf2d3aff021dfff5
Is there a way to read it from file at once into string object keeping in mind that every 2 chars are hexadecimal representation of byte? I.e. I need a reading with conversion from hex to char.
UPDATE
Guys, please read carefully what I asked.
I'm able to write conversion functions and looping along a string.
BUT I need read a string of hex to a string of char at once.
No any looping. No conversions by hands.
Something like cin >> ...some string variable...
Thanks.
UPDATE2
Imagine I have the string "315c4eeaa8b5". I want to write something like cin >> string_var and get that string_var containing exactly the "'0x31','0x5c','0x4e','0xea','0xa8','0xb5'". Please note, this last is an ordinal std::string. I.e. 0x31,0x5c,etc are codes of chars.
Hope it makes thing clearer.
Either you code something up or you use something that already exits. If you are using C++ IO streams then I would suggest taking a look at Boost.IOStreams library and especially its Filtering Streams concept. You can use the tab expanding 2.2.5.2 input_filter tutorial example as a base for your hexadecimal input filter implementation.
You can use istream::opeartor>> with the std::hex manipulator to parse as hexadecimal:
ifstream in("...");
char buffer[3];
vector<char> chars;
while (in.read(buffer, 2))
{
buffer[2] = '\0';
char c;
istringstream(buffer) >> hex >> c;
chars.push_back(c);
}
Related
I'm trying to use std::cin after a while.
Using uint8_t or unsigned char:
unsigned char data;
std::cin >> std::dec >> data;
Whatever std::dec is used or not, I get the first ASCII character I type.
If I type 12, data is 0x31 not 12. Why can't it parse number until 255 to be stored in a char?
int data;
std::cin >> std::dec >> data;
gives correctly data=12/0xC not 0x31
Why?
Using char[N] with std::hex
char data[128];
std::cin >> std::hex >> data;
Also gets the ASCII characters instead of the hexadecimal.
Writting 0x010203040506... data is 0xFFFFFFFFF...
Isn't std::cin>>std::hex able to parse the string I type into hexadecimal automatically?
In short:
cin >> charVar scans a single character from stdin
cin >> intVar scans characters from stdin until a non-numeric character is entered
Explaining your observation:
A char variable can store a single ASCII character.
When you type 12, only the character 1 is scanned.
The ASCII code of the character 1 is 0x31.
std::dec and std::hex affect the format of integers.
But as far as the streaming operators are concerned, char and its variants (including uint8_t aren't integers, they're single characters. They will always read a single character, and never parse an integer.
That's just how these functions are defined. There is no way around it. If you want an integer with a limited range, first read into an int (or other integer type that is not a char variant), and then range-check afterwards. You can, if you want, cast it to a small type afterwards, but you probably shouldn't. char types are awkward to work with numerically.
Similarly, reading into an array of char reads a string. (Also, never do that without using setw() to limit the length to fit in the buffer you have. Better yet, use std::string instead.) That's just how it's defined.
So, I'm having some issues with my c++ code. I have the following code, but so far I can't get most of the data stored into the structured data type.
//structured data declaration
struct item
{
int itemCode;
char description[20];
float price;
};
And then the get code looks like this.
cout << setprecision(2) << fixed << showpoint;
ofstream salesFile ("Sales.txt");
ifstream stockFile ("Stock.txt");
for (counter = 0; counter < 9; counter++)
{
stockFile >> instock[counter].itemCode;
stockFile.getline (instock[counter].description, 20);
stockFile >> instock[counter].price;
}
The output should have looked like:
1234 "description here" 999.99
Quantity X
And this was the output:
1234 0.00
Quantity 5
If you have a file format that is of the form (for one entry)
1234
description here
999.99
(across multiple lines) then the explanation is simple
Th reading code in your loop, which does
stockFile >> instock[counter].itemCode;
stockFile.getline (instock[counter].description, 20);
stockFile >> instock[counter].price;
will work in this sequence
The value of instock[counter].itemCode will receive the value 1234. However (and this is important to understand) the newline after the 1234 will still be waiting in the stream to be read.
The call of getline() will encounter the newline, and return immediately. instock[counter].description will contain the string "".
The expression stockFile >> instock[counter].price will encounter the d in description. This cannot be interpreted as an integral value, so instock[counter].price will be unchanged.
Assuming some preceding code (which you haven't shown) sets instock[counter].price to 999.99 the above sequence of events will explain your output.
The real problem is that you are mixing styles of input on the one stream. In this case, mixing usage of streaming operators >> with use of line-oriented input (getline()). As per my description of the sequence above, different styles of input interact in different ways, because (as in this case) they behave differently when encountering a newline.
Some people will just tell you to skip over the newline after reading instock[counter].itemCode. That advice is flawed, since it doesn't cope well with changes (e.g. what happens if the file format changes to include an additional field on another line?, what happens if the file isn't "quite" in the expected format for some reason?).
The more general solution is to avoid mixing styles of input on the one stream. A common way would be to use getline() to read all data from the stream (i.e. not use >> to interact directly with stockFile). Then interpret/parse each string to find the information needed.
Incidentally, rather than using arrays of char to hold a string, try using the standard std::string (from standard header <string>). This has the advantage that std::string can adjust its length as needed. std::getline() also has an overload that can happily read to an std::string. Once data is read from your stream as an std::string, it can be interpreted as needed.
There are many ways of interpreting a string (e.g. to extract integral values from it). I'll leave finding an approach for that as an exercise - you will learn more by doing it yourself.
My question seems to be the same as this one, but I didn't find an answer since the original question seems to ask something more specific.
In C++98, what is the difference between
char c;
cin.get(c);
and
char c;
cin >> c;
?
I've checked the cplusplus reference for get and operator>>, and they look the same to me.
I've tried above code and they seem to behave the same when I input a char.
The difference depends on when there is a whitespace character on the stream buffer.
Consider the input ' foo'
char c;
cin.get(c);
Will store ' ' in c
However
char c;
cin >> c;
Will skip the whitespace and store 'f' in c
In addition to what's already been said, std::istream::get() is also an unformatted input function so the gcount() of the stream is affected, unlike the formatted extractor. Most of the overloads of get() and getline() have mostly been made obselete by the introduction of std::string, its stream extractors, and std::getline(). I'd say to use std::istream::get() whenever you need a single, unformatted character straight from the buffer (by using its single or zero argument overload). It's certainly quicker than turning off the skipping of whitespace first before using the formatted extractor. Also use std::string instead of raw character buffers and is >> str for formatted data or std::getline(is, str) for unformatted data.
char ch[4];
char* ptr;
ptr = ch;
while(1)
{
cin >> *ptr;
if(*ptr == '\n')
break;
ptr++;
}
Here I just wrote a bit of sample code where I am trying to get out of a while loop when user writes ENTER but it's not working. Please help me. Thank you in advance.
To get a single character, use std::istream::get. This should work for getting newlines as well.
But instead of getting characters in a loop until you get a newline, why not just use something like std::getline:
std::string str;
std::getline(cin, str);
Or if you only want to get max three characters you can use std::istream::getline:
char ch[4];
cin.getline(ch, 4, '\n');
You are reading input into the value of a character. That's what *ptr means. I think you want just plain ptr, which is a pointer to an array of characters, which is something that is meant to receive data. What you wrote is basically this:
char c;
cin >> c;
I don't think that's what you meant, nor would it work even if it were, since as Joachim Pileborg points out above, the >> operator skips whitespace like newlines. In general, it is always best to be very robust when it comes to reading input. Provide adequate space, and either use a variable that can grow automatically (like std::string) or tell the system how much space you have (like fgets()).
The following will read a line:
istream& getline (char* s, streamsize n );
The extraction operator would skip leading white-spaces and stop execution on encountering any subsequent white-space. So, when you want to do something like this, use std::istream::get() or std::istream::getline().
I was trying out a few file reading strategies in C++ and I came across this.
ifstream ifsw1("c:\\trys\\str3.txt");
char ifsw1w[3];
do {
ifsw1 >> ifsw1w;
if (ifsw1.eof())
break;
cout << ifsw1w << flush << endl;
} while (1);
ifsw1.close();
The content of the file were
firstfirst firstsecond
secondfirst secondsecond
When I see the output it is printed as
firstfirst
firstsecond
secondfirst
I expected the output to be something like:
fir
stf
irs
tfi
.....
Moreover I see that "secondsecond" has not been printed. I guess that the last read has met the eof and the cout might not have been executed. But the first behavior is not understandable.
The extraction operator has no concept of the size of the ifsw1w variable, and (by default) is going to extract characters until it hits whitespace, null, or eof. These are likely being stored in the memory locations after your ifsw1w variable, which would cause bad bugs if you had additional variables defined.
To get the desired behavior, you should be able to use
ifsw1.width(3);
to limit the number of characters to extract.
It's virtually impossible to use std::istream& operator>>(std::istream&, char *) safely -- it's like gets in this regard -- there's no way for you to specify the buffer size. The stream just writes to your buffer, going off the end. (Your example above invokes undefined behavior). Either use the overloads accepting a std::string, or use std::getline(std::istream&, std::string).
Checking eof() is incorrect. You want fail() instead. You really don't care if the stream is at the end of the file, you care only if you have failed to extract information.
For something like this you're probably better off just reading the whole file into a string and using string operations from that point. You can do that using a stringstream:
#include <string> //For string
#include <sstream> //For stringstream
#include <iostream> //As before
std::ifstream myFile(...);
std::stringstream ss;
ss << myFile.rdbuf(); //Read the file into the stringstream.
std::string fileContents = ss.str(); //Now you have a string, no loops!
You're trashing the memory... its reading past the 3 chars you defined (its reading until a space or a new line is met...).
Read char by char to achieve the output you had mentioned.
Edit : Irritate is right, this works too (with some fixes and not getting the exact result, but that's the spirit):
char ifsw1w[4];
do{
ifsw1.width(4);
ifsw1 >> ifsw1w;
if(ifsw1.eof()) break;
cout << ifsw1w << flush << endl;
}while(1);
ifsw1.close();
The code has undefined behavior. When you do something like this:
char ifsw1w[3];
ifsw1 >> ifsw1w;
The operator>> receives a pointer to the buffer, but has no idea of the buffer's actual size. As such, it has no way to know that it should stop reading after two characters (and note that it should be 2, not 3 -- it needs space for a '\0' to terminate the string).
Bottom line: in your exploration of ways to read data, this code is probably best ignored. About all you can learn from code like this is a few things you should avoid. It's generally easier, however, to just follow a few rules of thumb than try to study all the problems that can arise.
Use std::string to read strings.
Only use fixed-size buffers for fixed-size data.
When you do use fixed buffers, pass their size to limit how much is read.
When you want to read all the data in a file, std::copy can avoid a lot of errors:
std::vector<std::string> strings;
std::copy(std::istream_iterator<std::string>(myFile),
std::istream_iterator<std::string>(),
std::back_inserter(strings));
To read the whitespace, you could used "noskipws", it will not skip whitespace.
ifsw1 >> noskipws >> ifsw1w;
But if you want to get only 3 characters, I suggest you to use the get method:
ifsw1.get(ifsw1w,3);