How to declare a variable as char* const*? - c++

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().

Related

The parameters of the Main function in C++

When I try to compile this code, an error appears :
#include<iostream>
using namespace std;
int main()
{
char* p = "Hello";
return 0;
}
error C2440: 'initializing': cannot convert from 'const char [6]' to 'char *'
This error is fixed when I add the word const in the declaration of p.
This code compiles and runs:
#include<iostream>
using namespace std;
int main()
{
const char* p = "Hello";
return 0;
}
So my question is : How is the main() function able to take char *argv[] (as a parameter) and not const char *argv[] (as a parameter)?
int main (int argc, char *argv[])
"Hello" is a string literal, which has a type of const char[6]. You can't set a non-const char* pointer to point at a const char[], hence the error. Doing so would grant the caller access to mutate read-only data.
The char* pointers in the argv[] parameter of main() are pointing at char[] arrays which are allocated and filled dynamically at runtime, when the program's startup code parses the calling process's command line parameters before calling main(). They are not pointing at string literals, and thus do not need to be const char*.
TL;DR: You can actually mutate argv, string literals are immutable in c++.
eg:
#include <iostream>
int main(int, char** argv) {
char* p = new char[3];
p[0] = 'H'; p[1] = 'i'; p[2] = 0;
argv[0][0] = ':';
argv[0][1] = 'P';
argv[0][2] = '\n';
std::cout << p << argv[0];
delete[] p;
}
Same code on Compiler Explorer
This is, as far as I know, valid c++, with well-defined behavior.
char* x = "An immutable char const[]."; is not.
You can probably cast const away with const_cast.
But any attempt to modify the string pointed to by x would cause undefined behavior.
Let's see what is happening in your example on case by case basis:
Case 1
Here we consider the statement:
char* p = "Hello";
On the right hand side of the above statement, we've the string literal "Hello" which is of type const char[6]. There are two ways to understand why the above statement didn't work.
In some contexts, const char[6] decays to a const char* due to type decay. This basically means that on the right hand side we will have a const char* while on the left hand side we have a char*. Note also that this means that on the right hand side we've a low-level const but on the left hand side we don't have any low-level const. So, the given statement won't work. For the statement to work we've to make sure that the left hand side should've either same or greater low-level const qualifier than the right hand side.
A few example would illustrate the point:
int arr1[] = {1,2,3};
int* ptr1 = arr1; //this works because arr1 decays to int* and both sides have no low level const
const int arr2[] = {1,2,3};
int* ptr2 = arr2; //won't work, right hand side will have a low level const(as arr2 decays to const char*) while the left hand side will not have a low level const
const int* ptr3 = arr2; //this works, both side will have a low level const
The second way(which is basically equivalent to the 1st) to understand this is that since "Hello" is of type const char[6], so if we are allowed to write char* p = "Hello"; then that would mean that we're allowed to change the elements of the array. But note that the type const char[6] means that the char elements inside the array are immutable(or non-changable). Thus, allowing char* p = "Hello"; would allow changing const marked data, which should not happen(since the data was not supposed to change as it was marked const). So to prevent this from happening we have to use const char* p = "Hello"; so that the pointer p is not allowed to change the const marked data.
Case 2
Here we consider the declaration:
int main (int argc, char *argv[])
In the above declaration, the type of the second parameter named argv is actually a char**. That is, argv is a pointer to a pointer to a char. This is because a char* [] decays to a char** due to type decay. For example, the below given declarations are equivalent:
int main (int argc, char *argv[]); //first declaration
int main (int argc, char **argv); //RE-DECLARATION. Equivalent to the above declaration
In other words, argv is a pointer that points to the first element of an array with elements of type char*. Moreover, each elements argv[i] of the array(with elements of type char*) itself point to a character which is the start of a null terminated character string. That is, each element argv[i] points to the first element of an array with elements of type char(and not const char). Thus, there is no need for const char*. A diagram is given for illustration purposes:

Invalid conversion from 'const char**' to 'char* const*'

