Reading int with specific field width from stringstream [duplicate] - c++

This question already has an answer here:
setw() does not affect reading integer fields
(1 answer)
Closed 3 years ago.
I'm trying to read bytes in hex notation from a string. The bytes may or may unfortunately not be separated by whitespace, e.g. " 00 ffab c " is a valid example and should result in 4 bytes read, 0x00, 0xff, 0xab and 0x0c. The problem is to skip whitespace but read only two adjacent digits, when present.
If the input were from a file, the task would be as easy as while(fscanf(f, "%2d", &i) == 1) ... because sscanf skips whitespace, the read position is tracked by the underlying FILE, and the maximum field width is only applied to the item read, not the raw input characters containing the whitespace. But the position tracking is not possible when reading from a string; I need to use the %n format conversion specifier which stores the number of characters read so far by this invocation into the associated variable, e.g. scanf(f, "%2d%n", &i, &readIncr), and manually maintain a read position by adding the respective increments.
This is somewhat cumbersome, hence I wanted to use std::istringstream which does keep track of a position in the underlying string.
But setting a width on the input stream does not have the desired (and expected) effect; below is a minimal demonstration; for simplicity I'm using decimal integers. Documentation and examples for an input field width are scarce.
Am I doing something wrong? I this use case simply not intended?
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdio>
using namespace std;
int main()
{
const char *s = " 1234";
int i;
istringstream is(s);
if (is >> setw(2) >> i)
{
cout << "stringstream i: " << i << '\n';
}
if (sscanf(s, "%2d", &i) == 1)
{
cout << "scanf i: " << i << '\n';
}
}
The output is (with g++ and MSVC)
$ g++ -Wall -o fieldwidth fieldwidth.cpp && ./fieldwidth
stringstream i: 1234
scanf i: 12

Sadly cpp streams are far from perfect. AFAIK std::setw works only for reading strings. What you can do is:
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdio>
using namespace std;
int main()
{
const char *s = " 1234";
std::string i;
istringstream is(s);
if (is >> setw(2) >> i)
{
cout << "stringstream i: " << std::stoi(i) << '\n';
}
int j;
if (sscanf(s, "%2d", &j) == 1)
{
cout << "scanf i: " << j << '\n';
}
}
And you get expected output:
stringstream i: 12
scanf i: 12

Related

C++: Hex values to String

I would like to convert a hex-value ("206564697374754f") to a string (from hex to ascii). These hex-values are from gdb, so the contents are "reversed" by every two. (So the exact hex-value I need to convert is "4f75747369..."). reverse2() reverses the string appropriately, but it needs to now be converted to hex (hence the "0x", then atoi()).
The following code is what I have so far, but I run into a runtime-error. What is the issue, and is there a better way of doing this?
#include <bits/stdc++.h>
using namespace std;
void reverse2s(string str)
{
for (int i=str.length()-2; i>=0; i-=2) {
string hx="0x"+str[i]+str[i+1];
cout << (char)(std::stoi( hx ));
}
}
// Driver code
int main(void)
{
string s = "206564697374754f";
reverse2s(s);
return (0);
}
The expression "0x"+str[i]+str[i+1]; does not do what you think. "0x" is a character array (not a string). Since str[i] is a character, the addition will add convert that character to an int, and perform a pointer addition. This results in Undefined Behavior.
To do the string concatenation you're expecting, you need to create a string object first:
string hx="0x"s+str[i]+str[i+1];
"0x"s will create an actual string literal to append characters to.
Well it seems like you're just trying to print it as hex,
so you could do
std::cout << std::hex << 5 << std::endl; // prints 0x5
If you don't care about performance:
std::stringstream s;
s << std::hex << num:
s.str(); // std::string containing your number as hex
If you do care about performance I have no clue
This should work:
#include <iostream>
#include <strstream>
#include <string>
int main()
{
std::strstream s1; // dynamic buffer
s1 << std::hex << 12345 << std::endl;
std::cout << "buffer: '" << s1.str() << "'\n";
s1.freeze(false);
return 0;
}

