Click here to Skip to main content
15,867,704 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,

I have a function which takes the arguments

foo(int argc, char* argv[] which is a portable library which I do not want to edit/patch.

How do I store the argv from main somewhere for later use. So i could do the following.

 myStoredArguments = storeArguments(argc,argv); // Store

    foo(myStoredArguments.getArgc(),myStoredArguments.getArgv()); // Restore
}


The order of the args must be maintained. I did look at

std::string myString* = new std::string[argc] but this did not seem to create an array of strings but rather a string with an array. Hope this makes sense, tired.

Note this will be on gcc as well are microsoft.

Thanks,
Iain
Posted
Updated 3-Mar-11 22:18pm
v2
Comments
Dalek Dave 4-Mar-11 4:19am    
Edited for Readability.

Here is a simple solution:
ACE_ARGV Class Reference
[^] - Builds a counted argument vector (ala argc/argv) from either a string or a set of separate tokens. Can substitute environment variable values for tokens that are environment variable references

To actually parse the command line ACE_Get_Opt Class [^] - This is a C++ wrapper for getopt(3c) and getopt_long(3c).

Regards
Espen Harlinn
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 6-Mar-11 19:01pm    
Very good suggestion, my 5.
--SA
Espen Harlinn 8-Mar-11 11:49am    
Thanks SAKryukov, appreciated :)
Hi Iain,

The simplest is to keep your args in a permanent std::vector<std::string>, can be a static member of a class or a global variable as:
C++
std::vector<std::string> _arguments;

int main(int argc, char * argv[])
{
    _arguments = std::vector<std::string>(argv, argv + argc);
    // ...


Added after Emilio's comment:

Indeed it starts to migrate your code from C to C++, next step will rewrite your foo() function to accept a std::vector<std::string>&

In between, as Emilio's comment points, you would need an adaptor to use your existing foo(), for instance using (VC2010 or gcc 4.5) C++0x lambdas:
C++
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>

std::vector<std::string> _arguments;

void foo(int argc, char* argv[])
{
    std::copy_n(argv, argc, std::ostream_iterator<char*>(std::cout, " "));
    std::cout << std::endl;
}

void CallFoo(std::vector<std::string>& args)
{
    std::vector<const char *> argv(args.size());
    std::transform(args.begin(), args.end(), argv.begin(), [](std::string& str){
        return str.c_str();});
    foo(argv.size(), const_cast<char**>(argv.data()));
}

int main(int argc, char * argv[])
{
    _arguments = std::vector<std::string>(argv, argv + argc);
    CallFoo(_arguments);
    return 0;
}



cheers,
AR
 
Share this answer
 
v2
Comments
Emilio Garavaglia 4-Mar-11 2:10am    
a vector<string> has a completely different memory layout than a char** that is what the OP has to pass to its "foo" function.
How do you extract a char** from a vector<string> ?!?
Alain Rist 4-Mar-11 4:05am    
Yes, needs an adaptor, see my update. cheers.
Sergey Alexandrovich Kryukov 6-Mar-11 19:00pm    
A sound solution (after update), my 5.
--SA
What about (please note error checking left to the reader):
C++
class Args
{
  int _argc;
  char ** _argv;
public:
  Args(int argc, char * argv[])
  {
    _argc = argc;
    if (_argc > 0)
    {
      _argv = new char *[argc];
    }
    for (int n = 0; n < argc; n++)
    {
      _argv[n] = new char[strlen(argv[n])+1];
      strcpy(_argv[n], argv[n]);
    }
  }
  ~Args()
  {
    if (_argc > 0)
    {
      for (int n = 0; n < _argc; n++)
        delete [] _argv[n];
      delete [] _argv;
    }
  }
  int get_argc(){ return _argc;}
  char ** get_argv(){ return _argv;}
};


 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 3-Mar-11 12:23pm    
Not bad, simple, but I would highly prefer std::string, and I believe OP too. My 4 this time.
--SA
CPallini 3-Mar-11 13:12pm    
4 is good for me, thank you. :-)
Anyway, personally, I don't like 'to travel to' std::string if in & out are both char *.
Sergey Alexandrovich Kryukov 3-Mar-11 14:29pm    
Maybe, this is my irrational hatred against null-terminated anything which was one of the most counter-productive inventions of all peoples and times... The scar of bugs and vulnerabilities stretches through whole industry even now.
--SA
Harrison H 3-Mar-11 14:48pm    
I have the same fear
Andrew Brock 3-Mar-11 22:22pm    
I prefer to use the standard char * too, because I make sure my usage of it is safe. Given that the OP is asking a rather simple question tho means that he/she probably wont. 4.
This is one of the case C++ STL is not a good help: using std::string literally means to copy the argv constant C strings on the process stack into the (dynamically allocated) memory of the std::string variables (may be even placed into a dynamically allocated memory of a vector).

What you need is store the int and char** coming from main into two globals and make those globals available to your foo function upon calling.
The function itself expects an array of C strings, (that has a precise memory layout). passing a C++ string vector completely mess-up such layout.

If yopu don't want two globals around, group them into a struct or make a class that let you able to access its members, store it globally (or store it locally to main and store a global pointer to it you initialize during main)

There is also no need to the "copy" and "delete" boililerplate proposed by CPallini: argc and argv (and the related char arrays)will exist for all the life of your program (they sits in the stack just under it). You don't need to create new copies nor to delete them.
 
Share this answer
 
Comments
Alain Rist 4-Mar-11 4:14am    
[using std::string literally means to copy the argv constant C strings on the process stack into the (dynamically allocated) memory of the std::string variables]
This is not true with modern compilers implementing the move semantics, VC2010 and ggc 4.5 by now. cheers, AR
Emilio Garavaglia 4-Mar-11 8:08am    
The "move semantics" is another thing respect to what I was discussing ... you cannot "move" something that is on the stack!
And, in any case, vector<string> does not convert into char** that is what the OP needs.
CPallini 4-Mar-11 4:27am    
You don't need to copy just if you're sure (OP is probably sure, I agree on this) they will be always the ones passed to the main function.
Sergey Alexandrovich Kryukov 6-Mar-11 19:05pm    
I rather agree with CPallini.

Basically, Emilio is right (argv is not to be muted, this is the key) but his criticism against using std is not completely valid: after all, this is also a matter of convenience and uniform approach if the whole product uses std. I up-voted the Answer by CPallini and did not vote for this Answer.

--SA
Emilio Garavaglia 7-Mar-11 2:07am    
Don't forget the OP wants a char** to pass to an already existent function. All STL based proposal uses vector<string>, that have a completely different layout.
Carlo didn't use STL. Just coyed the main parameters into a RAII class offering the same memory layout (char*[]), for which the STL doesn't have equvalents.

See Alan update to his answer: Certainly now it works, but ... we come with a char** to pass later to a function that wants a char**.
Why the hell do we have to transform a C layout into a C++ data structure to re-transform it back into a C layout (adding a one more vector)?
Don't make C++ (a STL) a religion. This case (an I underline This case) is simply not the case.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900