Is possible to convert argument from 'const char []' to 'char *' in C++? - c++

Definition of method is:
void setArgument(char *);
And i call that method with this code:
setArgument("argument");
But my VisualStudio compiler gets me the next error:
cannot convert argument 1 from 'const char [10]' to 'char *'
Is it possible to send arguments like this or I must change arguments type in the method?
Also, VS show me next note in output: note: Conversion from string literal loses const qualifier (see /Zc:strictStrings)

The problem is that string literals are arrays of constant characters.
While the array could easily decay to a pointer to its first element, the type of that pointer is const char *. Which needs to be the type of the argument for your functions.
And if you need to modify the string you pass, then you should create your own non-constant array:
char argument[] = "argument";
setArgument(argument);
Of course, since you're programming in C++ you should stop using char pointers and arrays and instead use std::string.

It's possible, just if you really need the argument to be mutable (char* and not char const*), you need to allocate a new storage in the mutable memory and clone the contents of the constant memory to there, if that fits into your definition of "convert".
auto const len = strlen(input);
auto const buf = std::unique_ptr<char[]>(new char[len + 1]);
memcpy(buf, input, len + 1);
If you actually need char const* and if you are C++17 or later, you can possibly change the signature to setArgument(std::string_view arg), making it misuse-proof.

Related

Error : invalid conversion from 'const char*' to 'char*' [-fpermissive]

first of all this is not duplicate one because same error Question
asked before but in different context
1
code
#include<iostream>
#include<cstring>
int main()
{
const char *s1;
const char *s2="bonapart";
s1=new char[strlen(s2)+1];
strcpy(s1,s2);
std::cout<<s1;
}
Output
[Error] invalid conversion from 'const char*' to 'char*' [-fpermissive]
Why such error ?
If I replace const char *s1 by char *s1 compile fine. But I think this const only saying that s1 is pointing to constant string means we can't modify that string whom it is pointing. It does not mean that s1 is constant ptr. please put some light on this.
Why such error ?
Look at the declaration of strcpy:
char* strcpy( char* dest, const char* src );
Pay particular attention to the first parameter. And very particular attention to the type of the first parameter: char*. It isn't const char*.
Now, look at the type of the argument that you pass.
const char *s1;
It's not char*. It's const char*. You cannot pass a const char* into a function that accepts char* because former is not convertible to the latter, as the diagnostic message explains.
But I think this const only saying that s1 is pointing to constant string means we can't modify that string whom it is pointing.
That's exactly what const bchar* means. So, how do you expect strcpy to modify the content of the pointed string when you know that it cannot be modified? Technically in this case the pointed string isn't const, it's just pointed by a pointer-to-const
As you say, const char *s1; means that the string pointed at by s1 is not modifyable.
On the other hand, strcpy(s1,s2); will modify the string pointed at by s1.
This is against the condition "the string pointed at by s1 is not modifyable".

Read binary file into unsigned char vector buffer

