Save argv to vector or string - c++

I need to save all arguments to a vector or something like this. I'm not a programmer, so I don't know how to do it, but here's what I've got so far. I just want to call a function system to pass all arguments after.
#include "stdafx.h"
#include "iostream"
#include "vector"
#include <string>
using namespace std;
int main ( int argc, char *argv[] )
{
for (int i=1; i<argc; i++)
{
if(strcmp(argv[i], "/all /renew") == 0)
{
system("\"\"c:\\program files\\internet explorer\\iexplore.exe\" \"www.stackoverflow.com\"\"");
}
else
system("c:\\windows\\system32\\ipconfig.exe"+**All Argv**);
}
return 0;
}

i need to save all arguments to a vector or something
You can use the range constructor of the vector and pass appropriate iterators:
std::vector<std::string> arguments(argv + 1, argv + argc);
Not 100% sure if that's what you were asking. If not, clarify.

To build string with all argument concatenated and then run a command based on those arguments, you can use something like:
#include <string>
using namespace std;
string concatenate ( int argc, char* argv[] )
{
if (argc < 1) {
return "";
}
string result(argv[0]);
for (int i=1; i < argc; ++i) {
result += " ";
result += argv[i];
}
return result;
}
int main ( int argc, char* argv[] )
{
const string arguments = concatenate(argc-1, argv+1);
if (arguments == "/all /renew") {
const string program = "c:\\windows\\system32\\ipconfig.exe";
const string command = program + " " + arguments;
system(command.c_str());
} else {
system("\"\"c:\\program files\\internet explorer\\iexplore.exe\" \"www.stackoverflow.com\"\"");
}
}

Related

replacing the command line arguments int argc and char** argv with std::vector<std::string>