Why splitting a filebuffer by space character doesn't work?

Given the following code:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
int main()
{
std::stringstream istrs("1 2 3 4 5 6");
std::vector<int> vec;
while(!istrs.eof())
{
int temp;
std::stringstream o;
istrs.get(*o.rdbuf(), ' ');
o >> temp;
vec.push_back(temp);
}
for(auto a : vec)
std::cout << a << " ";
std::cout << std::endl;
}
Why does the loop never exit? Why does o remain uninitialized?
I'm trying to split the ifstream buffer into smaller chunks for processing but I don't know why this get() doesn't work like I thought it would.
You could modify your code to parse the string using the getline for example:
std::stringstream istrs("1 2 3 4 5 6");
std::vector<int> vec;
string temp;
while(getline(istrs,temp, ' '))
{
vec.push_back(stoi(temp));
}
for(auto a : vec)
std::cout << a << " ";
std::cout << std::endl;
I do not see the need for another stringstream and then a conversion.
To see why what you mentioned fails, refer to the documentation of stringstream and for get. We are dealing with the 6th overload of signature type basic_istream& get( basic_streambuf& strbuf, char_type delim );
reads characters and inserts them to the output sequence controlled by
the given basic_streambuf
You are storing that as an int, try declaring temp as string, get the string using the stream operator o >> temp, and do a conversion to int using stoi. You will find the conversion you will succeed for the first time and not the others, rather the program will crash. The reason is after 1, you extract no characters and satisfy the condition:
the next available input character c equals delim, as determined by
Traits::eq(c, delim). This character is not extracted.
In which case
If no characters were extracted, calls setstate(failbit).
In your while loop if you set !istrs.eof() && istrs.good(), you will see the program will terminate gracefully but you will only have one value.

Using cin for char array

Here is my code:
#include <iostream>
using namespace std;
int main(){
char inp[5], out[4];
cin >> inp >> out;
cout << inp << endl;
cout << out << endl;
system("pause");
return 0;
}
when I type:
12345
6789
It gives me:
6789
Why I failed to save the 5 words char array 'inp' and it showed nothing? The second input looks normal though. However, when I set out[3] or out[5], it seems to work alright? It seem that two char array of [5] then followed by [4] would cause problem...
I see that you enter (type) 1234567890 characters to input data for inp[5] - it is a problem because imp array is able to store 4 characters and null-terminator. When cin >> inp store more than 4 characters to inp array it leads to problem with data (somthing like undefined behaviour). So solution can be in allocation more memory for data, e.g.:
#include <iostream>
using namespace std;
int main(){
char inp[15], out[15]; // more memory
cin >> inp >> out;
cout << inp << endl;
cout << out << endl;
system("pause");
return 0;
}
When you read into a character array the stream keeps reading until it encounters whitespace, the stream is not aware of the size of the array that you pass in so happily writes past the end of the array so if your first string is longer than 4 characters your program will have undefined behaviour (an extra character is used after your input for the null terminator).
Fortunately c++20 has fixed this issue and the stream operators no longer accept raw char pointers and only accept arrays and will only read up to size - 1 characters.
Even with c++20 the better solution is to change your types to std::string which will accept any number of characters end even tell you how many characters it contains:
#include <iostream>
int main(){
std::string inp, out;
std::cin >> inp >> out;
std::cout << inp << "\n";
std::cout << out << "\n";
return 0;
}
Its because, in memory layout of computer out[4] is laid out first and then inp[5]. Something like this:
out[0],out[1],out[2],out[3],inp[0],inp[1],inp[2],inp[3],inp[4]
So, when you write 6789 in out[4], you are overflowing null character to inp[0]. So, inp becomes NULL.

Printing out blank spaces from a text file in C++