I'm trying to read a binary file stream into a std::vector buffer.
std::ifstream file(srcPath, std::ifstream::binary);
file.unsetf(std::ios::skipws);
const std::vector<unsigned char> buffer(bufferSize);
file.read(buffer.data(), bufferSize);
But I get the following error
Cannot initialize a parameter of type 'std::__1::basic_istream >::char_type *' (aka 'char *') with an rvalue of type 'const std::__1::vector >::value_type *' (aka 'const unsigned char *')
I'm having trouble interpreting this error and figuring out what I'm doing wrong in my call to read.
const std::vector<unsigned char> buffer(bufferSize);
You declared a const object here. By definition, a const object cannot be modified. Your plans to modify this object, by reading something into it, are already doomed to a big, abysmal, failure at this point. But there's also a second problem.
file.read(buffer.data(), bufferSize);
If you actually read your compiler's error message, slowly, it tells you exactly what the problem is.
First of all, read()s first parameter is a char *, a pointer to a character.
But you are passing a const unsigned char *. That's because data(), given that buffer is const, obviously returns a const unsigned char *.
And that's why you get a compilation error. If you now reread the compilation error, skipping about half of its words, it makes perfect sense now:
Cannot initialize a parameter of type ... 'char *' with an rvalue of
type ... 'const unsigned char *'
To fix it, your buffer should not be a const object. Preferrably, it should be a std::vector<char>, so you end up really passing a char * to read().
But, if you insist, you can keep it a vector of unsigned chars and use reinterpret_cast to cast the result of data() from unsigned char * to char *.
You made your vector const.
So, you cannot change its contents.
You want to change its contents (that's its purpose).
So, don't make it const.

How can I make my strchr function take both 'const char' and 'char' arrays as first parameter?

I am expecting my function to work just the same as the function "strchr" I am using from the cstring / string.h library.
I understand that I cannot cast a " const char* " variable / array to " char* ". Yet, how is the predefined "strchr" function able to be passed both "const char" and "char" data type arrays and work just fine ? How could I change mine so that it works, too ?
char* my_strchr(char *place_to_find, char what_to_find)
{
for(int i=0;place_to_find[i];i++)
if(what_to_find==place_to_find[i]) return place_to_find+i;
return NULL;
}
...
int main()
{
const char vocals1[]="AEIOUaeiou";
char vocals2[]="AEIOUaeiou";
cout<<strchr(vocals1,'e');
cout<<strchr(vocals2,'e');
cout<<my_strchr(vocals1,'e');
cout<<my_strchr(vocals2,'e');
return 0;
}
As you could probably already tell, my third cout<< does not work.
I am looking for a way to change my function ( I am guessing the first parameter should somehow be typecast ).
How can I make my strchr function take both 'const char' and 'char' arrays as first parameter?
You could change the argument to be const char*. That would allow passing both pointers to char as well as const char.
However, you return a non-const pointer to that array, which you shouldn't do if the pointer is to a const array. So, when passing a const char*, your function should also return const char*
Yet, how is the predefined "strchr" function able to be passed both "const char" and "char" data type arrays and work just fine ?
There are two predefined std::strchr functions. One that accepts and returns char* and another that accepts and returns const char*:
const char* strchr(const char* str, int ch);
char* strchr( char* str, int ch);
If you would wish to return char* in case of char* argument, you need to have a different function for each case, like the standard library has. You can use an overload like the standard library does, or you can use a function template to generate both variations without repetition:
template<class Char>
Char* my_strchr(Char *place_to_find, char what_to_find)
Note that the C version of the function is declared char *strchr(const char *str, int ch). This makes the single function usable in both cases, but is unsafe, since the type system won't be able to prevent the user of the function from modifying though the returned non-const pointer even when a const array was passed as an argument.
Make two overloads, the way it is done in the C++ standard library:
char* my_strchr( char *place_to_find, char what_to_find)
const char* my_strchr(const char *place_to_find, char what_to_find)
Even though in your case only the second overload would be sufficient (demo) you would not be able to support an important use case, when you need to find a character and then replace it:
// This would not work with only one overload:
char *ptr = my_strchr(vocals2,'e');
if (ptr) {
*ptr = 'E';
}
That is why the non-const overload is necessary.
Note: I assume that you are doing this as a learning exercise, because C-style string functions are no longer necessary for new development, having been replaced with std::string functionality.
Short answer: make the type of the place_to_find const char*
The reason for your error is that you cannot implicitly convert a pointer to a const char to a pointer to a non-const char. If you could, then you could change the char that the pointer points to and it would defeat the purpose of having it a const char type in the first place.
You can implicitly convert a pointer to a non-const char to a pointer to a const char because it does not remove any restrictions.
L.E.: Also, the return value should be a const char*, because again, if you don't, it would remove the const restriction which is not allowed. The only problem with that is that you would not be able to modify the array through the pointer returned. If you also want that, then you would have to overload the method on both char and const char.

I cannot initializate WCHAR

I need to make and WCHAR.
But it wont work, and i always get an error:
Error C2440 'initializing': cannot convert from 'const wchar_t [11]' to 'WCHAR *'
StateError (active) E0144 a value of type "const wchar_t *" cannot be used to initialize an entity of type "WCHAR *
My code:
WCHAR *Testlooll = L"TEST";
L"TEST" is a string literal of type const wchar_t[5], which is an array of const characters (since the literal exists in read-only memory). You are trying to initialize a WCHAR*, which is a pointer to a non-const character, to point at that array.
Initializing a pointer to non-const character data to point at an array of const character data is deprecated in C++98 (to maintain backwards compatibility with legacy code), and is illegal in C++11 onwards.
You need to change the declaration of Testlooll according:
const WCHAR *Testlooll = L"TEST";
Or:
LPCWSTR Testlooll = L"TEST";
In addition to Remy Lebeau's answer, if for some reason you can't modify the defination of Testlooll. You can just cast the const arry to a wchar_t*. For example,
struct someLibaryType
{
WCHAR *Testlooll
};
someLibaryType a;
a.Testlooll = (wchar_t*)L"TEST";
Someone maybe argue should cast to WCHAR* just keep same with the defination type of Testlooll. But in this context, you've already used L to identify a string, so it has to be wchar_t*.

Cannot convert from 'T[N][2]' to 'T[][2]'

I have an API taking some options:
void init_api(const char* options[][2]);
I am allowed to pass a NULL pointer for no options, alternatively, an options array such as this can be passed:
const char* some_options[][2] = { {"opt1", "val1"},
{"opt2", "val2"},
{0,0}
};
This works without problems:
...
init_api(some_options);
... or ...
init_api(NULL);
...
However, this fails to compile:
const char* my_options[][2] = NULL; // error C2440: 'initializing' : cannot convert from 'int' to 'const char *[][2]'
if(...) {
my_options = some_options; // error C2440: '=' : cannot convert from 'const char *[4][2]' to 'const char *[][2]'
}
init_api(my_options); // no error here
What is going on here? Can someone explain this?
To declare an empty array of array of pointers to const char, you should use:
const char* my_options[][2] = {};
You need to declare a pointer to an array of pointers to const char instead. I recommend using a typedef to simplify the syntax.
typedef const char* array_of_two_cstring[2];
array_of_two_cstring* my_options = NULL;
if (...) {
my_options = some_options;
}
init_api(my_options);
In C++ (it is herited from C), array can be implicitly converted to pointer (only once though, that is char[] is compatible with char* but char[][] is compatible with char*[] but not `char**). However, the variable cannot be reassigned. So here you need to use a pointer instead of an array.
The init_api option accepts NULL as a parameter because for the compiler, its prototype is void init_api(char const* (*)[2]) (the first array degenerated into a pointer), and NULL is a valid pointer.
The compiler must know the array size.
If you omit the size of the array (ie: using []) you need to initialize the array with the definition, in order to let the compiler count how many items that array will contain.
Moreover you are assigning a pointer (NULL) to an array: const char *x[][2] is an array of two pointers to const char.
Edit:
In C++ (as in C), arrays can decay into pointers when you use them (with three exceptions which are not interesting here).
When you pass an array to a function expecting an array, what happens is that you actually pass a pointer to the array, since the array decays; you cannot pass an array by value in C or C++.
For this reason you can pass NULL to your function; the function parameter will be NULL, and if you try to access the array within your function (options[0]) your application will crash: you'll be dereferencing an invalid pointer.
You cannot however set your array variable to NULL, since it's not a pointer, it's an array: it will only decay when you'll use it in an expression.
const char* options[][2]
is an array of const char* pointers. You can't assign a pointer to an array.
A parameter declared as being an array of type T[N] or T[] becomes actually a parameter of type T*. Same is done for functions (a parameter declared as R(Params) becomes actually a parameter of type R(*)(Params...)).
Such transformation however is not done for other declarations. The reason it's done for function by-value parameters is that there is no way in C to actually copy an array directly (that is, to actually copy its contents) and it doesn't make sense to try and copy a function either, so such parameters are transformed in a way that conveys their purpose in a meaningful way.
So while you are initializing a pointer in the function parameter case, you are trying to initialize an array in the other case.