How would you use an if/then statement using argv[], upon the option/parameter entered?
For example, a.out -d 1 sample.txt versus a.out -e 1 sample.txt.
int main (int argc, char *argv[])
{
ifstream infile(argv[3]);
int c;
int number = 0;
int count = 0;
while ( infile.good() ) {
if (argv[1] == "-d")
{
c = infile.get();
number = atoi(argv[2]);
if (number == count)
{
cout.put(c);
count = 0;
}
else
count++;
}
if (argv[1] == "-e")
{
cout << "entered -e" << endl; //testing code
}
}//end while
}//end main
You can't use the equality operator to compare C-style strings, you have to use std::strcmp:
if (std::strcmp(argv[1], "-d") == 0)
The reason behind that is that the == operator compares the pointers not what they point to.
I hope you want to check the input parameter -d or -e, right?
if that is the case please use strcmp()
if (!strcmp(argv[1],"-d"))
{
count++;
printf("\ncount=%d",count);
}
if (!strcmp(argv[1],"-e"))
{
printf("entered -e"); //testing code
}
The first error is in the very first line of main:
ifstream infile(argv[3]);
You cannot write that because there is no third argument. When you invoke your program like this:
a.out -d 1 < sample.txt
then the command line that the program sees looks like this:
argv[0] = "a.out"
argv[1] = "-d"
argv[2] = "1"
The < sample.txt, by contrast, is interpreted by the shell directly, and the file is streamed to the standard input of your program – and there’s nothing you can do to change that, inside your program.
As for the parsing itself, don’t do it inside the loop which reads the file, do it before and set appropriate flags.
For the actual parsing I’d suggest using a library to spare you a lot of pain. The standard Unix tool is getopt but that’s only got a C interface. There are several C++ libraries, amongst them Boost.Program_Options which is a tad too complex for my taste, though.
The argc/argv comes from C and is rather cumbersome to use, so when more than basic argument passing is done, you can transform the arguments to a vector of strings and work in a C++ style:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
main(int argc, char* argv[])
{
std::vector<std::string> args;
std::transform(argv+1, argv+argc, std::back_inserter(args), [](char* arg){ return std::string(arg); });
if (args.at(1) == "-d") { std::cout << "Arg 1 = -d" << "\n"; }
for (auto& arg: args) { std::cout << "arg: " << arg << "\n"; }
}
Still, you need to check that the argument is present. If this is a basic tool and it is acceptable that the tool aborts when the parameter is not present, then you can access args elements with args.at(x) instead of args[x]
Or check this SO question for an argument parser.
char argv[] is an array of char *
so
if (string(argv[1]) == "-d")
Related
I'm trying to use something like strcmp to compare a command like "Hello 4" and keep the 4 as a variable
Something like this:
if(strcmp(c, "Hello %d") == 0){
int num = %d;
}
You're looking for sscanf, which uses the scanf-style percent encoders you're using and takes a string to parse as its argument (as well as pointers to store the successful parses into).
It returns the number of arguments successfully stored, or a negative number in the case of an EOF error. In your case, we'll consider it a successful parse if we successfully store the one argument. If we get a zero, that's a failed parse, and if we get a negative number, that's a premature EOF, so we want the result of sscanf to be greater than zero.
#include <cstdio>
#include <iostream>
int main() {
const char* c = "Hello 100";
int num;
if (std::sscanf(c, "Hello %d", &num) > 0) {
std::cout << "Success! " << num << std::endl;
} else {
std::cout << "Failure..." << std::endl;
}
}
Note that in the else branch, the num variable won't be assigned, so it will have whatever value your code previously assigned to it (which, in the code sample I've shown here, is nothing at all, hence UB). So be careful not to reference that variable in the failure branch.
Regular expressions are a way to solve this if you're using C++ and not simply compiling C with a C++ compiler.
#include <iostream>
#include <string>
#include <regex>
int main() {
std::string foo = "hello 4";
std::smatch matches;
if (std::regex_match(foo, matches, std::regex("hello (\\d+)"))) {
std::cout << matches[1] << std::endl;
}
return 0;
}
Using regular expressions makes it trivial to account for varying formatting of the string. E.g. What if there are spaces before or after the items we're looking for?
std::regex("\\s*hello\\s+(\\d+)\\s*")
Or maybe we want to do that but also make it case-insensitive.
std::regex("\\s*hello\\s+(\\d+)\\s*",
std::regex_constants::icase)
I am writing a simple program that compares a single character from argv[] to a character in a char array. This is done using a for loop to check if argv[1] is any of the characters in the character array, which is to serve as an input error check.
What I have done to implement this is below:
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
const char validCharacters[] = "abcde01234";
int goodChars = 0;
for (int i = 0; i < sizeof(validCharacters) - 1; i++) {
if (strcmp(argv[1], &validCharacters[i]) == 0) {
cout << "Characters match!" << endl;
goodChars++;
}
}
if (goodChars > 0) {
cout << "Input OK!";
}
else {
cout << "Invalid input!";
}
return 0;
}
I inputted '0' as the value for argv[].
When I was debugging, this, I found that strcmp(argv[1], &validCharacters[i]) returns -1, and that sizeof(argv[1]) returns 4.
Why is it that argv[1] has the size of 4 despite only having '0' entered into it?
I'm certain that this is the reason why my program isn't working and would like to know if there is a way to resolve this problem.
Also, I'm not very experienced in C++, so anything you thing is bad practice, please let me know.
argv is an array of char pointers. In order to compare and get the size of the actual value, you'll have to dereference the char object.
For example, to get the size:
if(*argv[1] == '0'){
// Do Something
}
Checks if the first argument(argv[0] is the command itself), is equal to the character '0'. Here I dereference the char at index 1 of the argv array.
This question already has answers here:
What does int argc, char *argv[] mean?
(12 answers)
Closed 7 years ago.
I wrote this simple code to understand how the argument system works. I dragged a textfile to the .exe file, and get 2 as output instead of 1 as i expected.
Why 2? Is Arg 1 the .exe itself? How can i find out the filenames of the arguments?
#include<iostream>
using namespace std;
int main(int argc, char* argv[])
{
int i = 0;
const int max = 100000;
if (argc > 0)
{
cout<< argc <<endl;
}
cin.get(); cin.get();
return 0;
}
And an additional question. Where can i inform on how to access each argument and use the informations. My goal is to open all files passed as arguments to the .exe.
This is not a duplicate question, i asked why 2 is returned when you pass 1 argument. The question in the Link is another...
argv[0] is normally the name of the program being run, and is counted in argc. If argc >= 2, the first of your text-file names should be in argv[1]. You can simply loop over them...
for (size_t i = 1; i < argc; ++i)
if (std::ifstream infile(argv[i]))
...use infile...
else
std::cerr << "ERROR - unable to open " << argv[i] << '\n';
For more complex requirements, you may want to use getopt() et al if your system provides it, or the boost library equivalents.
According to the C++ Standard (3.6.1 Main function)
...If argc is nonzero these arguments shall be supplied in argv[0]
through argv[argc-1] as pointers to the initial characters of
null-terminated multibyte strings (ntmbs s) (17.5.2.1.4.2) and argv[0]
shall be the pointer to the initial character of a ntmbs that
represents the name used to invoke the program or "".
To output all arguments you can use various approaches as for example
for ( char **s = argv; *s; ++s ) std::cout << *s << std::endl;
for ( int i = 0; i < argc; i++ ) std::cout << argv[i] << std::endl;
#include <algorithm>
#include <iterator>
//...
std::copy( argv, argv + argc, std::ostream_iterator<char *>( std::cout, "\n" ) );
first argument for main is always name of execution file(means .exe file name)
that is why the value of argc is 2 ( 1 for program name and other for your .txt file)
you can check it by printing argv[0]
So i am writing a program that takes in an int, and returns something to do with the bits that represent the int. However, when I put an int in the command line and immediately print it out it, it prints 2.
Why is this happening, and how can I fix it?
~ ./a.out 8
I can only take in one parameter for main:
#include<iostream>
#include<cstdlib>
using namespace std;
void foo (int ii, int x){
static int p;
k= x<<ii;
.
.
}
int main(int x) {
cout << x << endl;
.
.
.
return 0
}
Parameter passing does not work the way you appear to believe it does.
There are precisely two signatures for main that are guaranteed to work:
int main()
and
int main(int argc, char *argv[])
The latter is the one you use when you want to parse command line arguments. Here argc is the argument count, i.e. the number of passed arguments (including the name of the command itself) and the length of argv. argv is an array of C-style strings that holds the arguments.
So, when you call
./a.out 8
then argc is 2, argv[0] is "./a.out", argv[1] is "8", and argv[2] is a null pointer. If you want to use the first command line argument as a number, you have to parse argv[1] with std::istringstream or atoi or similar, as in
#include <iostream>
#include <sstream>
int main(int argc, char *argv[]) {
if(argc < 2) {
std::cerr << "No argument was given.\n";
return -1;
}
std::istringstream parser(argv[1]);
int x;
if(parser >> x) {
std::cout << x << " * 2 = " << x * 2 << '\n';
} else {
std::cerr << "The argument was not a number.\n";
return -2;
}
}
As a side note, because this is not something you can depend upon, this also explains why you get the output 2. When you write
int main(int x) {
x takes the value of argc, and what would have been argv is ignored, for low-level reasons that have to do with the way the arguments are laid out in memory before the jump to main. When you call the program with ./a.out 8, that value is 2, and so x is 2 in your code. This is not guaranteed to work by the C++ standard, but it is likely to happen on all platforms as it did on yours.
I currently have a c++ Linux program that reads a parameter "P" from a file and loads it in RAM for further operations. The file has the following line :
P = 123
I would like the program to take P from shell input instead of the file. I am open to all options, as long as I can manually enter P while connected in SSH.
What I have in mind is something like an input prompt :
sudo myprogram start
enter P value : (I would manually enter "123" here)
Or maybe an argument :
sudo myprogram start 123
It must be simple to do but I do not know how, so any help is greatly appreciated !
If this is the only data that the file has then the file operation is needless.
Simply pass 123 (or whatever) to your C++ program and convert the string into integer.
Assuming you pass the integer as the second argument then:
int p = atoi(argv[2]);
A better option is to use strtol:
char *s, *ptr;
s = argv[1];
int p = strtol(s, &ptr, 10);
If you can't make changes to the C++ code then simply do:
echo "P = 123" > file && myprogram start
If your file has more content and you can't simply do echo then, replace the existing line with new value:
sed -i "s/P = [0-9]*/P = 123/" file && myprogram start
First version (enter from keyboard):
echo -n "enter P value: "
read P
Second version (pass as shell script argument):
P=$1
Third version (learn bash/shell programming):
Advanced Bash-Scripting Guide
BASH Programming - Introduction HOW-TO
and many others
This is basic C++. Take a look at the sample code below or visit the site I copied it from.
#include <iostream>
// When passing char arrays as parameters they must be pointers
int main(int argc, char* argv[]) {
if (argc < 5) { // Check the value of argc. If not enough parameters have been passed, inform user and exit.
std::cout << "Usage is -in <infile> -out <outdir>\n"; // Inform the user of how to use the program
std::cin.get();
exit(0);
} else { // if we got enough parameters...
char* myFile, myPath, myOutPath;
std::cout << argv[0];
for (int i = 1; i < argc; i++) { /* We will iterate over argv[] to get the parameters stored inside.
* Note that we're starting on 1 because we don't need to know the
* path of the program, which is stored in argv[0] */
if (i + 1 != argc) // Check that we haven't finished parsing already
if (argv[i] == "-f") {
// We know the next argument *should* be the filename:
myFile = argv[i + 1];
} else if (argv[i] == "-p") {
myPath = argv[i + 1];
} else if (argv[i] == "-o") {
myOutPath = argv[i + 1];
} else {
std::cout << "Not enough or invalid arguments, please try again.\n";
Sleep(2000);
exit(0);
}
std::cout << argv[i] << " ";
}
//... some more code
std::cin.get();
return 0;
}
}
Don't you simply want to be prompted, within your C++ program, to input the value?
If that is what you want, this simple code will do the job:
#include <iostream>
int main(int argc, char **argv) {
int p = 0;
std::cout << "Enter P value: ";
std::cin >> p;
std::cout << "Entered value: " << p << std::endl;
return 0;
}