Issues with flushing cout after getting file data - c++

I am trying to write an implementation of rc4. I am reading in plaintext from a file using an ifstream. I noticed that it wasn't outputting at the end of the file, so I tried the various ways of explicitly clearing the buffers. No matter which way (using an endl, appending \n, calling cout.flush()) I try to flush the buffer, I get a segfault. As a sanity check, I replaced my code with an example from the web, which I also tested separately. It works if I put it in its own file and compile it (e.g., it prints out the contents of the file, doesn't segfault, and doesn't require any calls to flush() or endl to do so), but not in my code.
Here is the offending bit of code (which works fine outside of my code; its copied pretty much directly from cplusplus.com)
ifstream is;
is.open("plain");
char c;
while (is.good()) // loop while extraction from file is possible
{
c = is.get(); // get character from file
if (is.good())
cout << c;
// cout.flush();
}
is.close(); // close file*/
Here is the full code: (warning, lots of commented out code)
#include <iostream>
#include <fstream>
#include <string.h>
#include <vector>
using namespace std;
static char s[256], k[256];
//static char *i, *j;
void swap(int m, int n, char t[256]){
char tmp = t[m];
t[m] = t[n];
t[n] = tmp;
}
char getByte(){
static char i(0), j(0);
i = (i+1)%256;
j = (j + s[i])%256;
swap(i, j, s);
return s[(s[i]+s[j]) % 256];
}
int main(int argc, char ** argv){
/*string key = argv[1];*/
if(argc < 4){
cout << "Usage: \n rc4 keyfile plaintextfile outputfile" << endl;
return -1;
}
string key;
ifstream keyfile (argv[1]);
keyfile >> k;
cout << "Key = " << k << endl;
keyfile.close();
/*ifstream plaintextf;
plaintextf.open(argv[2]);*/
ofstream ciphertextf (argv[3]);
for(int q = 0; q < 256; q++){
s[q] = q;
}
int i, j;
for(int m = 0; m < 256; m++){
j = (j + s[m] + k[m % sizeof(k)])%256;
swap(m, j, s);
}
// vector<char> bytes(plaintext.begin(), plaintext.end());
// bytes.push_back('\0');
// vector<char>::iterator it = bytes.begin();
/* char pt;
while(plaintextf.good()){
pt = plaintextf.get();
if(plaintextf.good()){
cout << pt;
ciphertextf <<(char) (pt ^ getByte());
}
} */
ifstream is;
is.open("plain");
char c;
while (is.good()) // loop while extraction from file is possible
{
c = is.get(); // get character from file
if (is.good())
cout << c;
// cout.flush();
}
is.close(); // close file*/
/*// plaintextf.close();
ciphertextf.close();
keyfile.close();
*/
return 0;
}

Additionally, I think the second call to is.good() [ as in if(is.good()) ], would prevent the very last character of the file from being copied.

Related

Why am i getting blank output after writing this filehandling code in c++?

