Console main Input - c++

Okay Some may remember me from earlier, I am fairly new to programming so I may seem not up to par with many others. However at the moment, i am very much stuck.
int main(int argc, char* argv[]) {
string temp,input,output;//store input from file, and get which file//
ofstream out("output.txt");
if(argc == 3)
{
if(ifstream(argv[2]))
{
input = argv[2];
ifstream in(input);
while(in.good())
{
in >> temp;
ReverseWord(temp);
cout << temp << endl;
out << temp << endl;
}
out.close();
in.close();
}
}
}
This code right here is meant to reverse the letter order of words that it takes in from a file by typing "revstr < input.txt" with input.txt being the file name. however at the moment the program just opens and closes right away without anything happening and nothing being typed into the console. does anyone know how to fix this?

If you call your program as revstr < input.text your main() function will be called (on usual platforms) with:
argv = { "revstr", NULL }
argc = 1
In this case you get the contents of input.txt by reading from std::cin. That is what 'input readirection' means: your standard input stream is redirected to read from a file rather than the keyboard (aka terminal) device. No need to deal with the filename in that case.
To pass a filename as argument, use revstr input.txt. That should call main()with
argv = { "revstr", "input.txt", NULL }
argc = 2
so the filename will be available as argv[1].
The behavior in the former case is typically due to command shells, which treat '<' as a redirection directive (which ends the preceding command). You may have expected to get
argv = { "revstr", "<", "input.txt", NULL }
argc = 3
For that you would need to apply some form of quoting or escaping to disable the shell behavior, for example revstr "<" input.txtor revstr \< input.txt. But as far as I understand where you are coming from, you want the redirection. In that case forget about argc and argv and simply read your input from std::cin.

Related

Should I handle multiple instances of cin / stdin?

Below is a little program in C++ which is supposed to act as the cat linux binutil: it gets one or several inputs as detailed in the command line arguments (possibly specifying stdin via '-') and copy them onto the standard output. Unfortunately, it shows an unintended behaviour that I cannot understand the root causes of...
Upon the following command
./ccat - test.text
I hit CTRL-D directly without passing any character. I would expect the program to display anyway the content of test.txt, but instead, the program exits without passing any more characters onto the standard output stream.
Any idea on how I should correct my code below to have the correct behaviour in this situation? Should I handle multiple instances of the standard streams (cin, cout...)? If so, do you know how this can be achieved in C++?
Thank you in advance.
/**** ccat.cpp ****/
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main(int argc, char **argv) {
if (argc <= 1) {
cout << cin.rdbuf();
} else {
vector<string> inputs;
for (int i=1; i<argc; ++i) inputs.push_back(argv[i]);
for (auto &in: inputs) {
if (in == "-" || in == "--") {
cout << cin.rdbuf();
}
else {
ifstream *fd = new ifstream(in);
if (!fd->is_open()) cerr << "Cannot open file \'" << in << "\'\n";
else cout << fd->rdbuf();
delete fd;
}
}
}
return 0;
}
I tried the following commands in sequence:
$ ./ccat > test.txt
Let's try this text.
I would expect a correct behaviour.
$ ./ccat - test.txt # I hit CTRL-D directly without passing any character first
$ ./ccat - test.txt
But when I add some characters before hitting CTRL-D... This works fine.
But when I add some characters before hitting CTRL-D... This works fine.
Let's try this text.
I would expect a correct behaviour.
As the example shows, I would expect in any of the two cases (last two shell prompts) that test.txt gets displayed onto the standard output, but this occurs only if I inject characters through the standard input first. Hitting CTRL-D straight away makes the program exit prematurely.
That's overload 10 here;
basic_ostream& operator<<( std::basic_streambuf<CharT, Traits>* sb );
and it says
If no characters were inserted, executes setstate(failbit).
In other words, cout is now in an error state and will not output anything.
Doing
cout.clear();
first of all in the else branch, or last of all in the if branch, should do it.
Note that sending end-of-file to standard input is usually not something you can recover or "restart" from, so you might only be able to use one standard input "section".