#include <iostream>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <string>
#include <iomanip>
#include <fstream>
#include <stdio.h>
using namespace std;
int main()
{
ifstream file;
string filename;
char character;
int letters[153] = {};
cout << "Enter text file name: ";
cin >> filename;
file.open(filename.c_str());
if (! file.is_open())
{
cout << "Error opening file. Check file name. Exiting program." << endl;
exit(0);
}
while (file.peek() != EOF)
{
file >> character;
if(!file.fail())
{
letters[static_cast<int>(character)]++;
}
}
for (int i = 0; i <= 153; i++)
{
if (letters[i] > 0)
{
cout << static_cast<char>(i) << " " << letters[i] << endl;
}
}
exit(0);
}
#endif
Hi everyone, my current code counts the frequency of each letter from a text file. However, it does not count the number of blank spaces. Is there a simple way to printout the number of blank spaces in a .txt file?
Also, how come when I'm trying to access a vector item, I run into a seg fault?
For example, if I use:
cout << " " + letters[i] << endl;, it displays a segfault. Any ideas?
Thank you so much.
By default, iostreams formatted input extraction operations (those using >>) skip past all whitespace characters to get to the first non-whitespace character. Perhaps surprisingly, this includes the extraction operator for char. In order to consider whitespace characters as characters to be processed as usual, you should alter use the noskipws manipulator before processing:
file << std::noskipws;
Don't forget to set it back on later:
file << std::skipws;
What if you're one of those crazy people who wants to make a function that leaves this aspect (or in even all aspects) of the stream state as it was before it exits? Naturally, C++ provides a discouragingly ugly way to achieve this:
std::ios_base::fmtflags old_fmt = file.flags();
file << std::noskipws;
... // Do your thang
file.flags(old_fmt);
I'm only posting this as an alternative way of doing what you're apparently trying. This uses the same lookup table approach you use in your code, but uses an istreambuf_iterator for slurping unformatted (and unfiltered) raw characters out of the stream buffer directly.
#include <iostream>
#include <fstream>
#include <iterator>
#include <climits>
int main(int argc, char *argv[])
{
if (argc < 2)
return EXIT_FAILURE;
std::ifstream inf(argv[1]);
std::istreambuf_iterator<char> it_inf(inf), it_eof;
unsigned int arr[1 << CHAR_BIT] = {};
std::for_each(it_inf, it_eof,
[&arr](char c){ ++arr[static_cast<unsigned int>(c)];});
for (int i=0;i<sizeof(arr)/sizeof(arr[0]);++i)
{
if (std::isprint(i) && arr[i])
std::cout << static_cast<char>(i) << ':' << arr[i] << std::endl;
}
return 0;
}
Executing this on the very source code file itself, (i.e. the code above) generates the following:
:124
#:4
&:3
':2
(:13
):13
*:1
+:4
,:4
/:1
0:3
1:2
2:1
::13
;:10
<:19
=:2
>:7
A:2
B:1
C:1
E:2
F:1
H:1
I:3
L:1
R:2
T:2
U:1
X:1
[:8
]:8
_:10
a:27
b:1
c:19
d:13
e:20
f:15
g:6
h:5
i:42
l:6
m:6
n:22
o:10
p:1
r:37
s:20
t:34
u:10
v:2
z:2
{:4
}:4
Just a different way to do it, but hopefully it is clear that usually the C++ standard library offers up elegant ways to do what you desire if you dig deep enough to find whats in there. Wishing you good luck.

How do you print out the binary representation of a file?

