why we use "const char* const* argv" instead of "char *"? [duplicate] - c++

This question already has answers here:
C++ : Meaning of const char*const*
(5 answers)
Closed 6 years ago.
I'm working on simulating computer networks using "NS2 Simulator". I don't really understand why we should use const char* const* argv instead of char *?
Can I use char * instead of that? There are many QA about this subject but I've confused about that. Don't mark this question as "Duplicate", please .
why we use const char* const* argv in the function below? is this a rule in c++ standard? can i use either string or char ** instead of that?
Function Connector::command.
//~ns/common/connector.cc
int Connector::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
...
if (argc == 3) {
if (strcmp(argv[1], "target") == 0) {
...
target_ = (NsObject*)TclObject::lookup(argv[2]);
...
}
...
}
return (NsObject::command(argc, argv));
}

const char*const* argv means "pointer to constant pointer to constant char". It's not the same as char*. There is a reason for the const modifier, as the argv pointer wont be reassigned, the elements will have to be accessed by subscript.
This makes it safe for the caller to dynamically allocate argv, pass it into command(), and free it later. Otherwise, if you point a pointer elsewhere before it is freed, then you've leaked the memory that it used to point to.
const char* const* argv creates two levels of indirection - first level is a const pointer to a const char, and second level is a pointer to the const pointer.

The programmer is allowed to const qualify arguments how they see fit. The benefit of this signature:
void func(const char* const* argv);
...is that it will accept argument arrays (of the type passed to main() or exec()), with any const qualification.
So all these are acceptable:
int main(int, char** argv)
{
func(argv);
}
int main(int, const char** argv)
{
func(argv);
}
int main(int, char* const* argv)
{
func(argv);
}
int main(int, const char* const* argv)
{
func(argv);
}
So if you are writing a function to accept argument array parameters (that your function will not modify) then its probably the best signature to select.

why we should use "const ... argv" instead of "char *" ?
The 'const' is from you, the programmer, commanding the compiler to inform you when the code you write tries to modify argv.
can i use char * instead of that?
Possibly, and sometimes it does not matter. But if you mistakenly modify argv (or whatever the const var name is), then the compiler won't let you know you made a mistake, and the result may be something you do not want, even UB.

Related

How to declare a variable as char* const*?