C++ input redirection causing error while file arguments work

When I specify an input file as a file argument, like so:
./asm ex1_in
everything works as it should!
However, when I specify an input file using redirection, like so:
./asm < ex1_in
the program throws the error it is supposed to throw when the input file is corrupt or doesn't exist.
This is the part of the code that handles input and file arguments:
int main(int argc, char * argv []) {
ifstream InFile(argv[1], ios::in);
if (!(InFile.is_open())) { /* check file */
fprintf (stderr, "The input file cannot be open or cannot be read. \n");
return 2;
}
if (InFile.is_open()) {
//some stuff
InFile.close();
}
//other stuff
}
I would like to be able to keep using ifstream, as it is very helpful for the rest of the program.
Also, the program is supposed to accept input directly on stdin if no file argument is supplied. Currently, if no file arguments are supplied, it throws the same error, instead of looking for user input.
EDIT: I added a line in main to try to see what's going on, and it looks like when input redirection is used, the program doesn't see argv[1] or anything after it.
cout << argv[0] << " " << argv[1] << " " << argv[2];
prints out only ./asm.
When input redirection isn't used, it prints out:
./asm ex1_in my1_out
You are trying to open argv[1] as a file every time you run the program.
In the first case, argv has a lenght of two (the executable name and the filename) so it opens and does what it needs to do normally, but when you run it redirecting the file to the stdin, argv just contains the executable name, and since argv[1] is a C-style string, it will read everything until it finds a null byte, then pass whatever it read to the std::ifstream constructor, failing each time.
You should use argc to know the number of arguments passed, and use either the file or stdin depending on the number of arguments.

Providing a file path to an input-dependent program

