C++, command line, parameters - c++

I am starting my c++ program from command line:
program input_file1 input_file2 output_file
where
int main( int argc, char *argv[] )
{
short indicator= 3;
char input_file1[4096], input_file2[4096], output_file[4096];
char *p_file = NULL;
while ( --argc > 0 ) {
switch (--indicator) {
case 2:
p_file = output_file;
break;
case 1:
p_file = input_file2;
break;
case 0:
p_file = input_file1;
break;
}
for (char *argument = argv[argc]; ; ++argument) {
if (*argument == '\0')
break;
else
*p_file++ = *argument;
}
*p_file = '\0';
}
std::cout << input_file1 << '\n';
std::cout << input_file2 << '\n';
std::cout << output_file << '\n';
}
But with the real arguments
program D:\\data\\file1.txt D:\\data\\file2.txt D:\\data\\file3.txt
in names of the files only the first letter D is stored...
Output:
D
D
D
Thanks for your help...

Ok, so here is the short version:
int main(int argc, char *argv[]) {
if (argc != 2) {
std::cout << "This program requires 1 argument!" << std::endl;
return 1;
}
std::string input_file(argv[1]);
std::cout << input_file << std::endl;
}
You should be able to take it from here.

This is a C problem, not a C++ one, but as it is tagged C++, i will suggest a C++ solution for your problemĀ :
int main( int argc, char *argv[] ) {
std::vector<std::string> args(argv+1, argv+argc);
std::cout << args[0] << '\n' << args[1] << '\n' << args[2] << std::endl;
}
UPDATE using iterators on argv to fill the vector args (thanks Space_C0wb0y)

Rather than copying the arguments, just set the file names to point to the appropriate entry in argv.
int main(int argc, char *argv[]) {
char *input_file1, *input_file2, *output_file;
if (4 > argc)
{
std::cout << "Not enough parameters\n";
return -1;
}
input_file1 = argv[1];
input_file2 = argv[2];
output_file = argv[3];
std::cout << input_file1 << '\n';
std::cout << input_file2 << '\n';
std::cout << output_file << '\n';
}
the contents of argv will exist for as long as the program is running.

*p_file ++ = * argument;
This assigns the first character of arguement to the first character in p_file.
You need to use strcpy, or declare some std::strings instead of arrays of char

Your loop is all wrong. You are looping through characters, not the parameter array. You can do that like this:
for(auto arg = argv + 1; *arg; ++arg)
{
std::cout << (*arg) << '\n'; // *arg is a char*
}
This works because the arguments (if any) start at argv + 1 and because they are null terminated so that *arg is nullptr (converts to false) at the end of the argument array.
Your arguments are obtained by dereferencing arg using *arg which is a char*.
So you can do:
if(!std::strcmp(*arg, "--help"))
print_help_info();

Related

c++ error: change from command line input to variable input

I want to change from command line input to variable input.
int main(int argc, char *argv[])
{
std::cout << argc << std::endl;
std::cout << argv[0] << std::endl;
std::cout << argv[1] << std::endl;
}
Change to this, but when I want to compile this an error appears.
int main()
{
int argc = 2;
char *argv[] = 0;
argv[0] = "./server";
argv[1] = "127.0.0.1";
}
This error appears: error: array initializer must be an initializer list
char *argv[] = 0;
You have to provide the size of the array, since you did not provide an initializer from which the compiler can deduce the size. Again, from C++11 you cannot have a string-literal bind to char*, use const char*.
int main()
{
constexpr int argc = 2;
const char *argv[argc] = {};
argv[0] = "./server";
argv[1] = "127.0.0.1";
}
You may want to explore good use of std::array<std::string, 2> instead.

Taking parameters on the command line in C++

