Cannot extract data from command line as expected - c++

I have a courses0.dat file with a single 4 on line 1 that I want to extract with my ifstream program:
void processEnrollments (std::istream& courseFile);
int main (int argc, char** argv)
{
// Take input and output file names from the command line
ifstream coursesIn (argv[1]);
return 0;
}
void processEnrollments (istream& courseFile)
{
int numCourses;
courseFile >> numCourses;
cout << numCourses;
// Create the arrays we need
//!! Insert your code here
}
when I run
program courses0.dat
my test is cout'ing a 32767 instead of a 4. My .dat file is in the same directory as my executable.
any clue as to what is going on?
thanks

Check for errors! Try to use the full path to the file when you pass it as an argument.
My guess is courseFile >> numCourses; fails because ifstream coursesIn (argv[1]) doesn't find or can't access the file.
Try this
if( courseFile >> numCourses )
cout << numCourses;
Does it output anything then?

Related

Why am I getting a seg fault with my if statement?

I want to read a file and count the words. I want it set up so I can use a command line or, if no file is entered on the command line, to trigger an if statement that will get the file name and read it, then count the words. It works if I type the file name in command line, however it seg faults if I don't use it. Here is the code:
int main(int argc, char **argv)
{
char file[75];
if (argc < 2)
{
cout << "Please enter the filename: ";
cin >> file;
strcpy(argv[1], file);
}
string content;
ifstream inFile(argv[1]);
int count = 0;
while (inFile >> content)
count++;
inFile.close();
display(count, argv);
return 0;
}
You should not modify data of argv especially out of bounds. You logic should work opposite:
char file[75];
if (argc < 2)
{
cout << "Please enter the filename: ";
cin >> file;
} else
strcpy( file, argv[1] );
string content;
ifstream inFile(file);
but you better use std::string for variable file as well.
Also cin >> inputs only words (excluding space symbols) but filenames can have them, so you better use cin.getline( file ) or std::getline( cin, file ) if you change file to std::string
If the condition is true that is if argc is indeed less than 2 then in general case argc is equal to 1 and according to the C Standard argv[argc] is equal to NULL.
So the program in this case has undefined behavior.
In any case it is a bad idea to copy a string to argv[n] where n is some index because the source string can be larger than the target string.
You could use a reverse approach that is to copy argv[1] to file.

Reading in from file gives unexpected output

