47

I have a program that reads hard-coded file-path and I want to make it read file-path from command line instead. For that purpose I changed the code like this:

#include <iostream>

int main(char *argv[])
{
...
}

but, argv[1] variable exposed this way seems to be of type pointer, and I need it as a string. What should I do to convert this command line argument to string?

roschach
  • 8,390
  • 14
  • 74
  • 124
theta
  • 24,593
  • 37
  • 119
  • 159

7 Answers7

49

It's already an array of C-style strings:

#include <iostream>
#include <string>
#include <vector>


int main(int argc, char *argv[]) // Don't forget first integral argument 'argc'
{
  std::string current_exec_name = argv[0]; // Name of the current exec program
  std::vector<std::string> all_args;

  if (argc > 1) {
    all_args.assign(argv + 1, argv + argc);
  }
}

Argument argc is count of arguments plus the current exec file.

masoud
  • 55,379
  • 16
  • 141
  • 208
32

You can create an std::string

#include <string>
#include <vector>
int main(int argc, char *argv[])
{
  // check if there is more than one argument and use the second one
  //  (the first argument is the executable)
  if (argc > 1)
  {
    std::string arg1(argv[1]);
    // do stuff with arg1
  }

  // Or, copy all arguments into a container of strings
  std::vector<std::string> allArgs(argv, argv + argc);
}
Tim Yates
  • 5,151
  • 2
  • 29
  • 29
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
10

No need to upvote this. It would have been cool if Benjamin Lindley made his one-liner comment an answer, but since he hasn't, here goes:

std::vector<std::string> argList(argv, argv + argc);

If you don't want to include argv[0] so you don't need to deal with the executable's location, just increment the pointer by one:

std::vector<std::string> argList(argv + 1, argv + argc);

kayleeFrye_onDeck
  • 6,648
  • 5
  • 69
  • 80
2
#include <iostream>

std::string commandLineStr= "";
for (int i=1;i<argc;i++) commandLineStr.append(std::string(argv[i]).append(" "));
brkeyal
  • 1,317
  • 1
  • 16
  • 22
  • 2
    This would create temporary string objects for no reason at all. `commandLineStr.append(argv[i]).append(" ")` would be much more efficient (`append` returns `*this` to allow this chaining). Also, the default constructor will make the string blank, so the initialization is also wasteful. – Aaron D. Marasco Nov 10 '15 at 18:04
2

I'm not sure if this is 100% portable but the way the OS SHOULD parse the args is to scan through the console command string and insert a nil-term char at the end of each token, and int main(int,char**) doesn't use const char** so we can just iterate through the args starting from the third argument (@note the first arg is the working directory) and scan backward to the nil-term char and turn it into a space rather than start from beginning of the second argument and scanning forward to the nil-term char. Here is the function with test script, and if you do need to un-nil-ify more than one nil-term char then please comment so I can fix it; thanks.

#include <cstdio>
#include <iostream>

using namespace std;

namespace _ {
/* Converts int main(int,char**) arguments back into a string.
@return false if there are no args to convert.
@param arg_count The number of arguments.
@param args      The arguments. */
bool ArgsToString(int args_count, char** args) {
  if (args_count <= 1) return false;
  if (args_count == 2) return true;
  for (int i = 2; i < args_count; ++i) {
    char* cursor = args[i];
    while (*cursor) --cursor;
    *cursor = ' ';
  }
  return true;
}
}  // namespace _

int main(int args_count, char** args) {
  cout << "\n\nTesting ArgsToString...\n";

  if (args_count <= 1) return 1;
  cout << "\nArguments:\n";
  for (int i = 0; i < args_count; ++i) {
    char* arg = args[i];
    printf("\ni:%i\"%s\" 0x%p", i, arg, arg);
  }
  cout << "\n\nContiguous Args:\n";
  char* end = args[args_count - 1];
  while (*end) ++end;
  cout << "\n\nContiguous Args:\n";
  char* cursor = args[0];
  while (cursor != end) {
    char c = *cursor++;
    if (c == 0)
      cout << '`';
    else if (c < ' ')
      cout << '~';
    else
      cout << c;
  }
  cout << "\n\nPrinting argument string...\n";
  _::ArgsToString(args_count, args);
  cout << "\n" << args[1];
  return 0;
}
1

It's simple. Just do this:

#include <iostream>
#include <vector>
#include <string.h>

int main(int argc, char *argv[])
{
    std::vector<std::string> argList;
    for(int i=0;i<argc;i++)
        argList.push_back(argv[i]);
    //now you can access argList[n]
}

@Benjamin Lindley You are right. This is not a good solution. Please read the one answered by juanchopanza.

Careal Manic
  • 212
  • 2
  • 4
  • 5
    Skip the loop and just use the vector constructor. `std::vector argList(argv, argv + argc);` – Benjamin Lindley Mar 11 '13 at 17:27
  • 1
    That's a lot of overhead to extract one string. – Alex Chamberlain Mar 11 '13 at 17:29
  • @BenjaminLindley can you explain what that means? For example, if I didn't want to include `argv[0]`, what would I change in that line? I think this is the kind of initializer being used, but I can't be certain: `initializer_list il, const allocator_type& alloc = allocator_type()` : http://www.cplusplus.com/reference/vector/vector/vector/ – kayleeFrye_onDeck May 25 '18 at 00:40
  • Well, my co-worker hooked me up with an answer to my specific request, at least :) `std::vector args(argv+1, argv + argc);` I didn't realize the first parameter was just a pointer, ergo a single increment would be all that's needed. – kayleeFrye_onDeck May 25 '18 at 00:56
  • @BenjaminLindley can you explain how this code works ? – Aritro Shome Aug 27 '21 at 14:45
1

Because all attempts to print the argument I placed in my variable failed, here my 2 bytes for this question:

std::string dump_name;

(stuff..)

if(argc>2)
{
    dump_name.assign(argv[2]);
    fprintf(stdout, "ARGUMENT %s", dump_name.c_str());
}

Note the use of assign, and also the need for the c_str() function call.

clockw0rk
  • 576
  • 5
  • 26