I'm doing a school assignment where I have to call execvp, whose method signature is the following
execvp(const char* file, char* const argv[])
However my data is in the form:
std::vector<std::string*>
I've been trying to convert said vector into the right format for the second format of execvp(), but inevitably get the following error:
command.cc:120:29: error: invalid conversion from ‘const char**’ to ‘char* const*’ [-fpermissive]
execvp(args[0], argv);
I've tried different variations but they all lead to this error. This error confuses me, since I have no idea what it means by const*. How can you have a const*? I'd consider changing the std::vector to some other type, but this is an assignment and I'm not really allowed to change it. Below is the code I use to try and create a char*[] from the vector:
const size_t numArgs = _simpleCommands[i]->_arguments.size();
std::vector<const char*> args;
for(size_t j = 0; j < numArgs; ++j)
{
args.push_back(strPtrToCharPtr(_simpleCommands[i]->_arguments[i]));
}
const char** argv = new const char*[numArgs];
for(size_t j = 0; j < numArgs; ++j)
{
argv[j] = args[j];
}
execvp(args[0], argv);
The char* const argv[] prototype means that argv is (the address of) an array of pointers to char, that the pointers in the array cannot be modified, but that the strings they point to can be. This is different from a char const **, which is a pointer to a pointer to char whose characters cannot be modified. Since passing it to a function that might modify the strings in the array would violate the const qualifier of const char **, it is not allowed. (You could do it with const_cast, but that would be solving the wrong problem.)
Since execvp() is a very old UNIX function and would not have the same interface today, it doesn’t have any parameter to tell the OS how many arguments there are, nor does it promise not to modify the contents of the strings in the array. You terminate the array by setting the final element to NULL.
It’s a similar format to the argv parameter of main(). In fact, it becomes the argv parameter of the main() function of the program you run, if it was written in C.
This isn’t a complete solution, since this is a homework assignment and you want to solve it on your own, but you have to create that array yourself. You can do this by creating a std::vector<char *> argv( args.size() + 1 ), setting each element but the last to the .data() pointer from the corresponding element of args, and setting the last element to NULL. Then, pass argv.data() to execvp().
Note that the POSIX.1-2008 standard says,
The argv[] and envp[] arrays of pointers and the strings to which those arrays point shall not be modified by a call to one of the exec functions, except as a consequence of replacing the process image.
Therefore, you ought to be able to get away with casting away the const-ness of the strings in the array, this once, if you don’t mind living dangerously. Normally, you would need to make a modifiable copy of each constant string in the array.
Update
Enough time has passed that I’m not giving out answers to homework. A commenter claimed that my answer did not work on g++8, which means that they didn’t implement the same algorithm I was thinking of. Therefore, posting the complete solution will be helpful.
This actually solves the closely-related problem of how to convert a std::vector<std::string> for use with execvp(). (A std::vector<std::string*> is basically never correct, and certainly not here. If you really, truly want one, change the type of s in the for loop and dereference.)
#define _XOPEN_SOURCE 700
// The next three lines are defensive coding:
#define _POSIX_C_SOURCE 200809L
#define _XOPEN_VERSION 700
#define _XOPEN_UNIX 1
#include <errno.h>
#include <stdlib.h>
#include <string>
#include <unistd.h>
#include <vector>
int main()
{
const std::vector<std::string> cmdline{ "ls", "-al" };
std::vector<const char*> argv;
for ( const auto& s : cmdline ) {
argv.push_back( s.data() );
}
argv.push_back(NULL);
argv.shrink_to_fit();
errno = 0;
/* Casting away the const qualifier on the argument list to execvp() is safe
* because POSIX specifies: "The argv[] [...] arrays of pointers and the
* strings to which those arrays point shall not be modified by a call to
* one of the exec functions[.]"
*/
execvp( "/bin/ls", const_cast<char* const *>(argv.data()) );
// If this line is reached, execvp() failed.
perror("Error executing /bin/ls");
return EXIT_FAILURE;
}
Another twist on this would be to write a conversion function that returns the std::vector<const char*> containing the command-line arguments. This is equally efficient, thanks to guaranteed copy elision. I normally like to code using RIIA and static single assignments, so I find it more elegant to return an object whose lifetime is managed automatically. In this case, the elements of argv are weak references to the strings in cmdline, so cmdline must outlive argv. Because we used C-style pointers as weak references, RIIA does not quite work here and we still need to pay attention to object lifetimes.
#define _XOPEN_SOURCE 700
#define _POSIX_C_SOURCE 200809L
#define _XOPEN_VERSION 700
#define _XOPEN_UNIX 1
#include <errno.h>
#include <stdlib.h>
#include <string>
#include <unistd.h>
#include <vector>
std::vector<const char*> make_argv( std::vector<std::string>const& in )
{
std::vector<const char*> out;
out.reserve( in.size() + 1 );
for ( const auto& s : in ) {
out.push_back( s.data() );
}
out.push_back(NULL);
out.shrink_to_fit();
return out; // Benefits from guaranteed copy elision.
}
int main()
{
const std::vector<std::string> cmdline{ "ls", "-al" };
errno = 0;
/* Casting away the const qualifier on the argument list to execvp() is safe
* because POSIX specifies: "The argv[] [...] arrays of pointers and the
* strings to which those arrays point shall not be modified by a call to
* one of the exec functions[.]"
*/
execvp( "/bin/ls", const_cast<char* const *>(make_argv(cmdline).data()) );
// If this line is reached, execvp() failed.
perror("Error executing /bin/ls");
return EXIT_FAILURE;
}
I don't understand the std::vector<std::string *> part (are you sure you don't need a std::vector<std::string>?), anyway...
Rule for const: it's applied to the element on the left; if there is non element on the left, it's applied to the element on the right.
So a const char** (or char const **, if you prefer) is a pointer to a pointer to a constant char. I mean: the constant part is the char pointed, not the pointers.
And char * const * is a pointer to a constant pointer to a char; in this case the constant part is one of the two pointers, not the char pointed.
In your case the function
execvp(const char* file, char* const argv[])
expect, as second parameter, a char * const argv[] (a C-style array of constant pointers to a char) that you can see as a char * const *.
But you call
execvp(args[0], argv);
where argv is a char const **, that is different to a char * const *.
So the error: the function expect to be able to modify the pointed char's and you pass a pointer to a pointer to not modifiable char's
And you can't define argv as a char * const *
char * cont * argv = new char * const [numArgs]; // <-- WRONG
because you can't modify it.
So, to solve the problem, I suppose you can define argv as a char **
char** argv = new char* [numArgs];
for(size_t j = 0; j < numArgs; ++j)
argv[j] = args[j];
execvp(args[0], argv);
There ins't problem if you pass a not-constant object to a function that require a constant one (the contrary can be a problem), so you can pass a char ** to a function that expect a char * const *.
1) You don't need to have const * (const pointer) because pointer is automatically converted to const pointer if needed;
2) But you do need to supply char* (not const char* !) array as a second argument of execvp, i.e. your string characters should be modifiable. By having such a signature, execvp reserve its right to modify the supplied argument strings (yes it seems strange - but a process does have right to change its argument - note that main() routine may have (non-const) char** argv arguments!). Thus, you need to get rid of const char* in your piece of code and replace them by char *

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);

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

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.

