Tellg returning unexpected value - c++

I have a function which reads lines from a file. But before reading it returns the address from where its going to read the next line.
my function is:
void print()
{
int j=0;
string a,b,c,d,e;
ifstream i("data.txt");
cout<<setw(15)<<left<<"Hash Value"<<setw(15)<<left<<"Employee Name"<<setw(15)<<left<<"Employee ID"<<setw(15)<<left<<"Salary"<<setw(15)<<left<<"Link"<<endl;
while(j<10)
{
j++;
cout<<i.tellg()<<endl;
i>>a>>b>>c>>d>>e;
cout<<setw(15)<<left<<a<<setw(15)<<left<<b<<setw(15)<<left<<c<<setw(15)<<left<<d<<setw(15)<<left<<e<<endl;
}
i.close();
}
The file it is reading from is data.txt:
0 --- 0 0 -1
1 --- 0 0 -1
2 --- 0 0 -1
3 --- 0 0 -1
4 --- 0 0 -1
5 --- 0 0 -1
6 --- 0 0 -1
7 --- 0 0 -1
8 --- 0 0 -1
9 --- 0 0 -1
And the output I am getting is:
Hash Value Employee Name Employee ID Salary Link
0
0 --- 0 0 -1
81
1 --- 0 0 -1
157
2 --- 0 0 -1
233
3 --- 0 0 -1
309
4 --- 0 0 -1
385
5 --- 0 0 -1
461
6 --- 0 0 -1
541
7 --- 0 0 -1
617
8 --- 0 0 -1
693
9 --- 0 0 -1
Every line is of length 76 characters. So everytime the address printed should increase by 76.
But i dont understand whats going on when the 2nd line is printed[hash value 1], and the 7th line is printed [hash value 6].
Can someone please help me with this?

A couple of things:
First and foremost, you're not reading line by line, so there
is no reason to assume that you advance the number of characters
in a line each time through the loop. If you want to read line
by line, use std::getline, and then extract the fields from
the line, either using std::istringstream or some other
method.
The result of tellg is not an integer, and when converted to
an integral type (not necessarily possible), there is no
guaranteed relationship with the number of bytes you have
extracted. On Unix machines, the results will correspond, and
under Windows if (and only if) the file has been opened in
binary mode. On other systems, there may be no visible
relationship what so ever. The only valid portable use of the
results of tellg is to pass it to a seekg later; anything
else depends on the implementation.
How do you know that each line contains exactly 76 characters?
Depending on how the file was produced, there might be a BOM at
the start (which would count as three characters if the file in
encoded in UTF8 and you are in "C" locale). And what about
trailing whitespace. Again, if your input is line oriented, you
should be reading lines, and then parsing them.
Finally, but perhaps the most important: you're using the
results of >> without verifying that the operator worked. In
your case, the output suggests that it did, but you can never be
sure without verifying.
Globally, your loop should look like:
std::string line;
while ( std::getline( i, line ) ) {
std::istringstream l( line );
std::string a;
std::string b;
std::string c;
std::string d;
std::string e;
l >> a >> b >> c >> d >> e >> std::ws;
if ( !l || l.get() != EOF ) {
// Format error in line...
} else {
// ...
}
}
Outputting tellg still won't tell you anything, but at least
you'll read the input correctly. (Outputting the length of
line might be useful in some cases.)

Related

Is there a better way to extract the n-th element of a stringstream than ignore in a loop?