I'm trying to create a compression program but I need to know the basics of how to open a file in binary and print out its contents.
In a text file, called "Tester.txt", I have this:
MJ
In a .cpp file, I have this:
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main
{
fstream istr;
istr.open("Tester.txt", ios::binary);
}
From my understanding in the cplusplus reference, this uses a stream object to open the file specified in binary?
But I'm stuck on how exactly I can "print" out the first byte of the file, i.e. the letter M in binary?
I know that M (capital letter) in binary is 01001101.
So how do I do a cout of M in binary?
Thanks
You have a confusion between numbers and representations of numbers, probably created by the fact that the word "binary" can sometimes be used to describe both. When you open a file in "binary mode", that means you see the raw values of the bytes in the file. This has nothing to do with "binary" in the sense of representing numbers in base two.
Say a file has "x" followed by a newline and a return. In "binary mode", you will see that as three byte-size values, one containing the ASCII code for "x", one containing the ASCII code for newline, and one containing the ASCII code for return. These are values that you read from the file. You can represent them in binary, but you can also represent them in decimal or hex, you still have read the exact same values from the file.
Reading a file in "binary" determines the values you read, not how you represent them. Two cars are the same two cars whether you represent the value two as "2" (decimal), "10" (binary), or "two" (English).
Binary input/output on streams is done using their member functions read() and write().
Like this:
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main
{
fstream istr;
istr.open("Tester.txt", ios::binary);
if (istr) {
// Read one byte
char byte;
if (!istr.read(&byte, 1)) {
// Error when reading
}
// Alternative way to read one byte (thanks to DyP)
byte = istr.get();
// Another alternative:
if (!istr.get(byte)) {
// Error when reading.
}
// Read a block of bytes:
char buffer[1024];
if (!istr.read(buffer, 1024)) {
// Read error, or EOF reached before 1024 bytes were read.
}
}
}
Here is a quick program which uses the C++ Standard Library to do all the heavy lifting.
#include <iostream>
#include <iterator>
#include <bitset>
#include <algorithm>
int main() {
std::istreambuf_iterator< char > in( std::cin ), in_end;
std::ostream_iterator< std::bitset< 8 > > out( std::cout, " " );
std::copy( in, in_end, out );
std::cout << '\n';
}
See it run. I used std::cin for demonstration, but you should open a file with std::ios::binary and pass that instead.
Since each variable is only used once, this could all be done on one line. Even if you open the file instead of using std::cin.
EDIT:
std::copy is a function encapsulating the loop for ( ; in != in_end; ++ in ) * out ++ = * in;.
The type std::istreambuf_iterator either takes an istream constructor argument and provides an iterator in suitable for such a loop, or takes no constructor argument and provides an iterator in_end such that in == in_end if in.eof() == true. The iterator gets unformatted bytes (type char) from the stream.
The type std::ostream_iterator< std::bitset< 8 > > provides an iterator out so * out ++ = x converts x to std::bitset< 8 > and prints the result. In this case x is a byte and bitset provides a constructor for such a byte value, and overloads operator<< to print a binary representation of 1's and 0's.
To output a value in binary you need to do it manually as the standard library does not support that output format.
int mask = 0x80;
while(mask)
{
std::cout << (byteValue & mask ? '1' : '0');
mask >>= 1;
}
std::cout << std::endl;
This will scan from the top bit to the low bit and print out a value representing each one.
try this:
#include <fstream>
#include <iostream>
#include <string>
#include <bitset>
#include <iomanip>
int main()
{
// Set up your objects.
char c;
std::fstream istr("Tester.txt", ios::binary);
unsigned long loc = 0;
// Read the file one character at a time.
// Remembering not to skip white space in this situation.
for(;istr >> std::noskipws >> c;++loc)
{
// When printing compensate for non printable characters.
// If the character is outside the ASCII range then print it as an integer.
std::stringstream charStr;
if ((c < 32) || (c > 126))
{
charStr << "Char: " << c;
}
else
{
charStr << "Non Printable: " << static_cast<int>(c);
}
// Print the value and location in a nicely formatted way.
std::cout << std::setw(16) << location
<< " : "
<< std::bitset<8>(c).to_string() // Prints the character as an 8 bit binary value.
<< " : "
<< charStr.str()
<< "\n";
}
}
But there are standard tools that do this already:
Look at od