Following this post, where I have found a temporary workaround for my other problem, I want to know if I can replace the int argc, char** argv with a std::vector<std::string> variable/object.
Consider the imaginary code:
#include <iostream>
#include <CloseLibrary>
void someFunction(int argc, char** argv){
for (int i = 0; i < argc; ++i) {
std::cout << argv[i] << std::endl;
}
}
int myFunc(int argc, char** argv){
someFunction(argc, argv);
return 0;
}
where the CloseLibrary is a closed library that I don't have access to the source code, and the someFunction function from that library demands the int argc, char** argv command line arguments. But for some reason I can't have double pointers char** in my code.
Here in this post something like what I need is proposed, but I don't know how to use that. Can I write the code this way:
#include <iostream>
#include <CloseLibrary>
#include <vector>
void someFunction(int argc, char** argv){
for (int i = 0; i < argc; ++i) {
std::cout << argv[i] << std::endl;
}
}
int myFunc("args", [](std::vector<std::string> args){
std::vector<char *> cstrs;
cstrs.reserve(args.size());
for (auto &s : args) cstrs.push_back(const_cast<char *>(s.c_str()));
someFunction(cstrs.size(), cstrs.data());
return 0;
}
Or maybe there is a more canonical way to do this? I would appreciate it if you could help me find the correct way to do this and understand the solution. Thanks for your help in advance.
P.S.1. The char* argv[] method is ok in the body of the function but not ok in the inputs. I don't know why pybind11 does this!
P.S.2. Here on pybind11 gitter, this was suggested:
void run(const std::vector<std::string>& args) {
for(auto&& e : args) std::cout << e << '\n';
}
P.S.3. Also suggested on pybind11 Gitter:
char** argv = new char*[vec.size()]; // just like malloc(sizeof(char*)*vec.size());
for (int i = 0; i < vec.size(), i++) {
argv[i] = new char[vec[i].size()];
memcpy(argv[i], vec[i].data(), vec[i].size()); // or strcpy
}
You could use the constructor which initializes the vector from a given range, with the argv parameter acts as the starting iterator and argv+argc acting as the ending iterator.
For example, I usually start my main function with:
int main( int argc, char* argv[] )
{
std::vector< std::string > args( argv, argv + argc );
for ( auto s : args )
{
std::cout << s << std::endl;
}
}
Note that this will also capture the first argument (argv[0]) which usually (but not necessarily) hold the name of the application when it is started.
In your case, you would like to do the reverse, build up a contiguous array of char* from a std::vector< std::string >. I would do something like:
std::vector< char* > rargs( args.size(), 0 ); // Initialize N nullptrs.
for ( int i=0; i<args.size(); ++i )
{
std::strcpy( rargs[i], args[i].c_str() ); // One-by-one strcpy them
}
And then you can pass them into a function accepting an argc, argv as
someFunction( rargs.size(), rargs.data() );
For what it's worth ... Taking it completely back to your original problem of not being able to use char** with pybind11, a full working example, scavenged from the pieces you posted is below. Yes, it's not pretty, but working with pointers never is.
#include <pybind11/pybind11.h>
#include <iostream>
#if PY_VERSION_HEX < 0x03000000
#define MyPyText_AsString PyString_AsString
#else
#define MyPyText_AsString PyUnicode_AsUTF8
#endif
namespace py = pybind11;
void closed_func(int argc, char** argv){
for (int i = 0; i < argc; ++i) {
std::cout << "FROM C++: " << argv[i] << std::endl;
}
}
void closed_func_wrap(py::object pyargv11) {
int argc = 0;
std::unique_ptr<char*[]> argv;
// convert input list to C/C++ argc/argv
PyObject* pyargv = pyargv11.ptr();
if (PySequence_Check(pyargv)) {
Py_ssize_t sz = PySequence_Size(pyargv);
argc = (int)sz;
argv = std::unique_ptr<char*[]>{new char*[sz]};
for (Py_ssize_t i = 0; i < sz; ++i) {
PyObject* item = PySequence_GetItem(pyargv, i);
argv[i] = (char*)MyPyText_AsString(item);
Py_DECREF(item);
if (!argv[i] || PyErr_Occurred()) {
argv = nullptr;
break;
}
}
}
// bail if failed to convert
if (!argv) {
std::cerr << "argument is not a sequence of strings" << std::endl;
return;
}
// call the closed function with the proper types
closed_func(argc, argv.get());
}
PYBIND11_MODULE(HelloEposCmd, m)
{
m.def("run", &closed_func_wrap, "runs the HelloEposCmd");
}
Which after compiling can be used as expected:
$ python - a b c d=13
>>> import HelloEposCmd
>>> import sys
>>> HelloEposCmd.run(sys.argv)
FROM C++: -
FROM C++: a
FROM C++: b
FROM C++: c
FROM C++: d=13
>>>

Split command line argument into arguments/a vector using C++

I have a C++ project that was previously receiving multiple command line arguments with code like so:
int main(int argc, char *argv[]) {
for (int i = 1; i < 4; i = i + 1) {
// do some stuff with argv[i]
int in_arg = m[argv[i]];
}
return 0
}
Using this code, an example command line argument might be:
C:\MyFolder\MyExecutable.exe 4 0 1
However, due to plugging this code into a wider project my command line will now have to look like this instead:
C:\MyFolder\MyExecutable.exe 401
How can I split the argument 401 into a vector or similar that is functionally the same as having three input arguments like 4 0 1 so that my line:
int in_arg = argv[i];
...could be repointed to something like:
int in_arg = new_vector[i];
I only dabble with C++, so apologies if I am asking basic questions.
Thanks
If you already know that the 1st argument is the one to use it's simple, copy it to a string and then access it using one of the iteration options given by C++, I'm using a foreach type cycle:
#include <iostream>
#include <vector>
int main(int argc, char** argv)
{
if(argc < 2){
std::cout << "Not enough arguments"; //<-- args check
return 0;
}
std::string s1;
s1 = argv[1]; //<-- copy argument to a string type to use string iterator
std::vector<int> args_vector;
for (char c : s1) {
args_vector.push_back(c - '0'); // convert char to integer and save it in vector
}
for(int i: args_vector){ // print the args in integer format, 1 by 1
std::cout << i << " ";
}
return 0;
}
You could create strings out of the arguments and just go though them character by character:
#include <iostream>
#include <string>
#include <vector>
int cppmain(std::string program, std::vector<std::string> args) {
std::cout << program << " got " << args.size() << " argument(s):\n";
for(auto& arg : args) { // each argument as a string
std::cout << " " << arg << '\n';
for(char ch : arg) { // each char in the current argument
if(ch < 0) continue; // skip negative char:s
int in_arg = m[ch]; // assuming it was: int in_arg = m[*argv[i]];
// use in_arg
}
}
return 0;
}
int main(int argc, char* argv[]) {
//
// string from char*
// |
// V
return cppmain(argv[0], {argv + 1, argv + argc});
// ^ ^
// | |
// vector<string> from char*[]
}

comparison of pointer and integer

#include<fstream>
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
for (int i=1; i<argc ; i++)
{
cout<< argv[i]<< endl;
if( argv[i] == 'all')
cout<<"hey"<< endl;
}
i am passing "1 all emptyfile" through the command files. but i want to compare when argue[i] is equal to all, i want it to print hey
i get this error "Comparison between pointer and integer ('char *' and 'int')" at the if( argv[i] == 'all') anyway i could do it ?
C-style strings can't be compared directly, and even worse, 'all' isn't a string (you probably meant "all", note the quotes).
The C-way to compare them is to use strcmp:
#include <cstring>
if (std::strcmp(argv[i], "all") == 0) { ... }
Since you are using C++, you can use std::string which will allow you to compare strings directly.
#include <iostream>
using namespace std;
int main(int argc, char* argv[]) {
string s = "all";
for (int i=1; i<argc ; i++)
{
cout<< argv[i]<< endl;
if( argv[i] == s)
cout<<"hey"<< endl;
}
}
Note: all is in double-quotes.
Output when you run the program:
>a.exe all
all
hey

How do you use string.erase and string.find?

Why cant i call string.find in string.erase like so: str.erase(str.find(a[1]),str.size())?
edit:code added
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
// html tags
string tags[5]={"<!--...-->","<!DOCTYPE>","<a>","<abbr>","<acronym>"};
//
//check if string exists
int boolStringExists(string a, string b)
{
if(a.find(b)>0)
{
return 1;
}
if(a.find(b)<=0)
{
return 0;
}
}
//erase tag from string a
void eraseTags(string a,string b[])
{
for(int i=0; i<5;i++)
{
int x=(boolStringExists(a,b[i]));
while (x>0)
{
a.erase(a.find(b[i]),b[i].size());
x=(boolStringExists(a,b[i]));
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
fstream file;
file.open("h:\\a.htm");
string k,m;
while(getline(file, k))
m += k ;
eraseTags(m,tags);
return 0;
}
Gives this message: "this application has requested the runtime to terminate it in an unusual way.Please contact the application's support team for more information."
If the string is not found, find returns string::npos, and then your code wouldn't work and will give runtime error. See this gives error : https://ideone.com/NEhqn
So better write this:
size_t pos = str.find(a[1]);
if ( pos != std::string::npos)
str.erase(pos); //str.size() is not needed!
Now this doesn't give error : https://ideone.com/IF2Hy
There's nothing wrong with that call (assuming a[1] exists and is found in str at least once)
#include <iostream>
#include <string>
int main()
{
std::string str = "Hello, world!";
std::string a = "wwwwww";
str.erase(str.find(a[1]), str.size());
std::cout << str << '\n';
}
test run: https://ideone.com/8wibR
EDIT: Your full source code fails to check if b[1] is actually found in str. The function boolStringExists() returns 1 if a.find(b) is greater than zero, and the value of std::string::npos which it returns when b is not found in a IS greater than zero.
To fix this while keeping the rest of your logic intact, change that function to
//check if string exists
bool boolStringExists(string a, string b)
{
return a.find(b) != string::npos;
}
It seems you want to erase everything that comes after str.find(a[1]). In that case you can omit the second argument.
#include <iostream>
#include <string>
int main(int argc, char *argv[]) {
std::string str = "Hello, world!";
std::string needle = "o,";
str.erase(str.find(needle));
std::cout << str << "\n";
}
In this example I used needle instead of a[1], but the principle is the same.

How to run multiple arguments in Cygwin

I've been trying to run a program that will invert the order of a string and to run it, I have to type a second argument in prompt.
int main(int argc, char* argv[])
{
string text = argv[2];
for (int num=text.size(); num>0; num--)
{
cout << text.at(num);
}
return 0;
}
e.g. ./program lorem result: merol
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char* argv[])
{
string text = argv[1];
for (int num=text.size() - 1; num >= 0; num--)
{
cout << text.at(num);
}
return 0;
}
You missed the includes and used string::at wrong. There are size() chars in the string but you start counting at 0. Then the loop has to run until num >= 0 and not num > 0. You also used the wrong index into argv.
This would still be an abomination of C++. A clearer way would be:
#include <iostream>
#include <string>
#include <algorithm>
int main(int argc, char* argv[])
{
std::string text = argv[1];
for(std::string::reverse_iterator it = text.rbegin(); it != text.rend(); ++it) {
std::cout << *it;
}
std::cout << std::endl;
//or if you want further usage of the reversed string
std::reverse(text.begin(), text.end());
std::cout << text;
return 0;
}
I think you're getting an exception because num is out of bounds. size() is returning a value one larger than the biggest valid index into the string, so at() is throwing an exception.