I have made a tester class where I take questions from a question pool text file and put random questions from there to a docx file. I want to know why my code is giving me blank output in the docx file.
my random function is working fine. I am selecting two two questions from three questions file.
Here is my code - `
void test()
{
string line;
fstream question1("questiondesc.txt",ios::in | ios::out | ios::app);
fstream testgen("GeneratedTest.docx",ios::trunc | ios::in | ios::out);
testgen.open("GeneratedTest.docx");
if(!question1.is_open())
{
question1.open("questiondesc.txt");
}
int i,num;
for (i = 0; i < 2; i++) {
num = random(1,12);
for(int i =1;i<=num;i++)
{
getline(question1,line);
}
question1.clear();
question1.seekg(0, ios::beg);
testgen<<line<<endl;
}
question1.close();
ifstream question2("questionmcq.txt");
if(!question2.is_open())
{
question2.open("questionmcq.txt");
}
for (i = 0; i < 2; i++) {
num = random(1,26);
while(num%2==0)
{
num = random(1,26);
}
for(int i =1;i<=num;i++)
{
getline(question2,line);
}
testgen<<line<<endl;
getline(question2,line);
testgen<<line<<endl;
question2.clear();
question2.seekg(0, ios::beg);
}
question2.close();
ifstream question3("questionanalytical.txt");
if(!question3.is_open())
{
question3.open("questionanalytical.txt");
}
for (i = 0; i < 2; i++) {
num = random(1,12);
for(int i =1;i<=num;i++)
{
getline(question3,line);
}
question3.clear();
question3.seekg(0, ios::beg);
testgen<<line<<endl;
}
question3.close();
testgen.close();
}
There are errors in your code. I will show them as a comment in the below listing. Additionally I will show (onw of many, and maybe not the best ) solutions for your problem.
You should break down your problem into smaller pieces and design more functions. Then, life will be easier.
Additionally. You´should write comments. If you write comments, then you will detect the problems by yourself.
Your code with my remarks:
#include <iostream>
#include <fstream>
#include <string>
#include <random>
using namespace std; // NO NEVER USE
int random(int from, int to) {
std::random_device random_device;
std::mt19937 generator(random_device());
std::uniform_int_distribution<int> distribution(from, to);
return distribution(generator);
}
void test()
{
string line; // Line is not initialized an not needed here. Pollutes namespace
fstream question1("questiondesc.txt", ios::in | ios::out | ios::app); // Opening a file with these flags will fail. Use ifstream
fstream testgen("GeneratedTest.docx", ios::trunc | ios::in | ios::out);// Opening a file with these flags will fail. Use ofstream
testgen.open("GeneratedTest.docx"); // File was alread opened and failed. Reopening will not work. It failed alread
if (!question1.is_open()) // Use if "(!question1)" instead. There could be also other error bits
{ // Always check the status of any IO operation
question1.open("questiondesc.txt"); // Will never work. Failer already
}
int i, num; // Variable not initialized and not needed here. Name space pollution
for (i = 0; i < 2; i++) {
num = random(1, 12); // This function was not defined. I redefined it
for (int i = 1; i <= num; i++) // i=1 and i<= reaaly) not i=0 and i<num?
{
getline(question1, line); // Always check status of any IO function
}
question1.clear();
question1.seekg(0, ios::beg);
testgen << line << endl;
}
question1.close(); // The destructor of the fstream will close the file for you
ifstream question2("questionmcq.txt"); // Now you open the file as ifstream
if (!question2.is_open()) // Do check for all possible flags.: If (!question2)
{
question2.open("questionmcq.txt"); // Will not work, if it failed in the first time
}
for (i = 0; i < 2; i++) { // So 2 times
num = random(1, 26);
while (num % 2 == 0) // If numbers are equal
{
num = random(1, 26); // Get an odd number
}
for (int i = 1; i <= num; i++) // Usually from 0 to <num
{
getline(question2, line);
}
testgen << line << endl;
getline(question2, line);
testgen << line << endl;
question2.clear();
question2.seekg(0, ios::beg);
}
question2.close(); // No need to close. Destructor will do it for you
ifstream question3("questionanalytical.txt"); // Now you open the file as ifstream
if (!question3.is_open()) // Wrong check. Check for all flags
{
question3.open("questionanalytical.txt"); // Will not help in case of failure
}
// Now this is the 3rd time with the same code. So, put it into a function
for (i = 0; i < 2; i++) {
num = random(1, 12);
for (int i = 1; i <= num; i++)
{
getline(question3, line);
}
question3.clear();
question3.seekg(0, ios::beg);
testgen << line << endl;
}
question3.close();
testgen.close();
}
int main() {
test();
return 0;
}
And here one possible solution. With functions to handler similar parts of the code:
#include <iostream>
#include <string>
#include <fstream>
#include <random>
#include <vector>
#include <tuple>
// From the internet: https://en.cppreference.com/w/cpp/numeric/random/random_device
int random(int from, int to) {
std::random_device random_device;
std::mt19937 generator(random_device());
std::uniform_int_distribution<int> distribution(from, to);
return distribution(generator);
}
std::string readNthLineFromFile(std::ifstream& ifs, int n) {
// Reset file to the beginning
ifs.clear();
ifs.seekg(0, std::ios::beg);
// Default return string in case of error
std::string result{ "\n*** Error while reading a line from the source file\n" };
// If getline fails or ifs is in fail state, the string will be default
for (; std::getline(ifs, result) && (n != 0); n--);
// Give back the desired line
return result;
}
void generateQuestion(std::ifstream& sourceFileStream, std::ofstream& destinationFileStream, int n, const bool twoLines = false) {
// We want to prevent readin the same question again
int oldLineNumber = 0;
// For whatever reason, do this 2 times.
for (size_t i = 0U; i < 2; ++i) {
// If we want to read 2 consecutive lines, then we should not come up with the last kine in the file
if (twoLines & (n > 1)) --n;
// Get a random line number. But no duplicates in the 2 loops
int lineNumber{};
do {
lineNumber = random(1, n);
} while (lineNumber == oldLineNumber);
// For the next loop execution
oldLineNumber = lineNumber;
// Read the random line
std::string line{ readNthLineFromFile(sourceFileStream, lineNumber) };
// And write it to the destination file
destinationFileStream << line << "\n";
// If we want to read to lines in a row
if (twoLines) {
// Read next line
line = readNthLineFromFile(sourceFileStream, ++lineNumber);
// And write it to the destination file
destinationFileStream << line << "\n";
}
}
}
int main() {
const std::string destinationFilename{ "generatedTest.txt" };
const std::string questions1Filename{ "questiondesc.txt" };
const std::string questions2Filename{ "questionmcq.txt" };
const std::string questions3Filename{ "questionanalytical.txt" };
// Here we store the filenames and if one or 2 lines shall be read
std::vector<std::tuple<const std::string, const size_t, const bool>> source{
{ questions1Filename, 12U, false },
{ questions2Filename, 26U, true },
{ questions3Filename, 12U, false }
};
// Open the destination file and check, if it could be opened
if (std::ofstream destinationFileStream(destinationFilename); destinationFileStream) {
// Now open the first source file and generate the questions
for (const std::tuple<const std::string, const size_t, const bool>& t : source) {
// Open source file and check, if it could be opened
if (std::ifstream sourceFileStream(std::get<0>(t)); sourceFileStream) {
generateQuestion(sourceFileStream, destinationFileStream, std::get<1>(t), std::get<2>(t));
}
else {
std::cerr << "\n*** Error. Could not open source file '" << std::get<0>(t) << "'\n";
}
}
}
else {
std::cerr << "\n*** Error: Could not open destination file '" << destinationFilename << "'\n";
}
return 0;
}

C++ Problem with space detection in an Array String

I'm currently writting a program where I try to filter extra spaces so if there are more than 1 spaces in a row, I discard the rest leaving only one
But this is only the first step because the aim of the program is to parse a txt file with mips assembly instructions.
So far I've opened the file, stored the content in a vector and then stored the vector content in an array. Then I check, if you find a char 2 times in a row shift the array to the left.
The problem is that the code works well for any other letter, except for the space character. (On the code below I test it with the 'D' character and it works)
#include <iostream>
#include <cmath>
#include <fstream>
#include <cstdlib>
#include <vector>
#include <algorithm>
using namespace std;
class myFile {
vector<string> myVector;
public:
void FileOpening();
void file_filter();
};
void myFile::FileOpening() {
string getcontent;
ifstream openfile; //creating an object so we can open files
char filename[50];
int i = 0;
cout << "Enter the name of the file you wish to open: ";
cin.getline(filename, 50); //whatever name file the user enters, it's going to be stored in filename
openfile.open(filename); //opening the file with the object I created
if (!openfile.is_open()) //if the file is not opened, exit the program
{
cout << "File is not opened! Exiting the program.";
exit(EXIT_FAILURE);
};
while (!openfile.eof()) //as long as it's not the end of the file do..
{
getline(openfile, getcontent); //get the whole text line and store it in the getcontent variable
myVector.push_back(getcontent);
i++;
}
}
void myFile::file_filter() {
unsigned int i = 0, j = 0, flag = 0, NewLineSize, k, r;
string Arr[myVector.size()];
for (i = 0; i < myVector.size(); i++) {
Arr[i] = myVector[i];
}
//removing extra spaces,extra line change
for (i = 0; i < myVector.size(); i++) {
cout << "LINE SIZE" << myVector[i].size() << endl;
for (j = 0; j < myVector[i].size(); j++) {
//If I try with this character for example,
//it works (Meaning that it successfully discards extra 'Ds' leaving only one.
// But if I replace it with ' ', it won't work. It gets out of the loop as soon
//as it detects 2 consecutive spaces.
if ((Arr[i][j] == 'D') && (Arr[i][j + 1] == 'D')) {
for (k = j; k < myVector[i].size(); k++) {
Arr[i][k] = Arr[i][k + 1];
flag = 0;
j--;
}
}
}
}
for (i = 0; i < myVector.size(); i++) {
for (j = 0; j < myVector[i].size(); j++) //edw diapernw tin kathe entoli
{
cout << Arr[i][j];
}
}
}
int main() {
myFile myfile;
myfile.FileOpening();
myfile.file_filter();
}
My question is, why does it work with all the characters except the space one, and how do I fix this?
Thanks in advace.
Wow. Many lines of code. I can only recomend to learn more about the STL and algorithms.
You can read the complete file into a vector using the vectors "range"-constructor and std::istream_iterator. Then you can replace one or more spaces in a string by using a std::regex. This is really not complicated.
In the below example, I do all the work, with 2 lines of code in function main. Please have a look:
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <string>
#include <fstream>
#include <regex>
using LineBasedTextFile = std::vector<std::string>;
class CompleteLine { // Proxy for the input Iterator
public:
// Overload extractor. Read a complete line
friend std::istream& operator>>(std::istream& is, CompleteLine& cl) { std::getline(is, cl.completeLine); return is; }
// Cast the type 'CompleteLine' to std::string
operator std::string() const { return completeLine; }
protected:
// Temporary to hold the read string
std::string completeLine{};
};
int main()
{
// Open the input file
std::ifstream inputFile("r:\\input.txt");
if (inputFile)
{
// This vector will hold all lines of the file. Read the complete file into the vector through its range constructor
LineBasedTextFile text{ std::istream_iterator<CompleteLine>(inputFile), std::istream_iterator<CompleteLine>() };
// Replace all "more-than-one" spaces by one space
std::for_each(text.begin(), text.end(), [](std::string& s) { s = std::regex_replace(s, std::regex("[\\ ]+"), " "); });
// For Debug purposes. Print Result to std::out
std::copy(text.begin(), text.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
}
return 0;
}
I hope, I could give you some idea on how to proceed.

Read binary file and count specific number c++

Hey everyone I've been looking everywhere for insight on how to do this particular assignment. I saw something similar but it didn't have a clear explanation. I'm trying to read a bin file and count the number of times a specific number appears. I saw examples of this using a .txt file and it seemed very straight forward using getline. I tried to replicate the similar structure but using a binary file.
int main() {
int searching = 3;
int counter = 0;
unsigned char * memblock;
long long int size;
//open bin file
ifstream file;
file.open("threesData.bin", ios:: in | ios::binary | ios::ate);
//read bin file
if (file.is_open()) {
cout << "it opened\n";
size = file.tellg();
memblock = new unsigned char[size];
file.seekg(0, ios::beg);
file.read((char * ) memblock, size);
while (file.read((char * ) memblock, size)) {
for (int i = 0; i < size; i++) {
(int) memblock[i];
if (memblock[i] == searching) {
counter++;
}
}
}
}
file.close();
cout << "The number " << searching << " appears ";
cout << counter << " times!";
return 0;
}
When I run the program it's clear that it opens but it doesn't count the number I'm searching for. What am I doing wrong?
You seem to be thinking this through but here's how I would go about doing it.
Initialize a buffer with a sensible size.
Cast it to integers, so you can do array[size_t] syntax for simpler arithmetic.
Open the stream, and read while the stream is valid.
Convert the number of read bytes to the number of ints you would expect.
Increment the counter for each character you find that is valid.
Code
#include <fstream>
#include <iostream>
bool check_character(int value)
{
return value == 3;
}
int main(void)
{
// choose the size, cast a pointer as an int type, and initialize
// our counter
static constexpr size_t size = 4096;
char* buffer = new char[size];
int* ints = (int*) buffer;
size_t counter = 0;
// create our stream,
std::ifstream stream("file.bin", std::ios_base::binary);
while (stream) {
// keep reading while the stream is valid
stream.read(buffer, size);
auto count = stream.gcount();
// we only want to go to the last valid integer
// if we expect the file to be only integers,
// we could do `assert(count % sizeof(int) == 0);
// otherwise, we may have trailing characters
// if we have trailing characters, we may want to move them
// to the front of the buffer....
auto chars = count / sizeof(int); // floor division
for (size_t i = 0; i < chars; ++i) {
// false == 0, true == 1, so we can just add
// if the value is 3
counter += check_character(ints[i]);
}
}
std::cout << "Counter is: " << counter << std::endl;
delete[] buffer;
return 0;
}
As NeilButterworth points out, you could also use a vector. I don't really like this, but "meh".
#include <fstream>
#include <iostream>
#include <vector>
/* ellipsed lines */
int main(void)
{
/* ellipsed lines */
static constexpr size_t size = 4096;
std::vector<int> ints;
ints.resize(size / sizeof(int));
char* buffer = (char*) ints.data();
/* ellipsed lines */
/* ellipsed lines */
std::cout << "Counter is: " << counter << std::endl;
// no delete[]
return 0;
}

