Convert separate digits into one whole number C++ - c++

I need a little more help. I have managed to convert all my chars input from a text file into digits.
Example:
Input from file:
$1,9,56#%34,9
!4.23#$4,983
Output:
1956
349
423
4983
Now, I need to take those individual digits the 1 9 5 6 and make it read as a whole number. The output would look the same but they would actually be whole numbers. Make sense? I have to do this in my outer loop. It also has to be an EOF loop. So, I know I need to take the first digit and multiply it by 10 and add the next digit then multiply all that by 10 until I reach the last number. How can I write that in an efficient non-crashing way?
The input.txt file has the input stated above.
This is what I have so far...
Any help is greatly appreciated
/*
*/
//Character Processing Algorithm
#include <fstream>
#include <iostream>
#include <cctype>
using namespace std;
char const nwln = '\n';
int main ()
{
ifstream data;
ofstream out;
char ch;
char lastch;
int sum;
data.open ("lincoln.txt"); //file for input
if (!data)
{
cout << "Error!!! Failure to Open lincoln.txt" << endl;
system ("pause");
return 1;
}
out.open ("out.txt"); //file for output
if (!out)
{
cout << "Error!!! Failure to Open out.txt" << endl;
system ("pause");
return 1;
}
data.get (ch); // priming read for end-of-file loop
while (data)
{
sum = 0;
while ((ch != nwln) && data)
{
if (isdigit(ch))
out<<ch;
if (ch == '#')
out<<endl;
{
;
}
lastch = ch;
data.get (ch); // update for inner loop
} // inner loop
if (lastch != '#')
out<<endl;
data.get (ch); // update for outer loop
} //outer loop
cout << "The End..." << endl;
data.close (); out.close ();
system ("pause");
return 0;
} //main

If you need simply to output all numbers in the standard stream std::cout (or some other stream as for example file) then you can use the following code as an example. I only substituted the file input for std::cin input in variable line. You can use file input instead of the standard stream.
Also instead of
std::ostream_iterator<char>( std::cout ),
use
std::ostream_iterator<char>( out ),
and instead of
std::cout << std::endl;
use
out << std::endl;
after the std::copy_if call.
Here is the example
#include <iostream>
#include <iterator>
#include <string>
#include <sstream>
#include <algorithm>
#include <cctype>
int main()
{
std::string line;
while ( std::getline( std::cin, line) ) // instead of std::cin use data
{
// std::cout << line << std::endl;
std::string word;
std::istringstream is( line );
while ( std::getline( is, word, '#' ) )
{
// std::cout << word << std::endl;
auto it = std::find_if( word.begin(), word.end(),
[]( char c ) { return ( std::isdigit( c ) ); } );
if ( it != word.end() )
{
std::copy_if( it, word.end(),
std::ostream_iterator<char>( std::cout ),
[]( char c ) { return ( std::isdigit( c ) ); } );
std::cout << std::endl;
}
}
}
}
Test input data is
$1,9,56#%34,9
!4.23#$4,983
The output is
1956
349
423
4983
Or you can define the lambda before its using.
#include <iostream>
#include <iterator>
#include <string>
#include <sstream>
#include <algorithm>
#include <cctype>
int main()
{
std::string line;
while ( std::getline( std::cin, line) ) // instead of std::cin use data
{
// std::cout << line << std::endl;
std::string word;
std::istringstream is( line );
while ( std::getline( is, word, '#' ) )
{
// std::cout << word << std::endl;
auto lm_IsDigit = []( char c ) { return ( std::isdigit( c ) ); };
auto it = std::find_if( word.begin(), word.end(), lm_IsDigit );
if ( it != word.end() )
{
std::copy_if( it, word.end(),
std::ostream_iterator<char>( std::cout ),
lm_IsDigit );
std::cout << std::endl;
}
}
}
}

Read the input file character by character. To check if a character is a digit, use std::isdigit. Then add the number to the back of a string.
If you need to convert a string to an integer, use std::stoi

Related

C++: why is vector implementation not yielding comma-delimited values?