I've a program that takes two csv files and a checkin date as inputs and renders a certain output. Thus I'd normally run the executable in this manner,
./my_executable file.csv 2015-10-13
However my requirement is to have the usage behave this way
my_executable --input1 ./file1.csv --input2 ./file2.csv --date 2015-08-01
How can I do this. Do I have write the words input1, input2 and date somewhere in my code. Any help appreciated.
Simplest way I can think of:
Live On Coliru
#include <string>
#include <vector>
#include <iostream>
#include <iterator>
#include <cassert>
int main(int argc, char *raw_argv[]) {
using namespace std;
vector<string> const args { raw_argv+1, raw_argv+argc };
assert(args.size() < 1 || args[0] == "--input1");
assert(args.size() < 3 || args[2] == "--input2");
if (args.size() > 4) {
std::string const& csv1 = args[1];
std::string const& csv2 = args[3];
std::string date = args.size() > 4? args[4] : "(unspecified)";
std::cout << "Arguments received: " << csv1 << ", " << csv2 << " date:" << date << "\n";
}
}
Prints e.g.
./test --input1 stuff.csv --input2 other.csv
Arguments received: stuff.csv, other.csv date:(unspecified)
Command line arguments are passed to your program via the argument count and argument list parameters of main:
int main(int argument_count, char * argument_list[]);
The first parameter is the number of arguments, including the name of your executable.
The second argument is an array of C-style strings, one for each argument (or word) on the command line. The first item is usually the name of the program.
You can always write a small program to test this out:
#include <iostream>
int main(int arg_count, char * arg_list[])
{
for (unsigned int i = 0; i < arg_count; ++arg_count)
{
std::cout << "Argument " << i << ": " << arg_list[i] << std::endl;
}
return EXIT_SUCCESS;
}
Edit 1:
Your parameters would line up as:
Argument 0: my_executable
Argument 1: --input1
Argument 2: ./file1.csv
Argument 3: --input2
Argument 4: ./file2.csv
//...
If you want to compare these parameters, then yes, you would need to type "input1":
//...
std::string arg1 = arg_list[1];
if (arg1 == "--arg1")
{
//...
}
This should give you a kickstart.
https://www.gnu.org/software/libc/manual/html_node/Argp-Example-3.html#Argp-Example-3
or if you want to handle the arguments manually.
see: https://www.gnu.org/software/libc/manual/html_node/Program-Arguments.html#Program-Arguments
int main(int argc, const char **argv[])
{
for(int i = 0; i < argc; i++) {
std::cout << argv[i] << std::endl;
}
return 0;
}
Usually when you give argument in that way the order should not matter, so you'll have to be able to parse the arguments in any order.
Here is a possible solution:
struct arguments
{
std::string input1;
std::string input2;
std::string date;
};
bool parse_arguments(int argc, char** argv, arguments& args)
{
if(argc < 7){ //or set defaults
//print usage();//implement
return false;
}
for(int i=1; i<argc;i+=2){
string command = argv[i];
string argument = argv[i+1];
if(command == "--input1"){
args.input1 = argument;
}
else if(command == "--input2"){
args.input2 = argument;
}
else if(command == "--date"){
args.date = argument;
}
else{
std::cerr<<"Unknown argument: " <<command<<std::endl;
//print usage();
return false;
}
}
if(args.input1.empty() || args.input2.empty() || args.data.empty())
return false;
return true;
}
int main(int argc, char* argv[]){
arguments args;
parse_arguments(argc,argv, args);
//now you can use the struct.
...
}

Checking to make sure argv[1] is an integer c++

