Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing text file instead of user input as command line argument

I'm trying to figure out how to be able to read in a .txt file as a command prompt argument instead user input. If I have the program

#include <iostream>
#include "cmdline.h"
using namespace std;

int main (int cnt, char * args[]) {
    int a = cmdline_int(args, 1);
    int b = cmdline_int(args, 2);
    cout << "sum = " << a << " + " << b << " = " << a + b << endl;
    return 0;   
}

where the file "cmdline.h" contains

#include <cstdlib>
#include <string>
using namespace std;

int cmdline_int( char* cmdline_a[], int n ) {
  return atoi( cmdline_a[ n ] );
}
char cmdline_char( char* cmdline_a[], int n ) {
  char c = cmdline_a[ n ][0];
  return c;
}

I can run the program as

./program 3 5

and the output will be

sum = 3 + 5 = 8

however if I have a file (textfile.txt) that simply contains those same numbers in list form, i.e.

3
5

and try to run it as

./program < textfile.txt

I get

Segmentation fault

it does the same thing if textfile.txt contains "3 5", though its important that I use a text file in list form anyway. What do I need to change to make "./program textfile.txt" have the same output as "./program 3 5" ?
I'm guessing the problem lies between the int main parenthesis, I'm just not sure what specifically.

like image 326
zeurosis Avatar asked Oct 24 '17 07:10

zeurosis


People also ask

How do you pass values into command line arguments?

To pass command line arguments, we typically define main() with two arguments : first argument is the number of command line arguments and second is list of command-line arguments. The value of argc should be non negative. argv(ARGument Vector) is array of character pointers listing all the arguments.

How can arguments be passed from the command line into your program?

Command line arguments are passed to the main function as argc and argv. Command line arguments are used to control the program from the outside. argv[argc] is a Null pointer. The name of the program is stored in argv[0], the first command-line parameter in argv[1], and the last argument in argv[n].

How do I pass a command line argument in Windows?

For example, entering C:\abc.exe /W /F on a command line would run a program called abc.exe and pass two command line arguments to it: /W and /F. The abc.exe program would see those arguments and handle them internally.

What are command line arguments stored as?

All the command line arguments are stored in a character pointer array called argv[ ]. Total count of command line arguments including file path argument is stored in a integer parameter called argc.


2 Answers

Test program

When you want to check such things, I would recommend first understanding how the application receives them. I would start with the following minimal program:

int main (int argc, char * argv[]) {
  for (int i = 0; i < argc; i++)
    cout << argv[i] << endl;
  return 0;   
}

And execute it

  • ./program 3 5 outputs:

    ./program
    3
    5
    
  • ./program < textfile.txt outputs:

    ./program
    

So now you can see that the issue is with how the txt file is passed to the application. And the reason your application crashes is because you use the arguments without validating that they actually exist!

Explanation

The symbol (<) means opening the file up and attaching it to the standard input (cin) of your application.

./program < textfile.txt is not related to the arguments, instead you have to read it from cin.

Solution using arguments

Use

./program `cat textfile.txt`

The cat command will "replace itself" with the contents of the file and it will work as if you manually wrote it.

Solution using < and cin

When running with ./program < textfile.txt the following will print the numbers:

int a, b;
cin >> a >> b;
cout << a << endl;
cout << b << endl;

Combined solution

This will work for both:

int main (int argc, char * argv[]) {
  int a, b;
  if (argc == 1) { // No extra arguments, read from cin
    cin >> a >> b;
  } else { // Use args
    a = cmdline_int(argv, 1);
    b = cmdline_int(argv, 2);
  }

  // Do something with a,b
  return 0;
}
like image 175
Daniel Trugman Avatar answered Oct 21 '22 15:10

Daniel Trugman


Run your program as:

./program myfile.txt

and use the argv[1] command line parameter to accept the file name instead. Parse accordingly:

#include <iostream>
#include <fstream>
#include <string>

int main(int argc, char* argv[]) {
    if (argc > 1) {
        std::ifstream fs(argv[1]);
        int a, b;
        while (fs >> a >> b) {
            std::cout << a << ' ' << b << '\n';
        }
    } else {
        std::cout << "No arguments." << '\n';
    }
}
like image 21
Ron Avatar answered Oct 21 '22 15:10

Ron