First off, sorry if the title makes no sense. The nature of my question makes it very hard for me to phrase.
I am working on an assignment for my datastructures class and I am completely and totally brand new to c++ due to only having learned Java at my old school. The project is a weather logger that reads in data from a text file climatedata.txt. My teacher has provided us with a main function in the file (that we are NOT allowed to modify in any way) weatherlog.cpp which is below.
#include <iostream>
#include <fstream>
#include "datalogger.h"
using namespace std;
int main(int argc, char** argv) {
datalogger dl;
if (argc != 2) {
cout << "Usage: " << argv[0] << " <datafile>" << endl;
exit(0);
}
// Read the data
char* datafile = argv[1];
ifstream infile(datafile);
int timestamp;
double temperature;
double windspeed;
while (!infile.eof()) {
infile >> timestamp;
infile >> temperature;
infile >> windspeed;
if (!infile.eof()) {
dl.addData(timestamp, temperature, windspeed);
}
}
// Output the report
dl.printReport();
return(0);
}
Initially I was confused as to why the program would never fully execute until I figured out what argc is in the scope of a main function. It seems that he wants me to provide the text file name while compiling so that argc will be 2 instead of 1 (the value I saw when debugging) so that it can actually execute the rest of the program instead of immediately exiting.
My problem is I'm not sure how to provide the program with the text file location. I've looked all over the internet but since I'm not even sure at which stage to provide the file path I haven't had any success. Is that information supposed to be passed when compiling with g++? After successfully compiling when I'm trying to run the executable? What does the terminal command to do so look like?
So I understand that you need to provide a file name in argv (Comment below if I'm incorrect). argv is an array of arguments passed by the commandline, and argc is the amount of arguments passed (automatically set). To do that simply call the program in terminal like this: ./<progam> <file_name>
Example:
compile just as you would a hello world progam.
Call the program weatherlog climatedata.txt.
If your file has spaces in its name either remove them or do this enclose its name in quotes.
argc stores number of passed in parameters, while argv points to parameters.
if (argc != 2) means checking number of input parameters passed in via Console mode. The first parameter is always the program name. From the second parameter you can pass anything you want. char* datafile = argv[1]; means taking the second parameter as data filename.
In short, open Console mode (CMD on Windows, Terminal on Linux) and type something like: yourprogram C:\path\to\climatedata.txt.

How can I detect that input is being redirected in from a file?

I've written a program that takes its first argument and reverses the letters. So, for instance:
revstr cat
Will produce tac.
Now I want this to work when a file is redirected in. So, if filler.txt is a file containing "Now is the time for all good men to come to the aid of their country!", then:
revstr < filler.txt
Should produce:
!yrtnuoc rieht fo dia eht ot emoc ot nem doog lla rof emit eht si woN
But I don't know how to detect that such redirection is occurring!
This is what I've tried - obviously, it's no good. Where am I going wrong?
int main(int argc, char* argv[]) {
string temp,input,output;//store input from file, and get which file//
ofstream out("output.txt");
if(argc == 3)
{
if(ifstream(argv[2]))
{
input = argv[2];
ifstream in(input);
while(in.good())
{
in >> temp;
ReverseWord(temp);
cout << temp << endl;
out << temp << endl;
}
}
else
ReverseWord(argv[2]);
}
else
}
I'm fairly new to C++ and am doing my best to learn.
There are two possible approaches for you (well, you can even support both):
You can accept a file name as command line argument (using a main that accepts arguments), then open an ifstream using this filename as the stream to read from. Users use your program like revstr filename.txt.
You can read your input from std::cin. Then users need to use redirection to pass you the contents of a file. If your program is started using: revstr < filename.txt, then reading from std::cin will read the contents of the file. The program never even sees the filename.
You can support both by reading from an ifstream, if you get an argument, and from cin, if you don't get an argument. The function that does the reading can get the steam passed in as a generic istream&.
You should change your definition of your main() function so that it accepts arguments passed from command line:
int main(int argc, char* argv[])
The first variable will hold the number of command-line arguments provided, the second is a vector whose elements are pointers to NULL-terminated strings. These strings are the command-line arguments themselves. Please keep in mind, that the first string will always be the name of the executable.
For instance, supposing the name of the file to be opened will be passed as the first argument:
int main(int argc, char* argv[])
{
std::string filename;
if (argc > 1)
{
// Oh, there's some command line arguments here...
filename = argv[0];
}
// Go on processing...
}

C++ Read/write file on Unix

I know this is a very specific question. I am compiling a c++ code using g++ compiler on a unix machine.
I have the following one line code to read a text file specified as parameter in C++: test.cc
int main(int argc, char *argv[])
{
ifstream inputfile(argv[1]);
}
Now after compiling with g++, I will call it as:
./test file.txt
But what should I do, if I want to call it as
./test <file.txt
In short how do I do a file read using default input/output
You should check the arguments to main to see if there is an argument given to the program. If it is then you can use that as the file, otherwise you use std::cin.
Here is an example:
void do_something(istream &input)
{
// Read some stuff from the input
}
int main(int argc, char *argv[])
{
if (argc == 1)
do_something(cin);
else if (argc == 2)
do_something(ifstream(argv[1]));
else
{
cout << "Error: Must supply a file\n";
return 1;
}
}
The reason I call another function to read and process the input, is because you can not assign streams, but must use references or pointers. It's also good to put separate tasks in separate functions, because it will increase readability of the code.
When you want to read from standard input, use std::cin instead of opening your own stream.
For example:
std::string s;
std::getline(std::cin, s);
Using < redirects that file to stdin, so you'd get at it via std::cin in c++.
You need instead to read from stdin, da file.
in other words read from the keyboard.
when you pipe stuff in, it will be read as if typed from the keyboard.
You can do what most of the Unix commands do: read from the file if the filename is specified. If the file name is missing read from standard input.
The cin object is already defined in iostream. Just read from cin instead of inputfile.
Perhaps
ifstream &myin;
if (argc>1) {
ifstream* inputfilep = new infstream(argv[1]);
myin = *inputfile;
}
else myin = cin;
/* do your input on myin */
you will need to modify your example to check argc to see if any command line arguments are passed in, as the input redirection is stripped off by the shell so if argc is 0 then read from standard in as given by the other examples, otherwise as your example code.
You don't have to do anything.
Just write your program as if your are reading from the command line.