I want to extract the n-th element of an std::istringstream. Right now I'm using a loop with std::istringstream::ignore, something like this:
std::istringstream linestream(line);
for (int i=0; i < n; i++) {
linestream.ignore(50, ' ');
}
linestream >> importantVariable;
The input is a process stat file on linux from /proc/$PID/stat and is comma seperated, but the fields do not have a fixed width (std::seekg won't work reliably here).
Is there a better way to do this? I was expecting something like an overloaded ignore method, that takes an argument which defines how many elements it should skip, instead of having to use a loop.
Edit: I've added information about the input stream.
Here is an example line:
1092 (avahi-daemon) S 1071 1071 1071 0 -1 1077936192 30 0 0 0 0 0 0 0 20 0 1 0 534 48205824 85 18446744073709551615 1 1 0 0 0 0 0 0 0 0 0 0 17 4 0 0 0 0 0 0 0 0 0 0 0 0 0
Basically all said in the comments.
I just one to show an additional solution. The input data is anyway stored in a std::string. So you can directly extract it from there.
You can use iterators and std::next instead of loops.
The same works of course also for streams.
please see
#include <iostream>
#include <string>
#include <regex>
#include <iterator>
#include <sstream>
const std::regex re(" ");
int main() {
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
std::string line{ "1092 (avahi - daemon) S 1071 1071 1071 0 - 1 1077936192 30 0 0 0 0 0 0 0 20 0 1 0 534 48205824 "
"85 18446744073709551615 1 1 0 0 0 0 0 0 0 0 0 0 17 4 0 0 0 0 0 0 0 0 0 0 0 0 0 "};
// 1. Extracting direcly from std::string
std::string entry24 = *std::next(std::sregex_token_iterator(line.begin(), line.end(), re, -1), 24);
std::cout << entry24 << "\n";
// 2. Putting in Stream and extracting from stream
// Stream solution
std::istringstream linestream(line);
entry24 = *std::next(std::istream_iterator<std::string>(linestream), 24);
std::cout << entry24 << "\n";
return 0;
}

Matlab - Convert Character Vector Into Number Vector?

I'm trying to implement an oscilloscope for a digital input and send it over a serial port for debugging. I have the scope software sending Matlab a string like "000000111111111000000001111111000000". I'd like to plot this. Is there any way for me to split this string into a vector. It doesn't seem Matlab allows you to use strsplit() without a delimiter. I'd rather not bog up the communications with a delimiter between each byte.
With MATLAB's weak typing, this is actually quite easy:
>> str = '000000111111111000000001111111000000'
str = 000000111111111000000001111111000000
>> class(str)
ans = char
>> vec = str - '0'
vec =
Columns 1 through 22:
0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0
Columns 23 through 36:
0 1 1 1 1 1 1 1 0 0 0 0 0 0
>> class(vec)
ans = double
This subtracts the ordinal value of the character '0' from each character in the string, leaving the numerical values 0 or 1.
You can use sscanf with a single value width:
a = '000000111111111000000001111111000000'
b = sscanf(a, '%1d');
Which returns:
>> b.'
ans =
Columns 1 through 18
0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0
Columns 19 through 36
0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0
A quick and fast solution is:
data = '000001111111110000000000111111111110000000';
vec = str2double(cellstr(data.').');
It will produce a column vector of numeric values. If you want a row vector as output, just use a single transpose:
vec = str2double(cellstr(data.'));
I'm surprised how difficult this is to do. But here's what I came up with:
str = '000001111111110000000000111111111110000000'; %test string
y = cellfun(#(x) str2num(x), regexp(str,'\d','match'));
plot(y);
regexp() seems to be the only way to go. By default, it return indexes of matches so you need to specify 'match'. Then you end up with a cell array of strings. The only good way to convert this into a numerical array is one item at a time with str2num().
I hope this helps someone else out who is assuming there is a straight forward function as I assumed. And if anyone knows a way to do this without converting my "01...01....01....01....00....00....00....00" stream of bytes into the ascii representations of the binary numbers: "49.....49.....49....49....48....48....48....48", I'd love to hear it.

Reading single lines from file into vector

I have an input file of the following format:
# 1 2 3 4 5 6 7
0 0 0 1
1 0 0 1
2 0 0 1
3 0 0 1
5 0 0 1
6 0 0 1
# 0 0 2 2 4 4 5
0 0 0 1
0 1 0 1
0 2 0 1
0 3 0 1
# 9 10 11 12 13 14 15 16 17 18
0 0 0 1
0 0 1 1
0 0 2 1
0 0 3 1
Each line preceded by a # must be read into its own vector. The entries in between these vectors represent matrices that also must be read into their own matrix.
So from the input file above, what I want to end up having is the following:
knot1 = {1 2 3 4 5 6 7}
cp1= { {0,0,0,1} {1,0,0,1} {2,0,0,1} {3,0,0,1} {5,0,0,1} {6,0,0,1} }
knot2 = {0 0 2 2 4 4 5}
cp2= {{...} {...} {...} {...} }
knot3 = {9 10 11 12 13 14 15 16 17 18}
cp3= {{...} {...} {...} {...} }
Note, each vector is not necessarily the same size! Same goes for the matrices. Also, the number of #vectors and matrices can vary as well.
Here is what I have so far:
ifstream file;
file.open(filename.c_str());
if(file.fail()){
cout << "Cannot open " << filename << endl;
}
int curr_line = 0;
vector<int> knot_locations; //stores the locations of the #vectors
while(!file.eof()){ //loops over input file checking to see where the #vectors are
curr_line++;
string line;
getline(file,line);
if(line[0]=='#'){
knot_locations.push_back(curr_line);
}
}
for(int i=0; i < knot_locations.size(); i++){
file.seekg(std::ios::beg);
for(int i=0; i < knot_locations[i] - 1; ++i){ // this loop skips to the line that contains the #vectors.
file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
}
}
so now that I am at the line
containing the vector, how can I read
in JUST that SINGLE line into a vector?!
I'm not sure how to turn a string into
a vector of floats. Also, since I know all the
locations of the vectors, I can read everything
else between into the matrices. But again, same
problem. I am not sure how to go about actually
reading these into a numeric array/vector given a line (string)
file.close();
Probably better ways of doing this. Any ideas on how to go about this problem? The key is to be able to read all the vectors marked with a # into their own vector. There can be anywhere between 1-3 of these vectors. And in between each of these vectors is a matrix of unknown rows/columns that also need to be read into their own matrix. What I have above just locates the # marked vectors. Need help on how to read a string line into a numeric array OR a recommendation on a different way to go about this.
Thank you.

How Can get the interface list in C++ in linux ?

I want to get my internet interface list in C++ in linux because my program need to down Or up the link but i dont know how get the interface to modifi it.
The system call you are looking for is getifaddrs. There is a brief example program on the man page.
Within the ifaddrs there is a bit flag field ifa_flags with which you can test whether the interface is up or down.
Read from /proc/net/dev
Full description in man proc:
/proc/net/dev
The dev pseudo-file contains network device status information. This gives the number of received and sent packets,
the number of errors and collisions and other basic statistics. These are used by the ifconfig(8) program to report
device status. The format is:
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
lo: 2776770 11307 0 0 0 0 0 0 2776770 11307 0 0 0 0 0 0
eth0: 1215645 2751 0 0 0 0 0 0 1782404 4324 0 0 0 427 0 0
ppp0: 1622270 5552 1 0 0 0 0 0 354130 5669 0 0 0 0 0 0
tap0: 7714 81 0 0 0 0 0 0 7714 81 0 0 0 0 0 0
This is a text file, each interface is a line... should be easy.
For example (no error checking... just printing the interface names)
#include <fstream>
#include <iostream>
int main() {
std::ifstream in("/proc/net/dev");
int c=0;
std::string line;
for(; std::getline( in, line ); c++)
{
if(c<2) continue; // skip header
std::size_t start=line.find_first_not_of(" "); // skip leading spaces
std::size_t end=line.find_first_of(":",start); // look for the ":"
std::cout << line.substr(start,end-start) << std::endl;
}
}

generating 'random' number using modulo from a stream of odd numbers

i want to generate a pseudo-random bool stream based on a modulo operation on another stream of integers (say X), so the operation would be
return ( X % 2);
The only problem is that X is a stream of integers that always ends in 1, so for instance would be somehing like 1211, 1221, 1231, 1241 .... is there a way for me to disregard the last bit (without using string manip) so the test doesnt always pass or always fail?
How about (X / 10) % 2 then?
If you'd otherwise be happy to use the last bits, use the penultimate bits instead:
return (x & 0x2) >> 1;
So say the next number from your stream is 23:
1 0 1 1 1 // 23 in binary
& 0 0 0 1 0 // 0x2 in binary
-----------
0 0 0 1 0
Shifting that right by one bit (>> 1) gives 1. With 25, the answer would be 0:
1 1 0 0 1
& 0 0 0 1 0
-----------
0 0 0 0 0
return ( x%20/10 );