1

I have to test the function

std::vector<std::string> convert_arguments(int argc, char **argv) {
[some code]
return command_arguments;
};

that takes a pointer to an array of command arguments and returns a Vector containing those arguments. The function works well. But I'm having trouble constructing such a pointer myself. The array is an array of strings, i.e. an array of array of chars. As far as I know, the pointer is supposed to point to the first pointer of the pointers pointing to the first letters of the strings (that sounds quite strange). What I need is an exemplary pointer **argv that I can pass to the function to see if it works. I know that there are a lot of similar questions on the internet, but I couldn't really find an answer that works for me. I would be very thankful if you could help me out, because I've been looking for an answer for several hours.

2
  • for (int i = 0; i < argc; ++i) command_arguments.emplace_back(argv[i]); Commented Apr 1, 2021 at 6:54
  • Should the question say, how do I create a UT for this function? Commented Apr 1, 2021 at 7:31

5 Answers 5

2

char** argv is really just a 2 dimensional array. You can create such an array via char** argv = new char*[argc];. Then you can just loop over the argv array with for(int i=0;i < argc; ++i) and assaign whatever string you want to each entry.

Sign up to request clarification or add additional context in comments.

Comments

2

The command line arguments use both conventions to pass the number of arguments:

  • it is explicitely passed in argc
  • the argv array contains a null pointer as its last (useful) element

As you can construct a string for a const char *, code can be as simple as:

std::vector<std::string> convert_arguments(int argc, char **argv) {
    std::vector<std::string> command_arguments;
    for (int i=0; i<argc; i++) {
        command_arguments.push_back(std::string(argv[i]));
    }
    return command_arguments;
}

or (second convention):

std::vector<std::string> convert_arguments(int argc, char **argv) {
    std::vector<std::string> command_arguments;
    for (const char **ix=argv; ix!=nullptr; ix++) {
        command_arguments.push_back(std::string(*ix++));
    }
    return command_arguments;
}

If you want to build such an array for tests, you can easily do it from literal strings:

const char *const_argv[] = { "foo", "fee", "bar", "baz", nullptr};  // add the last null
int my_argc = sizeof(my_argv)/sizeof(*my_argv) - 1;        // but do no count it
char ** my_argv = const_cast<char **>(const_argv);         // cast it

Beware: This code correctly declared const_argv to be an array of pointers to const characters, because a string literal is const, and uses const_cast to be able to pass it to above function. It is harmless because the function never try to change its parameters but the rule is that const_cast should be avoided if possible.

If you really need an array of non const strings, you must build the strings first and then the array:

char a1[] = "foo";
char a2[] = "fee";
char a3[] = "bar";
char a4[] = "baz";
char *argv[] = {a1, a2, a3, a4, nullptr};

2 Comments

I'm really sorry, I think I did a bad job expressing my question. I already have the function convert_arguments, but in order to test it, I need to construct an exemplary array and the pointer I can test the function with. This is what I have trouble with.
Thanks a lot! It now makes sense :)
0

Here the argc stores number of arguments passed and argv stored all the arguments. You can do something like,

std::vector<std::string> vec;
for (int counter=1;counter<argc;counter++)   //0th argument is the program name
{
    vec.push_back(argv[counter]); //push each string into vector
}
return vec;

Comments

0

A one-line version:

std::vector<std::string> convert_arguments(int argc, const char **argv) {
  return std::vector<std::string>(argv + 1, argv + argc);
}

Or even simpler with c++11 above

std::vector<std::string> convert_arguments(int argc, const char **argv) {
  return {argv + 1, argv + argc};
}

Explanation:

We call the constructor for std::vector with two iterator ranges(pointer can be treat as an iterator), since argv is a pointer arry, the left range is argv+1, the right range is argv + argc.

For the std::string constructor, the const char* is passed.

Comments

0

You can achieve this with a pointer of char arrays in the C fashion:

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

using namespace std;

// borrowed from prehistoricpenguin
std::vector<std::string> convert_arguments(int argc, const char **argv) {
  return std::vector<std::string>(argv + 1, argv + argc);
}

bool test1(void) {
    int argc = 5;
    const char *argv[] = {"program_name", "some string", "another", "command", "ok", NULL };
    std::vector<std::string> myexpectedvector =  {"some string", "another","command", "ok" };
    std::vector<std::string> s = convert_arguments(argc, argv);
    return (s == myexpectedvector);
}

int main () {
    std::cout << test1() << std::endl;
}

1 Comment

Thanks good point, I was answering on mobile while outside, not the best to compile and test, I adjusted my answer with a full example

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.