Reputation: 372
I want to pass an integer array/vector as shell argument? Below is my last attempt:
#include <iostream>
#include <vector>
#include <string>
//using namespace std;
int main(int argc, const char *argv[])
{
char dummy;
std::vector<int> argument(argc-1);
std::cout<<argc<<std::endl;
for (int i = 1; i <= argc; ++i)
{
dummy=*(*(argv+1)+i);
argument[i-1]=std::stoi(dummy);
}
std::cout<<argument.size()<<std::endl;
return 0;
}
I got error:
error: no matching function for call to ‘stoi(char&)’
Is there any simpler way to do it? basically run program as:
./executable {1, 2, 3, 4, 5}
and intialize an array/vector in programme with those values?
Upvotes: 0
Views: 224
Reputation: 33952
Resolving the compiler error is a waste of time. OP had the right idea initially using std::string dummy;
, so let's stick with that and figure out what went wrong.
First off lets assume 4 arguments: 1 12 123 1234
and examine the range of the 4 loop.
for (int i = 1; i <= argc; ++i)
Because OP starts the loop at 1, I assume they know that the first argument is the command executed. Great start.
But i <= argc
will allow the i
to range from 1 to 5. argv
is valid from 0 to 4. That means undefined behaviour was invoked accessing argv[5]
and Crom only knows what happens after that. Very likely dummy
got loaded with garbage from argv[5]
and std::stoi
could not parse this garbage into an int
. This is only speculation. Determining the behaviour of undefined behaviour is a waste of time. It might be different next time. It might even look like it worked next time.
So the first thing to do is get rid of the out of bounds read.
for (int i = 1; i < argc; ++i)
Now we have an i
with a range of 1 to 4 and everything stays in bounds.
Next, we can clean up
dummy=*(*(argv+1)+i);
since we aren't tying to fit it into a char
anymore. The simplest is
std::string dummy(argv[i]);
which declares string
dummy
and initializes it to contain one command line argument. Can this be done faster? Yeah, but this is stupidly easy to read. Start with easy and only go into the difficult if easy doesn't meet the program requirements. The only change I would make here until forced is change dummy
to a more descriptive name.
Even simpler you could
argument[i-1]=std::stoi(argv[i]);
But I prefer the dummy
approach at least for now. It has a major debugging advantage: You can print or use the debugger to inspect the value of dummy
before std::stoi
throws an exception because dummy
can't be converted.
The resulting code:
int main(int argc, const char *argv[])
{
std::vector<int> argument(argc-1);
std::cout<<argc<<std::endl;
for (int i = 1; i < argc; ++i)
{
std::string dummy(argv[i]);
argument[i-1]=std::stoi(dummy);
}
std::cout<<argument.size()<<std::endl;
return 0;
}
called with ./executable 1 12 123 1234
the output will be
5
4
5 input arguments and 4 items in the vector because the command is discarded.
Figuring out how to handle the curly braces in
./executable {1, 2, 3, 4, 5}
I'm going to leave to OP to figure out.
Upvotes: 2
Reputation: 379
No need to make complex simply use
argument[i-1]=std::stoi(argv[i]); in place of
dummy=*(*(argv+1)+i);
argument[i-1]=std::stoi(dummy);
we know that array of size n stores element from location 0 to location n-1. argc is the number of strings when you run the program including your executable file name we know that argv is array of strings(character sequence) so at location zero in argv is a executable file name. that is why start for loop from location i=1, and we need to run for loop i=1 to i < argc( means till i<=argc-1)
try following program
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main(int argc, const char *argv[])
{
char dummy;
std::vector<int> argument(argc-1);
std::cout<<argc<<std::endl;
for (int i = 1; i < argc; ++i)
{
// dummy=*(*(argv+1)+i);
// argument[i-1]=std::stoi(dummy);
argument[i-1]=std::stoi(argv[i]);
}
std::cout<<argument.size()<<std::endl;
return 0;
}
Upvotes: 1