an advanced declaration of a function? [duplicate]

For reading complex pointer declarations there is the right-left rule.
But this rule does not mention how to read const modifiers.
For example in a simple pointer declaration, const can be applied in several ways:
char *buffer; // non-const pointer to non-const memory
const char *buffer; // non-const pointer to const memory
char const *buffer; // equivalent to previous declartion
char * const buffer = {0}; // const pointer to non-const memory
char * buffer const = {0}; // error
const char * const buffer = {0}; // const pointer to const memory
Now what about the use of const with a pointer of pointer declaration?
char **x; // no const;
const char **x;
char * const *x;
char * * const x;
const char * const * x;
const char * * const x;
const char * const * const x;
And what is an easy rule to read those declarations?
Which declarations make sense?
Is the Clockwise/Spiral Rule applicable?
Two real world examples
The method ASTUnit::LoadFromCommandLine uses const char ** to supply command line arguments (in the llvm clang source).
The argument vector parameter of getopt() is declared like this:
int getopt(int argc, char * const argv[], const char *optstring);
Where char * const argv[] is equivalent to char * const * argv in that context.
Since both functions use the same concept (a vector of pointers to strings to supply the arguments) and the declarations differ - the obvious questions are: Why do they differ? Makes one more sense than the other?
The intend should be: The const modifier should specify that the function does not manipulate strings of this vector and does not change the structure of the vector.
The const modifier is trivial: it modifies what precedes it, unless
nothing precedes it. So:
char const* buffer; // const modifies char
char* const buffer; // const modifies *
, etc. Generally, It's best to avoid the forms where nothing precedes
the const, but in practice, you're going to see them, so you have to
remember that when no type precedes the const, you have to logically
move it behind the first type. So:
const char** buffer;
is in fact:
char const** buffer;
, i.e. pointer to pointer to const char.
Finally, in a function declaration, a [] after reads as a * before.
(Again, it's probably better to avoid this misleading notation, but
you're going to see it, so you have to deal with it.) So:
char * const argv[], // As function argument
is:
char *const * argv,
a pointer to a const pointer to a char.
(Trying to focus on other aspects of the question)
The rule of thumb for const declarations is to read them from right to left and const modifies the next token. Exception: At the beginning of a declaration const modifies the previous token.
There is a rationale behind this exception - for elementary declarations const char c looks for some people more natural than char const c - and it is reported that a precursor form of const char c predates the final const rule.
getopt
int getopt(int argc, char * const argv[], const char *optstring);
or
int getopt(int argc, char * const * argv, const char *optstring);
Which means that argv is a pointer to const vector of pointers to non-const strings.
But one would expect following declaration:
int getopt(int argc, char const * const * argv, const char *optstring);
(pointer to const vector to const strings)
Because getopt() is not supposed to change the strings referenced via argv.
At least char ** (as used in main()) automatically converts to char * const * argv.
Clang
ASTUnit::LoadFromCommandLine(..., const char **argv, ...);
Which means that argv is a pointer to a non-const array of pointers to const strings.
Again one would expect const char * const *argv for the same reason as above.
But this is more noticeable because char ** does not convert to const char **, e.g.
int main(int argc, char **argv) {
const char **x = argv; // Compile error!
return 0;
}
yields a compile error, where
int main(int argc, char **argv) {
char * const *x = argv;
return 0;
}
and
int main(int argc, char **argv) {
const char * const *x = argv;
return 0;
}
do not.