Returning string from a function causing formatting issues

It's supposed to look like this: http://i.imgur.com/gko501E.png
Instead it looks like this: http://i.imgur.com/ISwqyD8.png
When I take the code out of the function and use it in the main class it works properly. However once I put it in this function the formatting problems occur, it also isn't filtering like it's supposed to. This program is supposed to take user input, store it in a string, remove all non-alphabetical characters, capitalize the vowels, and then space it out based on user defined variables given in the command line. It's also supposed to accept files as input in the command line, such as: 'program 5 8 < file'.
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <cstdlib>
#include <fstream>
#include <sstream>
using namespace std;
//make vowels uppercase
string filter(string input)
{
size_t found = input.find_first_of("aeiou");
while (found != string::npos)
{
if (islower(input[found]))
{
input[found] = toupper(input[found]);
found = input.find_first_of("aeiou", found + 1);
}
}
//Make consonants lowercase
size_t foundLower = input.find_first_of("BCDFGHJKLMNPQRSTVWXYZ");
while (foundLower != string::npos)
{
if (isupper(input[foundLower]))
{
input[foundLower] = tolower(input[foundLower]);
foundLower = input.find_first_of("BCDFGHJKLMNPQRSTVWXYZ", foundLower + 1);
}
}
//remove punctuation
for (int i = 0, len = input.size(); i < len; i++)
{
if (!isalnum(input[i]))
{
input.erase(i--, 1);
len = input.size();
}
}
return input;
}
int main(int argc, char* argv[])
{
int wordSize;
int wordSizeCounter;
int wordCounter = 0;
int rowSize;
//char letter;
wordSize = atoi(argv[1]);
rowSize = atoi(argv[2]);
ifstream inFile;
inFile.open(argv[3]);//open the input file
stringstream strStream;
strStream << inFile.rdbuf();//read the file
string test = strStream.str();//str holds the content of the file
if (!inFile) test = cin.get() ; // Read first character
//Begin filter for files
while (!test.empty())
{
filter(test);
if (test.length() < wordSize) //make sure we don't go out-of-bounds
{
wordSize = test.length();
}
cout << test.substr(0, wordSize);
cout << " ";
if (test.length() >= wordSize) //again, make sure we don't go out-of-bounds
{
test = test.substr(wordSize);
}
else
{
test = " ";
}
wordCounter++;
if (wordCounter == rowSize)
{
cout << std::endl;
wordCounter = 0;
}
if(test.empty())
{
test = cin.get();
}
}
cout << endl;
return 0;
}

