What is the difference between char** argv and char* argv[]? in int main(int argc, char** argv) and int main(int argc, char* argv[])?
Are they the same? Especially that the first part does not have [].
They are entirely equivalent. char *argv[] must be read as array of pointers to char and an array argument is demoted to a pointer, so pointer to pointer to char, or char **.
This is the same in C.
They are indeed exactly the same.
The golden rule of arrays to remember is:
"The name of an array is a pointer to the first element of the array."
So if you declare the following:
char text[] = "A string of characters.";
Then the variable "text" is a pointer to the first char in the array of chars you've just declared. In other words, "text" is of type char *. When you access an element of an array using [index], what you're actually doing is adding an offset of index to the pointer to the first element of the array, and then dereferencing this new pointer. The following two lines will therefore initialize both variables to 't':
char thirdChar = text[3];
char thirdChar2 = *(text+3);
Using the square brackets is a convience provided by the language that makes the code much more readable. But the way this works is very important when you start thinking about more complex things, such as pointers to pointers. char** argv is the same as char* argv[] because in the second case "the name of the array is a pointer to the first element in the array".
From this you should also be able to see why it is that array indexes start from 0. The pointer to the first element is the array's variable name (golden rule again) plus an offset of... nothing!
I've had debates with a friend of mine as to which is better to use here. With the char* argv[] notation it may be clearer to the reader that this is in fact an "array of pointers to characters" as opposed to the char** argv notation which can be read as a "pointer to a pointer to a character". My opinion is that this latter notation doesn't convey as much information to the reader.
It's good to know that they're exactly the same, but for readablity I think that if the intention is an array of pointers then the char* argv[] notation conveys this much more clearly.
For the first part of the question:
char** argv: pointer to a pointer to a char
char* argv[]: pointer to an array
So the question is whether a pointer to a type C and an array C[] are the same things. They are not at all in general, BUT they are equivalent when used in signatures.
In other words, there is no difference in your example, but it is important to keep in mind the difference between pointer and array otherwise.
For all practical purposes, they're the same. This is due to C/C++'s handling of arrays passed as arguments, where an array decays to a pointer.
The bracket form is only useful in statement declarations like:
char *a[] = {"foo", "bar", "baz"};
printf("%d\n", sizeof a / sizeof *a);
// prints 3
Because it knows at compile time the size of the array. When you pass a bracket form as parameter to a function (main or some other one), the compiler has no idea what the size of the array would be at runtime, so it is exactly the same as char **a. I prefer char **argv since it's clearer that sizeof wouldn't work like it would on the statement declaration form.
There is a difference between TYPE * NAME and TYPE NAME[] in both C and C++. In C++ both types are not interchagneable. For example following function is illegal (you will get an error) in C++, but legal in C (you will get warning):
int some (int *a[3]) // a is array of dimension 3 of pointers to int
{
return sizeof a;
}
int main ()
{
int x[3][3];
std::cout << some(x)<< std::endl;
return 0;
}
To make it legal just change signature to int some (int (*a)[3]) (pointer to array of 3 ints) or int some (int a[][3]). The number in last square brackets must be equal to an argument's. Converting from array of arrays to an array of pointers is illegal. Converting from pointer to pointer to array of arrays is illegal too. But converting pointer to pointer to an array of pointers is legal!
So remember: Only nearest to dereference type signature doesn't matter, others do (in the context of pointers and arrays, sure).
Consider we have a as pointer to pointer to int:
int ** a;
&a -> a -> *a -> **a
(1) (2) (3) (4)
You cannot change this value, the type is int ***. May be taken by function as int **b[] or int ***b. The best is int *** const b.
The type is int **. May be taken by function as int *b[] or int ** b. Brackets of the array declaratin may be leaved empty or contain any number.
The type is int *. May be taken by function as int b[] or int * b or even void * b
Should be taken as int parameter. I don't want to fall into details, like implicit constructor call.
Answering your question: the real type of argumets in main function is char ** argv, so it may be easily represented as char *argv[] (but not as char (*argv)[]). Also argv name of main function may be safely changed.
You may check it easily: std::cout << typeid(argv).name(); (PPc = pointer to p. to char)
By the way: there is a cool feature, passing arrays as references:
void somef(int (&arr)[3])
{
printf("%i", (sizeof arr)/(sizeof(int))); // will print 3!
}
Moreover pointer to anything may be implicitly accepted (converted) by function as void pointer. But only single pointer (not pointer to pointer etc.).
Further reading:
Bjarne Stroustrup, C++, chapter 7.4
C pointers FAQ
This is a simple example I came up with, which have two functions (Main_1, Main_2) take the same arguments as the main function.
I hope this clear things up..
#include <iostream>
void Main_1(int argc, char **argv)
{
for (int i = 0; i < argc; i++)
{
std::cout << *(argv + i) << std::endl;
}
}
void Main_2(int argc, char *argv[])
{
for (int i = 0; i < argc; i++)
{
std::cout << *(argv + i) << std::endl;
}
}
int main()
{
// character arrays with null terminators (0 or '\o')
char arg1[] = {'h', 'e', 'l', 'l', 'o', 0};
char arg2[] = {'h', 'o', 'w', 0};
char arg3[] = {'a', 'r', 'e', '\0'};
char arg4[] = {'y', 'o', 'u', '\n', '\0'};
// arguments count
int argc = 4;
// array of char pointers (point to each character array (arg1, arg2, arg3 and arg4)
char *argPtrs[] = {arg1, arg2, arg3, arg4};
// pointer to char pointer array (argPtrs)
char **argv = argPtrs;
Main_1(argc, argv);
Main_2(argc, argv);
// or
Main_1(argc, argPtrs);
Main_2(argc, argPtrs);
return 0;
}
Output :
hello
how
are
you
hello
how
are
you
hello
how
are
you
hello
how
are
you
Both are same for your usage except for the following subtle differences:
Sizeof will give different results for both
Also second one may not be reassigned to new memory area since it's an array
With second one you can use only those indexes which are
valid. It's unspecified by C/C++ if you try to use an array index beyond
array length. However with char** you can use any index from 0 to ...
Second form can only be used as formal parameters to a function. While first can even be used to declare variables within a stack.
Related
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:
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().
I'm very new to C++. I'm trying to call a function that takes in char**:
bool func(char** a) {
//blablabla
}
So it takes in an array of c-strings. I need to create a char**, but nothing works.
char** a = char[255][255]; // error: type name is not allowed
char** a = new char[255][255]; // error: a value of type "char (*)[255]" cannot be used to initialize an entity of type "char **"
char a[][] = {"banana", "apple"};
char** b = &a; // error: a value of type "<error-type> (*)[2]" cannot be used to initialize an entity of type "char **"
At the end I need to do:
char* a[] = {"banana", "apple"};
Why the first few didn't work and why the last one worked?
Thanks in advance.
There's a lot wrong in your code.
char** a = char[255][255]; // error: type name is not allowed
First of all this is not even valid C++ (or C for that matter). Maybe you meant:
char a[255][255];
In any case always remember that the type of a bi-dimensional dynamically allocated array is not ** but (*)[N] which is very different.
char** a = new char[255][255]; // error: a value of type "char (*)[255]" cannot be used to initialize an entity of type "char **"
The error message you provide in the comment explains exactly what I said earlier.
char a[][] = {"banana", "apple"};
In the above code the correct type of the variable a should be char* a[]. Again, arrays and pointer (for what the type is concerned) are very different things. A char array may decay to pointer (if NULL terminated), but for the rest, except with explicit casts, you can't use pointers and arrays like you are doing.
The last one worked because, like I said earlier, char* [] is the correct type for an array of C-strings.
Anyway, if you just doing homework, it is ok to learn this things. But in future development using C++: try not to use "features" that start with C-, like C-strings, C-arrays, etc. C++'s standard library gives you std::string, std::array, std::vector and such for free.
If you really need to allocate dynamic memory (with new and delete, or new[] and delete[]) please use smart pointers, like std::shared_ptr or std::unique_ptr.
You say you are working in C++. Then you can easily ignore const char* and char** and focus about what you can use:
#include <string>
#include <vector>
std::vector<std::string> arrayOfStrings;
arrayOfStrings.push_back("foo");
bool func(const std::vector<std::string>>& a) {
..
}
If you know the size at compile time you can even use std::array:
std::array<255, std::string> fixedArrayOfStrings
EDIT: since you need to build an array of C strings in any case you can easily do it starting from the vector:
const char **arrayOfCstrings = new const char*[vector.size()];
for (int i = 0; i < vector.size(); ++i)
arrayOfCstrings[i] = vector[i].c_str();
func(arrayOfCstrings);
delete [] arrayOfCstrings;
char**
is ambiguous - it can mean:
pointer to pointer
array of c-strings - experienced programmer would write char* arr[] instead
In the first case it is quite simple:
char* niceString = GetNiceString();
func(&niceString);
however in the second case it is slightly more complex. The function will not know the length of the array so you need to end it explicitly with a NULL, just like for example environ is:
char* a[3] = { "One", "Two", NULL }; /* note that this is possibly dangerous
because you assign const char* (READ-ONLY) to char* (WRITABLE) */
func(a); // char*[] gets downgraded to char** implicitly
so char** a = char[255][255]; it's weird to C and C++
and if you want a static 2d array just
char a[255][255];
char ** is a scalar type, you have to cast to (char *[]), try this :
char **temp = (char *[]){"abc", "def","fg"};
From the book:
Write declarations for the following: a pointer to a character, an
array of 10 integers, a ref-erence to an array of 10 integers, a
pointer to an array of character strings, a pointer to a pointer to a
character, a constant integer, a pointer to a constant integer, and a
constant pointer to an integer. Initialize each one.
I'm confused by "a pointer to an array of character strings". What does Stroustrup want? Is this to be meant literally? In which way?
The straight and simple solution:
char* c[] = {"foo", "bar", "baz"};
char** c_ptr;
Or this one:
typedef char carray[20];
typedef array* carray_ptr;
carray_ptr ptr = new carray[10];
What do you think? (Okay, a pointer to pointer isn't very straight.)
With these sorts of declaration tests, it's often easiest to use a tool like cdecl. I think in this case what the book is looking for is:
c
is a pointer:
*c
to an array:
(*c)[]
of character strings:
char *(*c)[]
Or from cdecl:
cdecl> declare c as pointer to array of pointer to char
char *(*c)[]
I just made a guess about what the book expects, but since the next request is "pointer to a pointer to a character", it would be weird for the two to be asking the same thing.
typedef char* character_string;
typedef character_string[20] array_of_character_strings;
typedef array_of_character_strings* pointer_to_array_of_character_strings;
pointer_to_array_of_character_strings ptr; //done
or:
char*(*var)[20];
shown at: cdecl.ridiculousfish.com, "declare var as pointer to array 20 of pointer to char"
1) Chapter 5 is about "Pointers, Arrays and Structures".
I don't see any "typedef's" skimming the chapter, so I wouldn't use them in this exercise.
2) One could point to "argv" as an excellent example of "A pointer to an array of character strings":
int main (int argc, char *argv[])
3) "c_ptr" in your first example would certainly work (although maybe a better name
might be "c_pp" ;)):
char* c[] = {"foo", "bar", "baz"};
char** c_ptr = c;
'Hope that helps!
Break it down into steps:
A pointer to an array: T (*p)[N]
T = char const * gives you: char const * (*p)[N]
We initialize a pointer with the address of an existing thing, so make an array first:
char const * arr[] = { "hello", "world" };
Now initialize the guy from (2): char const * (*p)[2] = &arr;
I am doing it that way:
int argc = 9;
char* argv[argc];
argv[0] = "c:/prog.exe";
but I get notice, that it is deprecated. What is better way?
You have to either make it const:
const char *argv[] = { "Arg1", "Arg2", "..." };
... or not use the constant string literals:
int argc = 9;
char* argv[argc];
char prog_name[] = "c:/prog.exe";
argv[0] = prog_name;
Besides the problem of using something other than a constant expression for your array size...
The thing that has been deprecated is the silent casting of string literals to char*. This used to be OK:
char * hello = "hello";
Now it has to be:
char const* hello = "hello";
This deprecation is actually in an Appendix in C++03.
Let analyze what you are doing here:
// Create an int with value 9.
int argc = 9;
// Create an array of char* pointers of size 9
char* argv[argc];
// Assign the the first pointer to the global data string "C:\prog.exe"
argv[0] = "c:/prog.exe";
My guess is that you are not trying to do what I've described above. Try something like this:
// create an array of characters
char argv[] = "C:/prog.exe";
// argc in now the length of the string
int argc = sizeof argv;
-or -
// create an array of strings
char* argv[] = {"C:/prog.exe"};
// argc is now the number of strings in the array
int argc = 1;
Try using const to indicate that the strings won't be modified.
const char* argv[] = { "c:/prog.exe" };
const int argc = sizeof(argv) / sizeof(argv[0]);
int main()
{
for(int i = 0; i < argc; ++i)
{
::printf("%s\n", argv[i]);
}
}
Here, argc will also be calculated at compile time automatically so there's a lesser chance of error (thanks to Goz for the suggestion).
+1 for Vlad.
Some more explanation from me on what happens here:
You get the "deprecated" warning, because such code:
"asdf"
now has type const char*, not char*. And string literals can be converted to char*, to retain some compatibility with the older conventions when const wasn't that strict. But conversion of a string literal to char* from const char* is deprecated and you should not rely on it.
Why? String literal is a pointer to constant memory, that's why it needs to be const char*.
Other than what everyone else has pointed out about const string literals being assigned to non-const char pointers and the weirdness of declaring argv and argc outside of main()'s parameter list, there is an additional problem with this line here:
char* argv[argc];
You can only use integer constant expressions for array sizes in C++; an integer constant expression being a literal integer in the source of your program (like "5" or "10"), an enumerations value (like "red" from "enum colors {red, green, blue};"), a sizeof expression, or an int variable declared with const:
// can hold 30 ints
int myarray1[30];
// can hold as many ints as myarray1 is wide in bytes
int myarray2[sizeof(myarray1)];
// C++ does not support variable-length arrays like C99 does, so if an int
// variable is used to specify array size, it must be marked const:
const int myarray3_size = 42;
int myarray3[myarray3];
Many C++ compilers implement C99-style variable-length arrays, so you may not get any complaint when you use them, but they are still best avoided if you want to write portable code.