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.
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 was using the Decoder for Microsoft Script Encoder. It works perfectly well when I run it in Codeblocks. But when I run it in Visual Studio, it shows me the following errors
Snippet 1:
char decodeMnemonic(unsigned char *mnemonic)
{
int i = 0;
while (entities[i].entity != NULL)
{
**if (strcmp(entities[i].entity, mnemonic) == 0)**
**//Error 1: cannot convert argument 2 from 'unsigned char *'
// to 'const char *'**
return entities[i].mappedchar;
i++;
}
printf("Warning: did not recognize HTML entity '%s'\n", mnemonic);
return '?';
}
I had to integrate the Decoder in a program, so instead of passing the filenames as command line arguments, I have given their filepaths myself in the code.
Snippet 2:
int main()
{
unsigned char *inname = "C:\\Users\\Karthi\\Desktop\\Project Winter 2018-19\\poweliks_sample\\poweliks_encoded_js.bin";
unsigned char *outname = "C:\\Users\\Karthi\\Desktop\\Project Winter 2018-19\\poweliks_sample\\decoded1.txt";
unsigned int cp = 0;
//**Error 2: 'initializing': cannot convert from 'const char [87]' to 'unsigned char *'**
You can use reinterpret_cast (for unsigned char* to const char*). But if you go from const unsigned char* to a non const type, you have to use const_cast first, since reinterpret_cast cannot cast away a const.
The paragraph below gives a brief overview, why your code did not work.
According to C99 Standard (similiar to other C standards), a string literal has static storage duration and its type is char[] The standard says:
If the program attempts to modify such an array, the behavior is undefined.
The reason why your program worked, when you used argv is, that argv is not considered as an array of string literals. This means you can modify them.
Here are the solutions for your problems:
Snippet 1:
strcmp is a method to compare two C Strings. It expects const char* types.
int strcmp ( const char * str1, const char * str2 );
You have two option to solve it:
Declare your method like this
char decodeMnemonic(const char *mnemonic)
Use C++Strings and declare your method like this
char decodeMnemonic(std::string mnemonic)
If you use the second solutions you have to call the c_str()-Method to use it in strcmp
if (strcmp(entities[i].entity, mnemonic.c_str()) == 0)
Or you use only C++-String: read here how to use it: http://www.cplusplus.com/reference/string/string/compare/
Snippet 2: You can't use it like this because you have string literals which are arrays constant characters.
Please use C++-Strings. You work with C++, so use his features (https://www.geeksforgeeks.org/stdstring-class-in-c/)
Anyway if you want to use it C-like: https://www.programiz.com/c-programming/c-strings
char c[] = "abcd";
char c[50] = "abcd";
Or with const (C++)
char *str1 = "string Literal";
const char *str2 = "string Literal";
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
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.