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:
Related
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 got this confusion while learning c++:
int *a = 8 ;
This gives an error because, as I have understood it, i am trying to set an integer to a pointer which is a memory location. But,
const char *name = "name";
works perfectly fine? I don't get it as name should be an hexadecimal memory location but i am trying to set it to a series of characters.
A string literal, "name" in your case, is of typeconst char[]. An array can decay to a pointer which is what's happening in this case. That pointer will then point to the first element in the array. Note that since C++11 assigning to a char* instead of a const char* (thus needing a conversion) as you are doing is illegal, always use const char* for string literals, or better yet, std::string.
8 is of type int, which has no conversion to a pointer type that an array has.
The rules for int* and char* are the same. However, you compare apples to oranges.
You cannot assign a value of the respective type to its pointer (it doesn’t matter whether there is a const here; I made things const for consistency with the next example where it matters to some extend):
int const* ip = 8; // ERROR
char const* cp = ‘8’; // ERROR
Arrays decay into pointers upon the slightest opportunity. String literals are arrays of type char const[N] where N is the number of chars in the string literal, including the terminating null char.
int ia[] = { 8 };
char ca[] = { ‘8’ };
int const* ip = ia; // OK
char const* cp = ca; // OK
char const* lp = “8”; // OK
I was working with the strcmp function in C, then i saw the function as arguments gets:
strcmp(_const char *s1, const char *s2)_;
And actually i passed normal char array and it worked. Any ideas why this happening?
If you have for example the following code
char c = 'A';
char *p = &c;
const char *cp = &c;
then it means that you can change variable c using pointer p but you may not change it using pointer cp
For example
*p = 'B'; // valid assignment
*cp = 'B'; // compilation error
Thus function declaration
int strcmp(const char *s1, const char *s2);
means that inside the function the strings pointed to by s1 and s2 will not be changed.
There are two ways to use const key word to a pointer:
int my_int = 3;
const int* pt = &my_int; //prevent to modify the value that pointer pt points to
int* const ps = &my_int; //prevent to modify the value of pointer ps:
//it means the pointer is a const pointer, you can't modify the value of the pointer
//The value of the pointer ps is a memory address, so you can't change the memory address
//It means you can't reallocate the pointer(point the pointer to another variable)
int new_int = 5;
*pt = &new_int; //valid
*pt = 10; //invalid
*ps = &new_int; //invalid
*ps = 10; //valid
In strcmp function, the two arguments are pointer points to a const value, it means when you pass two char arrays or char pointers to the strcmp function, the function can use the value of those two pointers point to, but the function can't modify the value that you pass to it. That's why it works.
The const reference works in a similar way.
This worked, because passing non-const in place of const is allowed. It is the other way around that is prohibited:
char *hello = new char[20];
char *world= new char[20];
strcpy(hello, "hello");
strcpy(world, "world");
if (!strcmp(hello, world)) {
...
}
The const in the declaration is meant to tell the users of the API that the function will not modify the content of the string. In C++ this is important, because string literals are const. Without the const in the API, this call would have been prohibited:
if (!strcmp(someString, "expected")) { // <<== This would not compile without const
...
}
I think you intend to ask the mechanism of how the variable can compare the array.
if that's the case,
The pointer that has been declared in your example stores the initial address of the array's first element and
the ending point of the string can be determined by the detection null character that which in turn is the ending address of the array.
With that said the strcmp when called the pointer points to the strings or the character passed that is, the command would be assumed as follows strcmp("string1","string2");
and thus the comparison takes place as usual.
hmm i guess by this and with other examples posted around you can get a better picture for your answer.
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.
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.