I have a database.txt file with comma-separated values:
Name,ID,Year,Gender
I would like to extract each of these elements.
I've started with this code (I've already looked at all the other similar questions and implemented what they've suggested), but it's not printing each piece:
// reading a text file
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;
int main () {
string line;
ifstream myfile ("database.txt");
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
std::string str = line;
std::vector<int> vect;
std::stringstream ss(str);
int i;
while (ss >> i)
{
vect.push_back(i);
if (ss.peek() == ',')
ss.ignore();
}
for (i=0; i< vect.size(); i++)
std::cout << vect.at(i)<<std::endl;
//cout << line << '\n';
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
How can I modify it to be able to extract each value: name, ID, year, and gender? What am I doing wrong?
Use this function to split each line:
vector<string> split(const string &s, char delim) {
stringstream ss(s);
string item;
vector<string> tokens;
while (getline(ss, item, delim)) {
tokens.push_back(item);
}
return tokens;
}
and your code be like:
// reading a text file
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;
int main () {
string line;
ifstream myfile ("database.txt");
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
std::string str = line;
std::vector<string> vect;
vect = split(str, ',') ;
for (int i=0; i< vect.size(); i++)
std::cout << vect.at(i)<<std::endl;
//cout << line << '\n';
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
With the help of a utility function and a data structure you can simplify this quite easily.
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
std::vector<std::string> splitString( const std::string& stringToSplit, const std::string& delimiter, const bool keepEmpty ) {
std::vector<std::string> results;
if ( delimiter.empty() {
results.push_back( stringToSplit );
return results;
}
std::string::const_iterator itSubStrStart = stringToSplit.begin(), itSubStrEnd;
while( true ) {
itSubStrEnd = std::search( itSubStrStart, stringToSplit.end(), delimiter.begin(), delimiter.end() );
std::string temp( itSubStrStart, itSubStrEnd );
if ( keepEmpty || !temp.empty() )
results.push_back( temp );
if ( itSubStrEnd == stringToSplit.end() )
break;
itSubStrStart = itSubStrEnd + delimiter.size();
}
return results;
}
struct DataEntry {
std::string name;
unsigned id;
unsigned year;
std::string gender;
};
int main() {
std::string line;
std::fstream file;
file.open( "database.txt" );
std::vector<DataEntry> entries;
std::vector<std::string> elements;
while( file >> line ) {
elements = splitString( line, "," );
DataEntry entry;
entry.name = elements[0];
entry.id = std::stoul( elements[1] );
entry.year = std::stoul( elements[2] );
entry.gender = elements[3];
entries.push_back( entry );
}
file.close();
for ( auto& e : entries ) {
std::cout << e.name << " " << e.id << " "
<< e.year << " " << e.gender << '\n';
}
std::cout << "\nPress any key and enter to quit.\n";
std::cin.get();
return 0;
}
database.txt
John,12345,2010,M
Jane,54321,2012,F
output
John 12345 2010 M
Jane 54321 2012 F
This makes life it a lot easier just by reading in a single line first; then parsing that line of text and from there doing what you will with that data; either storing it to a struct, printing it, manipulating it etc.
Edit
You need to be aware of the fact that when reading in lines of text, and parsing them if you have something like this in your text file:
John Doe,12345,2010,M
It will not give you what you would expect. I'll leave that for you to figure out.

How to read a integer value from a string in C++? [duplicate]

I realize that this question may have been asked several times in the past, but I am going to continue regardless.
I have a program that is going to get a string of numbers from keyboard input. The numbers will always be in the form "66 33 9" Essentially, every number is separated with a space, and the user input will always contain a different amount of numbers.
I'm aware that using 'sscanf' would work if the amount of numbers in every user-entered string was constant, but this is not the case for me. Also, because I'm new to C++, I'd prefer dealing with 'string' variables rather than arrays of chars.
I assume you want to read an entire line, and parse that as input. So, first grab the line:
std::string input;
std::getline(std::cin, input);
Now put that in a stringstream:
std::stringstream stream(input);
and parse
while(1) {
int n;
stream >> n;
if(!stream)
break;
std::cout << "Found integer: " << n << "\n";
}
Remember to include
#include <string>
#include <sstream>
The C++ String Toolkit Library (Strtk) has the following solution to your problem:
#include <iostream>
#include <string>
#include <deque>
#include <algorithm>
#include <iterator>
#include "strtk.hpp"
int main()
{
std::string s = "1 23 456 7890";
std::deque<int> int_list;
strtk::parse(s," ",int_list);
std::copy(int_list.begin(),
int_list.end(),
std::ostream_iterator<int>(std::cout,"\t"));
return 0;
}
More examples can be found Here
#include <string>
#include <vector>
#include <iterator>
#include <sstream>
#include <iostream>
int main() {
std::string input;
while ( std::getline( std::cin, input ) )
{
std::vector<int> inputs;
std::istringstream in( input );
std::copy( std::istream_iterator<int>( in ), std::istream_iterator<int>(),
std::back_inserter( inputs ) );
// Log process:
std::cout << "Read " << inputs.size() << " integers from string '"
<< input << "'" << std::endl;
std::cout << "\tvalues: ";
std::copy( inputs.begin(), inputs.end(),
std::ostream_iterator<int>( std::cout, " " ) );
std::cout << std::endl;
}
}
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
using namespace std;
int ReadNumbers( const string & s, vector <int> & v ) {
istringstream is( s );
int n;
while( is >> n ) {
v.push_back( n );
}
return v.size();
}
int main() {
string s;
vector <int> v;
getline( cin, s );
ReadNumbers( s, v );
for ( int i = 0; i < v.size(); i++ ) {
cout << "number is " << v[i] << endl;
}
}
// get string
std::string input_str;
std::getline( std::cin, input_str );
// convert to a stream
std::stringstream in( input_str );
// convert to vector of ints
std::vector<int> ints;
copy( std::istream_iterator<int, char>(in), std::istream_iterator<int, char>(), back_inserter( ints ) );
Here is how to split your string into strings along the spaces. Then you can process them one-by-one.
Generic solution for unsigned values (dealing with prefix '-' takes an extra bool):
template<typename InIter, typename OutIter>
void ConvertNumbers(InIter begin, InIter end, OutIter out)
{
typename OutIter::value_type accum = 0;
for(; begin != end; ++begin)
{
typename InIter::value_type c = *begin;
if (c==' ') {
*out++ = accum; accum = 0; break;
} else if (c>='0' && c <='9') {
accum *= 10; accum += c-'0';
}
}
*out++ = accum;
// Dealing with the last number is slightly complicated because it
// could be considered wrong for "1 2 " (produces 1 2 0) but that's similar
// to "1 2" which produces 1 0 2. For either case, determine if that worries
// you. If so: Add an extra bool for state, which is set by the first digit,
// reset by space, and tested before doing *out++=accum.
}
Try strtoken to separate the string first, then you will deal with each string.

Quickest Way to parse a string of numbers into a vector of ints

I'm wondering what the quickest way to parse a string of numbers into a vector of ints. My situation is that I will have millions of lines of data, formatted like this:
>Header-name
ID1 1 1 12
ID2 3 6 234
.
.
.
>Header-name
ID1 1 1 12
ID2 3 6 234
.
.
.
I would like to discard the "Header-name" field (or maybe use it for sorting later on), and then ignore the ID field and then place the remaining three ints into a vector.
I realize that I could just used boost split and then lexical cast in a couple of for loops with logic to ignore certain data, but I'm not sure if that will give me the quickest solution. I've looked at boost spirit but I don't really understand how to use it. Boost or STL are all ok.
Do you have to use boost?
I've used this function for a while. I believe I got it out of Accelerated C++ and have used it since. Your delimiter seems to be a tab, or multiple white spaces. If you pass the delimiter a " " it might work. I think it will depend on what's actually there though.
std::vector<std::string> split( const std::string& line, const std::string& del )
{
std::vector<std::string> ret;
size_t i = 0;
while ( i != line.size() ) {
while ( ( i != line.size() ) && ( line.substr(i, 1) == del ) ) {
++i;
}
size_t j = i;
while ( ( j != line.size() ) && ( line.substr(j, 1) != del ) ) {
++j;
}
if ( i != j ) {
ret.push_back( line.substr( i, j - i ) );
i = j;
}
}
return ret;
}
You can get each line with this:
int main() {
std::string line;
std::vector<std::string> lines;
while ( std::getline( std::cin, line ) ) {
lines.push_back( line );
}
for ( auto it = lines.begin(); it != lines.end(); it++ ) {
std::vector<string> vec = split( (*it) );
// Do something
}
}
You can get it to return std::vector with a quick modification.
Make each string an int with atoi( myString.c_str() )
Also you'll want to put a check in to skip the headers. Should be trivial.
Note that I've not compiled that above. ;)
On this specific problem, if you want the quickest, I would recommend manual parsing 1 char at a time. Boost Spirit would probably come as a close second and save you lots of ugly code.
Manual parsing one char at a time is key to high speed, as even well optimized converters like atoi and strtol have to deal with many different numeric representations while your example seems to imply that you are only interested in plain unsigned integers. Formatted IOs (scanf, operator<<, etc.) are very slow. Reading lines into intermediate strings will probably have a visible cost.
Your problem is simple enough to parse manually, assuming that the header lines do not contain any '\t' (and assuming that there aren't any IO or format errors):
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
std::vector<unsigned> parse(std::istream &is)
{
bool skipField = true;
char c;
unsigned value = 0;
std::vector<unsigned> result;
while (is.get(c))
{
if (('\t' == c) || ('\n' == c))
{
if (!skipField)
{
result.push_back(value);
}
skipField = ('\n' == c);
value = 0;
}
else if (!skipField)
{
value *= 10;
value += (c - '0');
}
}
return result;
}
int main()
{
const std::string data = ">Header-name\nID1\t1\t1\t12\nID2\t3\t6\t234\n";
std::istringstream is(data);
const std::vector<unsigned> v = parse(is);
for (unsigned u: v)
{
std::cerr << u << std::endl;
}
}
As always, with delightfully underspecified questions like this, there's not a lot more than just showing "a way" to do "a thing". In this case, I used Boost Spirit (because you mentioned it):
Parsing into flat containers
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted.hpp>
#include <map>
std::string const input(
">Header - name1\n"
"ID1 1 1 12\n"
"ID2 3 6 234\n"
">Header - name2\n"
"ID3 3 3 14\n"
"ID4 5 8 345\n"
);
using Header = std::string;
using Container = std::vector<int>;
using Data = std::map<Header, Container>;
int main()
{
namespace qi = boost::spirit::qi;
auto f(input.begin()), l(input.end());
Data data;
bool ok = qi::phrase_parse(f, l,
*(
'>' >> qi::raw[*(qi::char_ - qi::eol)] >> qi::eol
>> *(!qi::char_('>') >> qi::omit[qi::lexeme[+qi::graph]] >> *qi::int_ >> qi::eol)
), qi::blank, data);
if (ok)
{
std::cout << "Parse success\n";
for (auto const& entry : data)
{
std::cout << "Integers read with header '" << entry.first << "':\n";
for (auto i : entry.second)
std::cout << i << " ";
std::cout << "\n";
}
}
else
{
std::cout << "Parse failed\n";
}
if (f != l)
std::cout << "Remaining input: '" << std::string(f, l) << "'\n";
}
Prints
Parse success
Integers read with header 'Header - name1':
1 1 12 3 6 234
Integers read with header 'Header - name2':
3 3 14 5 8 345
Parsing into nested containers
Of course, if you wanted separate vectors for each line (don't expect efficiency) then you can simply replace the typedef:
using Container = std::list<std::vector<int> >; // or any other nested container
// to make printing work without further change:
std::ostream& operator<<(std::ostream& os, std::vector<int> const& v)
{
os << "[";
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(os, " "));
return os << "]";
}
Prints
Parse success
Integers read with header 'Header - name1':
[1 1 12 ] [3 6 234 ]
Integers read with header 'Header - name2':
[3 3 14 ] [5 8 345 ]
You can use something like the following only instead of the string array I used you will get strings from a file
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
int main()
{
std::string s[] = { "ID1 1 1 12", "ID2 3 6 234" };
std::vector<int> v;
for ( const std::string &t : s )
{
std::istringstream is( t );
std::string tmp;
is >> tmp;
v.insert( v.end(), std::istream_iterator<int>( is ),
std::istream_iterator<int>() );
}
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The output is
1 1 12 3 6 234
As for the header then you can check whether tmp is a header and if so you will skip this record.
Here is a simplified version
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
int main()
{
std::string s[] =
{
"ID1 1 1 12",
">Header-name",
"ID2 3 6 234"
};
std::vector<int> v;
for ( const std::string &t : s )
{
std::istringstream is( t );
std::string tmp;
is >> tmp;
if ( tmp[0] == '>' ) continue;
v.insert( v.end(), std::istream_iterator<int>( is ),
std::istream_iterator<int>() );
}
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The output will be the same as above.

Counting the tokens when you tokenize the string in C++?

Java has this easy method to count the tokens that you tokenize:
import java.util.*;
public class Program
{
public static void main(String[] args)
{
String str =
"This is/some text/that I am/parsing/using StringTokenizer/.";
StringTokenizer strTok =
new StringTokenizer(str, "/", false);
System.out.println("Count...");
System.out.println(strTok.countTokens());
}
}
Output:Count...6
Is there any easy way to do in C++?
You could use std::istringstreamclass along with function std::getline. For example
#include <iostream>
#include <sstream>
#include <string>
int main()
{
char s[] = "This is/some text/that I am/parsing/using StringTokenizer/.";
std::istringstream is( s );
size_t count = 0;
std::string line;
while ( std::getline( is, line, '/' ) ) ++count;
std::cout << "There are " << count << " tokens" << std::endl;
}
The output is
There are 6 tokens
Or
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main()
{
char s[] = "This is/some text/that I am/parsing/using StringTokenizer/.";
std::istringstream is( s );
std::vector<std::string> v;
std::string line;
while ( std::getline( is, line, '/' ) ) v.push_back( line );
std::cout << "There are " << v.size() << " tokens" << std::endl;
}
To build again the string from the vector you could use for example the following code
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main()
{
char s[] = "This is/some text/that I am/parsing/using StringTokenizer/.";
std::istringstream is( s );
std::vector<std::string> v;
std::string line;
while ( std::getline( is, line, '/' ) ) v.push_back( line );
std::cout << "There are " << v.size() << " tokens" << std::endl;
std::string s1;
bool first = true;
for ( const std::string &t : v )
{
if ( first ) first = false;
else s1 += '/';
s1 += t;
}
std::cout << s1 << std::endl;
}
Or you could use standard algorithm std::replace declared in header <algorithm> to replace one delimeter to another in the original string.
If your compiler does not support the range based for loop then you can write instead
for ( std::vector<std::string>::size_type i = 0; i < v.size(); i++ )
{
if ( i != 0 ) s1 += '/';
s1 += v[i];
}
You could try this:
std::vector<std::string> v(std::istream_iterator<std::string>(std::cin), {});
std::cout << "Count..." << v.size() << "\n";
This will of course tokenize at spaces, not at arbitrary separators. To split on arbitary separators, we need std::getline, but now we don't have an easy istream_iterator. Thankfully, this is a solved problem. So we write:
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
namespace detail
{
template <char Sep = '\n'>
class Line : public std::string
{
friend std::istream & operator>>(std::istream & is, Line & line)
{
return std::getline(is, line, Sep);
}
};
}
int main()
{
std::vector<std::string> v(std::istream_iterator<detail::Line<'/'>>(std::cin), {});
std::cout << "Count..." << v.size() << "\n";
for (auto const & s : v) std::cout << s << "\n";
}
If you want to tokenize an existing string rather than the standard input, use a string stream, i.e. replace std::cin with iss, where we have:
#include <sstream>
std::istringstream iss(my_input_string);

print out the last 10 lines of a file

I want to have the option to print out the last 10 lines of a textfile . with this program I've been able to read the whole textfile, but I can't figure out how to manipulate the array in which the textfile is saved, any help?
// Textfile output
#include<fstream>
#include<iostream>
#include<iomanip>
using namespace std;
int main() {
int i=1;
char zeile[250], file[50];
cout << "filename:" << flush;
cin.get(file,50); ///// (1)
ifstream eingabe(datei , ios::in); /////(2)
if (eingabe.good() ) { /////(3)
eingabe.seekg(0L,ios::end); ////(4)
cout << "file:"<< file << "\t"
<< eingabe.tellg() << " Bytes" ////(5)
<< endl;
for (int j=0; j<80;j++)
cout << "_";
cout << endl;
eingabe.seekg(0L, ios::beg); ////(6)
while (!eingabe.eof() ){ ///(7)
eingabe.getline(zeile,250); ///(8)
cout << setw(2) << i++
<< ":" << zeile << endl;
}
}
else
cout <<"dateifehler oder Datei nicht gefunden!"
<< endl;
return 0;
}
Try this:
#include <list>
#include <string>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <iterator>
// A class that knows how to read a line using operator >>
struct Line
{
std::string theLine;
operator std::string const& () const { return theLine; }
friend std::istream& operator>>(std::istream& stream, Line& l)
{
return std::getline(stream, l.theLine);
}
};
// A circular buffer that only saves the last n lines.
class Buffer
{
public:
Buffer(size_t lc)
: lineCount(lc)
{}
void push_back(std::string const& line)
{
buffer.insert(buffer.end(),line);
if (buffer.size() > lineCount)
{
buffer.erase(buffer.begin());
}
}
typedef std::list<std::string> Cont;
typedef Cont::const_iterator const_iterator;
typedef Cont::const_reference const_reference;
const_iterator begin() const { return buffer.begin(); }
const_iterator end() const { return buffer.end();}
private:
size_t lineCount;
std::list<std::string> buffer;
};
// Main
int main()
{
std::ifstream file("Plop");
Buffer buffer(10);
// Copy the file into the special buffer.
std::copy(std::istream_iterator<Line>(file), std::istream_iterator<Line>(),
std::back_inserter(buffer));
// Copy the buffer (which only has the last 10 lines)
// to std::cout
std::copy(buffer.begin(), buffer.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
}
Basically, you are not saving the file contents to any array. The following sample will give you a head start:
#include <iostream>
#include <vector>
#include <string>
int main ( int, char ** )
{
// Ask user for path to file.
std::string path;
std::cout << "filename:";
std::getline(std::cin, path);
// Open selected file.
std::ifstream file(path.c_str());
if ( !file.is_open() )
{
std::cerr << "Failed to open '" << path << "'." << std::endl;
return EXIT_FAILURE;
}
// Read lines (note: stores all of it in memory, might not be your best option).
std::vector<std::string> lines;
for ( std::string line; std::getline(file,line); )
{
lines.push_back(line);
}
// Print out (up to) last ten lines.
for ( std::size_t i = std::min(lines.size(), std::size_t(10)); i < lines.size(); ++i )
{
std::cout << lines[i] << std::endl;
}
}
It would probably be wiser to avoid storing the whole file into memory, so you could re-write the last 2 segments this way:
// Read up to 10 lines, accumulating.
std::deque<std::string> lines;
for ( std::string line; lines.size() < 0 && getline(file,line); )
{
lines.push_back(line);
}
// Read the rest of the file, adding one, dumping one.
for ( std::string line; getline(file,line); )
{
lines.pop_front();
lines.push_back(line);
}
// Print out whatever is left (up to 10 lines).
for ( std::size_t i = 0; i < lines.size(); ++i )
{
std::cout << lines[i] << std::endl;
}
The eof() function does not do what you and it seems a million other C++ newbies think it does. It does NOT predict if the next read will work. In C++ as in any other language, you must check the status of each read operation, not the state of the input stream before the read. so the canonical C++ read line loop is:
while ( eingabe.getline(zeile,250) ) {
// do something with zeile
}
Also, you should be reading into a std::string, and get rid of that 250 value.
Do a circular buffer with 10 slots and while reading the file lines, putting them into this buffer. When you finish thr file, do a position++ to go to the first element and print them all.
Pay attention for null values if the file has less than 10 lines.
Have an array of strings with size 10.
Read the first line and store into the array
Continue reading till the array is full
Once the array is full delete the first entry so that you can enter new line
Repeate step 3 and 4 till the file is finished reading.
I investigate proposed approaches here and describe all in my blog post. There is a better solution but you have to jump to the end and persist all needed lines:
std::ifstream hndl(filename, std::ios::in | std::ios::ate);
// and use handler in function which iterate backward
void print_last_lines_using_circular_buffer(std::ifstream& stream, int lines)
{
circular_buffer<std::string> buffer(lines);
std::copy(std::istream_iterator<line>(stream),
std::istream_iterator<line>(),
std::back_inserter(buffer));
std::copy(buffer.begin(), buffer.end(),
std::ostream_iterator<std::string>(std::cout));
}