I am working on reading in from a file and parsing through data from command line argument for homework. And I ran in a wall and I do not know what's the problem, and I hope I could get some advice on what I am missing.
The data file is composed thusly; on the first line, it has number of total lines. For each line after that, it is a line of string separated by | character. I need the '|' character because I want to split my string into substrings.
Here is an example of input file.
3
league of legends|Teemo|Master Yi|Vayne
apple|samsung|smart phone|smart watch
overwatch|d.va|junkrat|Reinhart
Here is my code.
int main( int argc, char* const argv[] )
{
//change string to char* so I can check through each char to see if the
//thing I read in is '|' character.
String Data = (argv[1]);
ifstream fin (Data.c_str());
//check whether the file is open.
if ( !fin.is_open() )
{
cout << "Could not open file" << endl;
}
else
{
int dataLines;
char dataBuffer[100];
//The first integer I read in will be how many lines I will loop through
fin >> dataLines;
//ignore the new line character and do not include it in the count of
//dataLines.
fin.ignore();
//use noskipws so I can recognize whitespaces.
fin >> noskipws >> dataBuffer;
//TEST CODE: COMMENTED OUT FOR NOW.
//cout<<dataBuffer<<endl;
//loop for the number of lines
for(int i = 0; i < dataLines; i++)
{
fin.getline(dataBuffer, 100);
//print the buffer for checking
cout<<dataBuffer<<endl;
}
}
//close the file.
fin.close();
return 0;
}
The result is supposed to look like this.
league of legends|Teemo|Master Yi|Vayne
apple|samsung|smart phone|smart watch
overwatch|d.va|junkrat|Reinhart
The actual result looks like this
of legends|Teemo|Master Yi|Vayne
apple|samsung|smart phone|smart watch
overwatch|d.va|junkrat|Reinhart
The first word that I read in from buffer is gone. "league" is the one that is missing, and I tried to see what the problem is by inserting the test code at the location specified in my code. With the given test code, my output is
league
of legends|Teemo|Master Yi|Vayne
apple|samsung|smart phone|smart watch
overwatch|d.va|junkrat|Reinhart
So the problem is that between reading in the file with noskipws and the forloop that loops over dataLine. Before the forloop my buffer is league. Yet once I enter the loop it is passed that and goes straight to of.
What am I missing here? What could be a possible solution?
Main problem:
fin >> noskipws >> dataBuffer;
Does two things. 1. >> noskipws turns off automatically skipping whitespace, unnecessary because of how OP is reading the stream. 2. >> dataBuffer reads the first word from the stream, in this case consuming the word "league"
Solution: Don't do this.
Other problems:
fin.ignore();
will ignore exactly one character. But what if someone left a nigh-invisible space after the count? Instead use
fin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
to ensure the rest of the line is consumed in its entirity.
char dataBuffer[100];
Why make yourself suffer? Instead use
std::string dataBuffer;
Recommendation:
Use std::stringstream and std::getline to tokenize the lines on '|'
std::stringstream stream(databuffer);
std::string token;
while (std::getline(stream, token, '|')
{
std::cout << token << ',';
}
You do not need the following line:
fin >> noskipws >> dataBuffer;
Tested with g++ 4.8.3 2 on RHEL 7.1
Thanks User 4581301. It reads in the data correctly and split with '|' character. Now I can work on storing the data into classes.
for anyone who may have same problem, this is the fixed up version of code.
int main( int argc, char* const argv[] )
{
String Data = (argv[1]);
ifstream fin (Data.c_str());
if ( !fin.is_open() )
{
cout << "Could not open file" << endl;
}
else
{
int dataLines;
char dataBuffer[100];
fin >> dataLines;
fin.ignore();
for(int i = 0; i < dataLines; i++)
{
while(fin.getline(dataBuffer, 100, '|'))
{
cout<<dataBuffer<<endl;// check to see if it reads in correctly.
}
}
}
fin.close();
return 0;
}

Fixing syntax of number of line reading function

I tried making a program earlier that tells the user then number of char, words, and lines in a text file. I made functions to determine the numbers of each, yet I was passing them by value. This resulted in an error since after reading the number of char it would be at the end of the file and then output zero for the other two. Now I cant seem to rewrite my functions so that the file is open and closed each time its checked for char, words, and lines. Any one see where my errors are?? Thanks! (just copied and pasted one of my functions for now).
int num_of_lines(ifstream file)
{
string myfile;
myfile = argv[1];
ifstream l;
l.open(myfile);
int cnt3 = 0;
string str;
while(getline(file, str))cnt3++;
l.close();
return(cnt3);
}
int main(int argc, char **argv)
{
int num_of_char(ifstream file);
string file;
file = argv[1];
if(argc == 1)die("usage: mywc your_file");
ifstream ifs;
ifs.open(file);
if(ifs.is_open())
{
int a, b, c;
a = num_of_lines(ifs);
cout <<"Lines: " << a << endl;
}
else
{
cerr <<"Could not open: " << file << endl;
exit(1);
}
ifs.close();
return(0);
}
There is no way to "reopen" a file other than knowing the name and creating a new ifstream, but you can use the seekg member function to set your read position in the file, and setting it to 0 will have the next read operation start from the beginning of the file.
A stream is not possible to copy, so you can't pass it "by value", but must pass it by reference.
int num_of_lines(ifstream &file)
{
int count = 0;
string str;
while (getline(file, str)) {
count++;
}
file.seekg(0);
return count;
}
For the full problem, I agree with Mats Petersson, though. Counting both characters, lines and words in one pass will be much more efficient than reading through the file three times.

Why is this a never-ending loop?

The file that is being used as input is a .txt file that contains:
Line 1
Line 2
Line 3
Line 4
Line 5
And it is being opened on the 3rd line of my code. Yet the while loop never terminates, continuously print "Pass" to the console, so why is it not finding infile.eof() after the 5th line of text?
int main(int argc, char** argv) {
ifstream infile;
infile.open("TEST.txt", ios::in);
if(infile.is_open()){
while(!infile.eof()){
cout << "Pass" << '\n';
}
}
else{
cout <<"Fail";
}
}
Because you never actually consume (read) anything from infile to advance the file pointer. The code just continually checks for EOF, but doesn't actually read any contents of the file.
As others have pointed out, you don't do anything infile which causes an infinite loop. As to your question of how to do this right, try this:
int main()
{
ifstream infile("TEST.txt", ios::in);
string input;
while(infile)
{
getline(infile, input);
<do something with "input">
}
return 0;
}

Using input redirection, how to read file and get character string in C?

I have a file that I want my program to read from using input redirection from the command line. For example,a.out < file.dat . Then I was going to use cin.get() and put characters in an array.
I don't want to hard code any input file names, which I have been seeing in some of the existing posts. If I treat this input redirection as stdin, do I have to explicitly open my file?
int main (int argc, char *argv[])
{
string filename;
ifstream infile;
cin >> filename;
do {
int c = 0;
c = infile.get(); //need to get one character at a time
//further process
} while ( ! infile.eof());
}
You can just use cin, which is a stream buffer associated with stdin
#include <iostream>
int main()
{
char c;
while (std::cin.get(c))
{
std::cout << c << std::endl; // will print out each character on a new line
}
exit(0);
}