For my program I have to make sure the user only inputs a positive INTEGER. for example if the user inputted 12hi it should not run the program and print to std error. I am not quite sure how to implement this.
int main(int argc, char *argv[])
{
if(atoi(argv[1]) < 1)
{
cerr << "ERROR!"<< endl;
return 1;
}
return 0;
}
Pass it to a std::istringstream and ensure all data was processed:
if (a_argc > 1)
{
std::istringstream in(a_argv[1]);
int i;
if (in >> i && in.eof())
{
std::cout << "Valid integer\n";
}
}
See online demo at http://ideone.com/8bEYJq.
Ok, my revised answer. sscanf wasn't behaving how I thought it would and strtol provides the best C-like solution that is very portable.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
for (int i=1; i < argc; i++){
char* end;
long val = strtol(argv[i], &end, 10);
if (argc >= 2 && !end[0] && val >= 0){
printf("%s is valid\n", argv[i]);
} else {
printf("%s is invalid\n", argv[i]);
}
}
return 0;
}
Sample output:
./a.out 10 -1 32 1000 f -12347 +4 --10 10rubbish
10 is valid
-1 is valid
32 is valid
1000 is valid
f is invalid
-12347 is valid
+4 is invalid
--10 is invalid
10rubbish is invalid
This works because strtol will convert the argument to a long int. Then if end[0] is not at the end of the string it will be non-zero meaning it'll throw up an error for 10rubbish but be ok for values like 10. Then of course we only want positive integers and I've included the value 0 in that set.
atoi() by itself is not good enough as it returns zero for failure. 0 could be a valid input.
sscanf() also by itself is not good enough because it'll successfully convert strings like 10rubbish and return the value 10.
I realise op only wants argv[1], this answer scans through all provided args just to show the output of lots of valid and invalid entries.
Since you evidently do not object to using the Standard C library,
the function
long strtol (const char* str, char** endptr, int base)
from <cstdlib> is quite sufficient to ensure that the
commandline argument is a (long) integer numeral with an optional
"-" or "+" prefix, and nothing more than that. You merely need to
check that the char * stored at endptr on return addresses '\0',
which tells you that the function has consumed the entire argument.
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
if (argc < 2) {
return 1;
}
char * endp;
long i = strtol(argv[1],&endp,10);
if (!*endp) {
cout << "The value of \"" << argv[1] << "\" is " << i << endl;
return 0;
}
cerr << "\"" << argv[1] << "\" is not an integer" << endl;
return 1;
}
LATER ...or catering for Steve Jessop's comments:
#include <cstdlib>
#include <iostream>
#include <climits>
using namespace std;
int main(int argc, char *argv[])
{
if (argc < 2) {
return 1;
}
char * endp;
long i = strtol(argv[1],&endp,10);
if (*endp) {
cerr << "\"" << argv[1] << "\" is not an integer :(" << endl;
return 1;
}
if (endp == argv[1]) {
cerr << "Empty string passed :(" << endl;
return 1;
}
if (i < 0) {
cerr << "Negative " << i << " passed :(" << endl;
return 1;
}
if (i <= INT_MAX) {
cout << "Non-negative int " << i << " passed :)" << endl;
} else {
cout << "Non-negative long " << i << " passed :)" << endl;
}
return 0;
}
A wrapper function would be in order for this degree of discrimination. And there
remains the very-very corner case that an input of ULONG_MAX will be accepted
as LONG_MAX.
You can try checking if all the characters in argv[1] are digits (possibly with a leading minus sign). The check can be performed by using the standard library function isdigit().
http://www.cplusplus.com/reference/cctype/isdigit/
Complete solution based on OP's actual code (also available at http://codepad.org/SUzcfZYp):
#include <stdio.h> // printf()
#include <stdlib.h> // atoi()
#include <ctype.h> // isdigit()
int main(int argc, char *argv[])
{
if( argc != 2 ) {
return 0;
}
char * pWord = argv[ 1 ];
char c = 0;
for( int i = 0; c = pWord[ i ], c ; ++i ) {
if( ! isdigit( c ) ) {
return 0;
}
}
int argvNum = atoi( argv[ 1 ] );
printf( "argc = %d, argv[ 1 ] = %s, argvNum = %d\n",
argc, argv[ 1 ], argvNum );
}
I'm new to C++ so please don't flame me if this is wrong, but couldn't you throw an exception and allow the user to re-correct the input?
I've learned a few ways of dealing with errors:
If/Else handling
Assert
Throw exception
1.IF/ELSE
#include
int main(int argc, int **argv) {
if (!isdigit(argv[1])) {
// handle code if it's not a digit.
return 0;
}
}
This is probably the easiest way to make sure
2.ASSERT
#include
int main(int argc, int *argv[]) {
assert(isdigit(argv[1]));
}
* Assert will terminate the program if argv[1] is not a digit
3.THROW
#include
using namespace std;
class Except {};
int main(int argc, int **argv) {
try {
isdigit(argv[1]);
throw Except();
// this code will not be executed
// if argv[1] is not a digit
}
catch (Except) {
cout << "argv[1] is not a digit.";
// handle exception or rethrow
}
}
It is definitely worth noting that throwing an exception will create a stack trace and also all code in-between the thrown exception and the block that catches the exception will NOT be executed.

class assignment help- read input into a parser