Cutting a string into pieces

How can I extract pieces from this string?
I have a file that contains:
0065445 APPLE$456
089464 MANGO$489
0012389 GUAVA$744
What I want to do is input the file line by line, then cut the string into some pieces.
0065455 Will go in a struct a[0].num
APPLE will go in struct a[0].name
456 will go in struct a[0].dollar
And similarly for other lines.
Everything is working fine, but it's not successfully getting the dollar part into its variable.
Here's the code:
#include<cstdlib>
#include<iostream>
using namespace std ;
int main(){
FILE *fp;
fp = fopen("input.txt","r");
char str[80] ;
struct abc{
int num;
char name[20];
int dollar;
};
int i = 0;
while(fgets(str,79,fp)!=NULL){
struct abc a[i] ;
sscanf(str,"%d %[^$]s$%d\n",&a[i].num,a[i].name,&a[i].dollar);
cout <<i+1 <<") Number : "<<a[i].num<<" Name : "<< a[i].name <<" Dollar : "<< a[i].dollar << endl ;
i++;
}
return 0 ;
}
/* These didn't work too.
sscanf(str,"%d %[^$]s %d\n",&a[i].num,a[i].name,&a[i].dollar);
sscanf(str,"%d %[^$]s%d\n",&a[i].num,a[i].name,&a[i].dollar);
sscanf(str,"%d %s$%d\n",&a[i].num,a[i].name,&a[i].dollar);
*/
There's 1 more problem: the first part of string is an int that starts with 0, but the zero is not being accepted in the int. How to do it?
This is working as I want now but still after parasing the string into an int I am not getting the zeroes:
#include<cstdlib>
#include<iostream>
#include<cstring>
using namespace std ;
int main(){
FILE *fp;
fp = fopen("input.txt","r");
char str[80] ;
char temp[80] ;
struct abc{
int num;
char name[20];
int dollar;
};
int i = 0;
int j = 0 ;
while(fgets(str,79,fp)!=NULL){
i = 0;
j = 0 ;
struct abc a[i] ;
char* ptr = 0; // this is used as a helper variable to strtok
ptr = strtok(str, " $\n"); // we specify the delimiters here
while (ptr != NULL)
{
if (j == 0){
strcpy(temp, ptr);
a[i].num = atoi(temp);
}
if (j == 1)
strcpy(a[i].name, ptr);
if (j == 2){
strcpy(temp, ptr);
a[i].dollar = atoi(temp);
}
ptr = strtok(NULL, " $\n");
j++;
}
cout <<i+1 <<") Number : "<<a[i].num<<" Name : "<< a[i].name <<" Dollar : "<< a[i].dollar << endl ;
i++;
}
return 0 ;
}
/* These didn't work either.
sscanf(str,"%d %[^$]s %d\n",&a[i].num,a[i].name,&a[i].dollar);
sscanf(str,"%d %[^$]s%d\n",&a[i].num,a[i].name,&a[i].dollar);
sscanf(str,"%d %s$%d\n",&a[i].num,a[i].name,&a[i].dollar);
*/
Based on the C++ tag, I'd do things a little differently. First I'd overload the stream extractor operator for your abc type:
std::istream &operator>>(std::istream &is, abc &a) {
is >> a.num;
std::getline(is, a.name, '$');
return is >> a.dollar;
}
Then you can use that to read in a file of records, such as:
abc temp;
std::vector<abc> a;
std::ifstream in("input.txt");
while (in >> temp)
a.push_back(temp);
Or, you can use an istream_iterator to initialize a vector directly from the stream:
std::vector<abc> a((std::istream_iterator<abc>(in)),
std::istream_iterator<abc>());
The easiest way to keep the leading zeros on the first number is probably to change it from an int to a std::string.
Use strtok:
Here is a simple code (C only) that prints your strings separately (I recommended a similar solution in another post).
#include <stdio.h>
#include <string.h> // for strcpy and strtok
#include <stdlib.h> // for atoi
int main()
{
char input [25] = "0065445 APPLE$4056"; // input string
// storage for the separate parts of the string
char line[10];
char fruit[10];
char number[10];
char* ptr = 0; // this is used as a helper variable to strtok
ptr = strtok(input, " $\n"); // we specify the delimiters here
int i = 0;
// I'm using i here as a control variable so that during each iteration different part
// of the string is saved
while (ptr != NULL)
{
if (i == 0)
strcpy(line, ptr);
if (i == 1)
strcpy(fruit, ptr);
if (i == 2)
strcpy(number, ptr);
ptr = strtok(NULL, " $\n");
i++;
}
printf("%s %s %s\n", line, fruit, number);
return 0;
}
Some sample output:
$ ./a.out
0065445 APPLE 4056
Is this what you need?
the 0's will not show up when you print the integer a[i].num.
You could make a[i].num a string (char[]) or an integer array. to make the 0's show up. you can parse it as an integer (via atoi(str)), if you need it to be used otherwsie.
#include <iostream>
#include <fstream>
#include <sstream>
struct abc{ int num; std::string name; int dollar; };
int main(int argc, char* argv[]) {
std::ifstream file("input");
abc st1;
std::string l;
while (file >> st1.num >> l) {
if (size_t p = l.find_first_of('$')) {
st1.name = l.substr(0, p);
std::istringstream(l.substr(p+1)) >> st1.dollar;
std::cout << st1.num << " : "
<< st1.name << " : " << st1.dollar << std::endl;
}
}
return 0;
}