I have a bluez header file get_opt.h where argv is an argument:
extern int getopt_long (int ___argc, char *__getopt_argv_const *___argv,.....
which requires char* const* for argv. Because the unit is called from a different file I was trying to emulate argv but whatever permutation of declaring char, const and * is used I get unqualified-id or the compiler moans about not converting to char* const*. I can get const char * easily, of course. char const * argv = "0"; compiles OK in Netbeans with C++14 but
char * const * argv = "0";
produces
"error: cannot convert 'const char *' to 'char * const *'" in initialisation (sic).
How do you declare char* const* or am I mixing C with C++ so I'm up the wrong tree?
Let's review the pointer declarations:
char * -- mutable pointer to mutable data.
char const * -- mutable pointer to constant data.
char * const -- constant pointer to mutable data.
char const * const -- constant pointer to constant data.
Read pointer declarations from right to left.
Looking at the descriptions, which kind of pointer do you want?
Because void main(void) is in a different file I was trying to emulate
argv
void main(void) is not the correct main function declaration. The main function has to have int return value.
Simply change the void main(void) to int main(int argc, char **argv) in that "other" file.
It does not require char const * to be passed to. Do not change the type of the main function arguments.
int getopt_long (int ___argc, char * const *___argv);
int main(int argc, char **argv)
{
printf("%d\n", getopt_long(argc, argv));
}
Both language compile fine:
https://godbolt.org/z/5To5T931j
Credit #JaMiT above
[I don't know how to accept a commment]
Also, you might want to notice how you can remove the call to getopt_long() from that example while retaining the error (it's motivation for your declaration, but not the source of your issue). If you think about your presentation enough, you might realize that your question is not how to declare a char* const* but how to initialize it. Due to arrays decaying to a pointer, you could declare an array of pointers (char* const argv[]) instead of a pointer to pointer (char* const * argv). See The 1D array of pointers way portion of A: 2D Pointer initialization for how to initialize such a beast. Beware: given your setup, the "2D array way" from that answer is not an option. Reminder: The last pointer in the argument vector is null; argv[argc] == nullptr when those values are provided by the system to main().

How to declare a pointer to pointer to constant in C++?

I'm trying to write a function to parse command line arguments. This is the function declaration:
void parse(int, char const **);
Just in case, I have also tried (const char)**, const char **, and cchar ** using a typedef const char cchar. However, all of these (as expected, since they should all be identical) result in an error if I pass a char ** into the function, as in:
void main(int argc, char **argv) {
parse(argc, argv);
The error I get from GNU's compiler is error: invalid conversion from 'char**' to 'const char**' and the one from Clang is candidate function not viable: no known conversion from 'char **' to 'const char **' for 2nd argument.
I have seen such solutions suggested as declaring a pointer to a const pointer to char (const char * const *), but I don't want either pointer to be const because I want to be able to modify the pointer so I can iterate over an argument using for(; **argv; ++*argv). How can I declare a "non-const pointer to non-const pointer to const char"?
The function should be declared as:
void parse(int, char const * const *);
In C++, char ** can implicitly add const at all pointer depths, so you can call it as parse(argc, argv).
In C, const can only be added at the first pointer depth (this is a design defect in the language). Here is a dedicated thread. So you have to call the function as: parse(argc, (char const * const *)argv); unfortunately.
The safest signature that prevents modification of the arguments whilst allowing any other const combination to call the function is this:
parse(int argc, char const* const* argv);
That means that argv is a pointer to a const pointer to a const char
You can happily iterate over the parameters like this:
for(auto arg = argv + 1; *arg; ++arg)
{
if(!std::strcmp(*arg, "--help"))
return print_help();
else if(!std::strcmp(*arg, "-v") || !std::strcmp(*arg, "--verbose"))
verbose_flag = true;
// ... etc...
}
Notice there is no need to accept the variable int argc because the array of character arrays is null terminated.
So I normally use this:
struct config
{
// program options and switches
};
config parse_commandline(char const* const* argv);

Convert const std::vector<std::string> to const char **

I have a function with signature like this:
void foo(const std::vector<std::string>& args)
{
...
}
I want convert vector args to const char ** (just like argv in main). How this can be done? We can't actually make a char ** array because then it (obviously) fails to convert args[i].c_str() that is of type const char * to char *.
The only (ugly) way I can think of is to use const_cast to cast from const char * to char *.
Would anyone suggest more elegant way of doing this? I should note I can use only c++03 features.
Thanks in advance.
It can't be done without an extra array. A const char** means "a pointer to a pointer to const char" - so you need a place where there are actual pointers to char to point to.
So you need to create that array.
struct c_str { const char* operator ()(const std::string& s) { return s.c_str(); } };
std::vector<const char*> pointers(args.size());
std::transform(args.begin(), args.end(), pointers.begin(), c_str());
// If you really want to be compatible with argv:
pointers.push_back(0);
// &pointers[0] is what you want now

Pass argv[1] by reference

I've an issue with passing argv to a function. Basically, I want to pass &argv[1] to the function and work from that. However, I don't understand why the following does work:
void fun(char**&argv, const int& argc);
int main(int argc, char** argv)
{
fun(++argv, --argc);
return 0;
}
yet the following doesn't work:
void fun(char**&argv, const int& argc);
int main(int argc, char** argv)
{
fun(&argv[1], --argc);
return 0;
}
Prototype:
void myfunc (char **argv, int argc)
Example usage:
myfunc (argv, argc)
If you wanted to pass ONLY one string (argv[1]):
void myfunc (char *arg, int argc)
...
myfunc (argv[1], argc)
And if you wanted to pass an array of strings starting at argv[1]:
void myfunc (char **arg, int argc)
...
myfunc (&argv[1], argc)
The error I get when I try this is that argv[1] is a temporary value and you can't assign that to a non-const reference. If you instead do this:
void fun( char** const&argv, const int& argc);
Then either ++argv or &argv[1] will work.
Obviously, if you planned to actually change the value of argv itself, this won't work, but I presume that you aren't planning to do this since you're not passing a reference to argv itself but rather to the memory location of the second entry in argv.
The reason that the first one works and the second doesn't is that the ++ operator at the front modifies the variable and then returns not just its value after the modification, but the variable itself. As a result, the variable can then be passed into fun as a reference. But the &argv[1] is just the value of a memory location. It's a computed value, not a variable in its own right, so it can't be passed in as a non-const reference.
If you're planning to try to change the value of argv itself (to point it to a different array of character arrays), then &argv[1] doesn't work for that anyway, since it's not argv. ++argv, however, is argv, just after it's had its value adjusted.
You could also handle all of this without references at all, which would make things much easier, but that's up to you. If it were my code, though, I wouldn't be using references here. The const reference to an int could just be passed by value (which would be easier) and passing a reference to a double pointer doesn't save you any null checking (as it could still well be null). So there isn't much point to it. But if you like your code to be complex, feel free.

Why is main() argument argv of type char*[] rather than const char*[]?

When I wrote the following code and executed it, the compiler said
deprecated conversion from string constant to char*
int main()
{
char *p;
p=new char[5];
p="how are you";
cout<< p;
return 0;
}
It means that I should have written const char *.
But when we pass arguments into main using char* argv[] we don't write const char* argv[].
Why?
Because ... argv[] isn't const. And it certainly isn't a (static) string literal since it's being created at runtime.
You're declaring a char * pointer then assigning a string literal to it, which is by definition constant; the actual data is in read-only memory.
int main(int argc, char **argv) {
// Yes, I know I'm not checking anything - just a demo
argv[1][0] = 'f';
std::cout << argv[1] << std::endl;
}
Input:
g++ -o test test.cc
./test hoo
Output:
foo
This is not a comment on why you'd want to change argv, but it certainly is possible.
Historical reasons. Changing the signature of main() would break too much existing code. And it is possible that some implementations allow you to change the parameters to main from your code. However code like this:
char * p = "helllo";
* p = 'x';
is always illegal, because you are not allowed to mess with string literals like that, so the pointer should be to a const char.
why is it required for char* to be constant while assigning it to a string
Because such literal strings (like "hi", "hello what's going on", etc), are stored in the read-only segment of your exe. As such, the pointers that point to them need to point to constant characters (eg, can't change them).
You are assigning a string constant (const char*) to a pointer to a non-constant string (char *p). This would allow you to modify the string constant, e.g. by doing p[0] = 'n'.
Anyway, why don't you use std::string instead ? (you seem to be using C++).
If you look at execution functions like execve, you will see that they actually don't accept const char* as parameters, but do indeed require char*, therefore you can't use a string constant to invoke main.