Here is a starting point that my instructor has provided us. I am having trouble finding a way to read input from a command in UNIX environment such as "ls" or "hist" using the provided parcer gettoks(). gettoks() is linked from a .l that has the code for the parser. how can toks (which is declared as a pointer to a pointer) be used to pass a line of input into gettoks() that will parse it (i will then return appropriate system call based on the input) ive tried using fget but get a compiler error. Any suggestions would be appreciated.
//*********************************************************
int main( int argc, char *argv[] )
{
// local variables
int ii;
char **toks;
int retval;
// initialize local variables
ii = 0;
toks = NULL;
retval = 0;
// main (infinite) loop
while( true )
{
// get arguments
toks = gettoks();
if( toks[0] != NULL )
{
// simple loop to echo all arguments
for( ii=0; toks[ii] != NULL; ii++ )
{
cout << "Argument " << ii << ": " << toks[ii] << endl;
}
if( !strcmp( toks[0], "exit" ))
break;
}
}
// return to calling environment
return( retval );
}
This the solution which you can use to parse.
int main( int argc, char *argv[] )
{
// local variables
int ii;
for(ii=0;ii<argc;ii++)
{
cout << "Argument " << ii << ": " << argv[ii] << endl;
}
// return to calling environment
return 1;
}

Simplest way to validate a GPS string in C++?

I have some MET data I want to validate which would look something like these:
char validBuffer[] = {"N51374114W1160437"};
char invalidBuffer[] = {"bad data\n"};
char emptyBuffer[] = {""};
I've tried a simple sscanf, but that failed:
int _tmain(int argc, _TCHAR* argv[])
{
char validBuffer[] = {"N51374114W1160437"};
char invalidBuffer[] = {"bad data\n"};
char emptyBuffer[] = {""};
char ns = ' ';
char ew = ' ';
int northing = -999;
int easting = -999;
int paramsConverted = sscanf_s(validBuffer, "%c%d%c%d", &ns, &northing, &ew, &easting);
printf("Converted \"%s\"; Found %d params [%c,%d,%c,%d]\n", validBuffer, paramsConverted, ns, northing, ew, easting);
paramsConverted = sscanf_s(invalidBuffer, "%c%d%c%d", &ns, &northing, &ew, &easting);
printf("Converted \"%s\"; Found %d params [%c,%d,%c,%d]\n", invalidBuffer, paramsConverted, ns, northing, ew, easting);
paramsConverted = sscanf_s(validBuffer, "%c%d%c%d", &ns, &northing, &ew, &easting);
printf("Converted \"%s\"; Found %d params [%c,%d,%c,%d]\n", emptyBuffer, paramsConverted, ns, northing, ew, easting);
getchar();
return 0;
}
gives me:
Converted "N51374114W1160437"; Found 2 params [N,-999,",-1024]
Converted "bad data
"; Found 1 params [b,-999,",-1024]
Converted ""; Found 2 params [N,-999,",-1024]
I'd rather not use any external libraries if at all possible, so is there a nice simple way of doing this without parsing it one character at a time?
How about using Regular expressions from TR1?
char validBuffer[] = {"N51374114W1160437"};
char invalidBuffer[] = {"bad data\n"};
char emptyBuffer[] = {""};
if(strlen(validBuffer)!=18)
{
//Error not valid buffer
}
char ns = validBuffer[0];
char ew = validBuffer[9];
int N = atoi(&validBuffer[1]);
int W = atoi(&validBuffer[10]);
if(N==0 || W==0)
//Error not valid buffer
Not simple not the best but better than nothing
You could use std::stringstream and the stream operators...
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
bool parse(string & s) {
stringstream ss(s);
char n = 0, w = 0;
int x = 0, y = 0;
ss >> n;
if (! ss.good ()) return false;
ss >> x;
if (! ss.good ()) return false;
ss >> w;
if (! ss.good ()) return false;
ss >> y;
if ( ss.bad ()) return false;
cout << "Parsed {" << n << ", " << x << ", "
<< w << ", " << y << "}" << endl;
return true;
}
int main ()
{
string validBuffer = "N51374114W1160437";
string invalidBuffer = "bad data\n";
string emptyBuffer = "";
if (! parse (validBuffer))
cout << "Unable to parse: '" << validBuffer << "'" << endl;
if (! parse (invalidBuffer))
cout << "Unable to parse: '" << invalidBuffer << "'" << endl;
if (! parse (emptyBuffer))
cout << "Unable to parse: '" << emptyBuffer << "'" << endl;
return 0;
}
My output using the above:
Parsed {N, 51374114, W, 1160437}
Unable to parse: 'bad data
'
Unable to parse: ''
Consider a bit specific format parameter for sscanf():
int paramsConverted = sscanf(validBuffer, "%c%8d%c%7d", &ns, &northing, &ew, &easting);