Meaning of the syntax `const char (&x)[]` - c++

What is the meaning of the syntax const char (&x)[] in C++, is it something like pass pointer by reference to a function call?
Is it the same like const char x[], which defines x as const char*?
And if both are one and the same where should I use const char (&x)[] instead of const char x[]?

const char (&)[] is a reference to a const char array. The expression you showed is declaring x as a one of those.
Is it the same like const char x[]
it's a reference to one of those
... which defines x as const char*
Um, no, let's take a step back.
const char array[5]
declares array as a an array of 5 const chars. It doesn't declare a pointer. However, arrays easily decay to pointers in C++, so for example
void foo(const char *);
// ...
foo(array);
is legal. In fact, arrays decay to pointers so easily, it takes extra care to pass them somewhere without decay:
template <size_t N>
void bar(const char (&x)[N]);
bar(array);
will actually get a reference to the array, and as a bonus, allow bar to deduce the array size.
Note that the only useful difference between a pointer and an array is the number of elements - when I quoted you saying const char x[], I assume there will really be a number between the square brackets. If you omit that, it doesn't have any benefit over a pointer, unless you initialize it:
const char x[] = { 'h', 'e', 'l', 'l', 'o' };
will still allow that call to bar to deduce N=5, even though you never wrote a literal 5 in your code.
It can also be used when you want your function to accept a fixed-length array:
void fun(const char (&x)[50]);
It's also usable with multi-dimensional arrays (but prefer std::vector or std::array when possible).

What is the meaning of the syntax const char (&x)[] in C++
This syntax mean that you want to use a reference to an array of const char.
Is it the same like const char x[], which defines x as const char*?
No, it isn't the same, the main difference with const char* is that the size of the array became part of the type, so you can't pass an array with a different number of elements.
The main use of reference to array is in template where the number of elements is than deduced

Related

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.

Initializer list in constructor to initialize private const c string error

my private members in my class:
const char arr1[];
const char arr2[];
my constructor:
className(const char a[], const char b[])
:arr1(a), arr2(b)
{
}
The error message from console window is:
In constructor className::className(const char*, const char*):
error: incompatible types in assignment of const char* to const char [0]
Please help, what am I doing wrong?
On a side note, I found a solution...
I used pointers as my private member vars, so *arr1 and *arr2 and that worked. :)
You are declaring your members as const char arr1[]. I am suprised that the compiler is even allowing you to make that declaration, as it should have had a fixed size in that form (like const char arr1[512]).
Depending on what you want to do, you'll either have to:
declare your members as const char* arr1 -- note that this will not copy the strings; or
use a string class (like std::string) and/or allocate memory for the class member, and copy
First of all, you compiler should already choke on declarations of the members:
const char arr1[];
const char arr2[];
That's illegal C++, arrays as class members need to have their size spelled out.
Second, const char p[], when used in function declarations, literaly means const char* p. That is, a pointer to constant char. Arrays are not pointers, don't confuse the two. They decay to a pointer to their first element when passed to functions, though.

const Function Overloading [duplicate]

This question already has answers here:
Functions with const arguments and Overloading
(3 answers)
Closed 9 years ago.
I am confused why the following code is not producing any error ,because the arguments passed to display are of same type i.e char.Does const really makes difference?
#include<iostream>
using namespace std;
void display(char *p)
{
cout<<p;
}
void display(const char *p)
{
cout<<p;
}
int main()
{
display("Hello");
display("World");
}
EDIT
As per answers,the first display is never called,which is correct and so is the output.
But suppose I do it like :
int main()
{
char *p="Hello";
display(p);//now first display is called.
display("World");
}
Compiler gives a warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings] but then it calls first display.Does it mean that string is now no more taken as constant?
const char* and char * are actually not the same. The later allow for modifying the pointed char, while the first one will prevent that.
Also note that if those were class methods, void display() and void display() const would also be valid overloads. The later would imply that the method must not change the object's state.
Consider this code:
void display(char *s)
{
std::cout << "Display" << std::endl;
}
void display(const char *s)
{
std::cout << "Display with const" << std::endl;
}
int main()
{
char *str = strdup("boap");
const char *str2 = "toto";
/* It is a string literral "bound" as a char *.
Compiler will issue warning, but it still compiles.
Avoid to do that, it's just an exemple */
char *not_safe = "not_safe";
display("llama");
display(str2);
display(str);
display(not_safe);
}
This will print Display with const twice, and then twice Display. See there.
Now, let's see why:
"llama" is a string literal, and then is resolved as a const char *.
str2 is a pointer to a string literal. Since its type is const char*, this also revolves to the const overload.
not_safe is also a pointer to a string literal. However, its type is char *: this is not correct. The memory it points to is read-only, and trying to modifies it will result in a crash. However, the type of the variable is still char *, so this resolve to the non-const overload.
str is a char * pointer, and the string it points to is not read-only. Modifying its content is valid, and since its type is char *, it will resolve to the non-const overload.
The issue is that string literals such as "Hello" and "World" have type const char[6]. This can decay to const char*, but not to char*. So the overload taking const char*,
void display(const char *p);
is the better match. As #JamesKanze points out, it would be possible for a function taking char* to accept a string literal, but attempting to modify the data pointed at would result in undefined behaviour. For this reason, it is unsafe to pass string literals to such functions. With suitable warning settings, GCC produces the following:
warning: deprecated conversion from string constant to ‘char*’
In any case, in the presence of two overloads like the ones you have shown, the one taking const char* wins.
The arguments passed to the two functions are actually not the same.
The first takes a char*: A pointer to a char.
The second takes a const char*: A pointer to a const char.
So you see, the difference here is actually in whether the pointer points to an object which can be changed or not. This is definitely a property on which you want to be able to overload a function.
Whether you can modify an object or not definitely is a useful piece of information depending on which you may want to invoke different behavior! Consider this:
void foo(int * p) { ++(*p); }
void foo(int const * p) { std::cout << *p << '\n'; }
The sizes of the strings "Hello" and "World" are known at compile time and cannot be modified. They are constant, compile-time character arrays.
In C and C++, an array e.g. char a[6] can be referred to using a pointer, i.e. a is actually a char *. Since the arrays for "Hello" and "World" must not be modified at runtime, their type is essentially const char *.
The compiler recognizes this and performs the overload resolution for display correctly, since only one of the functions (display(const char* p)) takes a const char* as an argument. This is why there is no ambiguity in the two functions, and you don't get the error that you expected to get.
"because the arguments passed to display are of same type i.e char."
No here the argument are "const char*". the data type is the but the const qualifier indicate that the literal string you hard coded, is not something that can be change.
"Does const really makes difference?"
Yes the const qualifier make a difference.
in Display(char*) you can update the content of the null-terminate string you passed but not in Display(const char*). That fact allow more optimization by the compiler.
But read that http://www.possibility.com/Cpp/const.html it's a good source to start using const efficiently.

static character array size at compile-time in c++

I know this question asked many times and I'm not asking how to do it because i did that at compile-time. My question is how it works because that is what i don't understand.
When passing a char[] to a function it looses its information and become char* and because of that we can not get size of character array at compile time using template, so i tried and passed the string itself and it worked:
template <int N> inline int arr_len(const char (&)[N]) { return N - 1; }
#define STR "this is an example!"
const char *str_ptr = STR;
int main()
{
int array_size = arr_len(STR);
}
I tested this code with VC++ 2008, Intel C++ 12 and GCC 4.7 and it works.
By passing the string itself the compiler sees it as const char[] - at least that what i think - and he able to get the string size, How is that possible?
String literal type is an array, not a pointer. So, when you pass it directly to a function that takes array by reference, it doesn't decay to a pointer.
That is because STR is a macro that is replaced before the compiler starts.
It replaces it with "XXXX" which is a string literal (not an array).
To get this to work do:
char const str_ptr[] = "XXX YYY";
// ^^^^ Compiler works out size
int main()
{
int array_size = arr_len(str_ptr);
// ^^^^^^^ pass in an object that has a type.
};
In C++ when a function's parameter type is tentatively identified as an array, the parameter type is 'adjusted' to be a pointer to the array's element type.
So when you write: void foo(char c[]) the compiler effectively rewrites it to be void foo(char *c). Then when you pass an array:
char x[10];
foo(x);
C++ finds void foo(char *c) and sees that it can convert your char [] argument into a char * and call the function, and this is exactly what it does.
However, this adjustment to the function's type only occurs when the written parameter type is an array. A reference to an array is not an array, so no equivalent adjustment is performed when you declare a function void bar(char (&c)[10]).
The second bit needed to answer your question is that the type of a string literal is an array of const char. When you write the string literal directly in the function call, with a function that takes const char (&)[N] C++ sees that it can pass a reference to the array instead of doing the "array -> pointer to first element" conversion. So that's what it does and the template type deduction finds the right number for the size of the string.

What's char* const argv[]?

I'm studying linux C++ programing when I see
int execve(const char *path,
char *const argv[],
char *const envp[]);
I don't understand what is char *const argv[] . I know char *const foo is a const pointer to char. And const char *foo is a pointer to a const char. But what's char *const argv[]?
Is it an array of const pointers to char or an array of pointers to const char?
And I have a vector<string> now, how to convert it to char *const argv[]?
Is it an array of const pointers to char or an array of pointers to const char?
Read types right to left:
const always binds to the left (unless it is on the very left)
char *const argv[]
^^ Array of
^^^^^ const
^ pointer to
^^^^ char
An array of "const pointer" to char
So the pointers in the array can not be modified.
But what they point at can be modified.
Note: As pointed out by Steve below. Because this is being used as a parameter. It actually decays to a "A pointer to "const pointer" to char" or "char* const *".
And I have a vector<string> now, how to convert it to char *const argv[]?
int execve(const char *path,
char *const argv[],
char *const envp[]);
int main()
{
std::vector<std::string> data; /// fill
std::vector<char*> argv;
std::vector<char*> envp;
for(std::vector<std::string>::iterator loop = data.begin(); loop != data.end(); ++loop)
{
argv.push_back(&(*loop)[0]);
}
// I also bet that argv and envp need to be NULL terminated
argv.push_back(NULL);
envp.push_back(NULL);
execve("MyAppName", &argv[0], &envp[0]);
}
cdecl.org says:
char *const argv[]
declare argv as array of const pointer to char
// says: argv is a constant pointer pointing to a char*
int main(int c, char *const argv[]);
You won't be able to change "argv" within the function.
As you are just learning C, i recommend you to really try to understand the differences between arrays and pointers first instead of the common things.
In the area of parameters and arrays, there are a few confusing rules that should be clear before going on. First, what you declare in a parameter list is treated special. There are such situations where things don't make sense as a function parameter in C. These are
Functions as parameters
Arrays as parameters
Arrays as parameters
The second maybe is not immediately clear. But it becomes clear when you consider that the size of an array dimension is part of the type in C (and an array whose dimension size isn't given has an incomplete type). So, if you would create a function that takes an array by-value (receives a copy), then it could do so only for one size! In addition, arrays can become large, and C tries to be as fast as possible.
In C, for these reasons, array-values are not existent. If you want to get the value of an array, what you get instead is a pointer to the first element of that array. And herein actually already lies the solution. Instead of drawing an array parameter invalid up-front, a C compiler will transform the type of the respective parameter to be a pointer. Remember this, it's very important. The parameter won't be an array, but instead it will be a pointer to the respective element type.
Now, if you try to pass an array, what is passed instead is a pointer to the arrays' first element.
Excursion: Functions as parameters
For completion, and because i think this will help you better understand the matter, let's look what the state of affairs is when you try to have a function as a parameter. Indeed, first it won't make any sense. How can a parameter be a function? Huh, we want a variable at that place, of course! So what the compiler does when that happens is, again, to transform the function into a function pointer. Trying to pass a function will pass a pointer to that respective function instead. So, the following are the same (analogous to the array example):
void f(void g(void));
void f(void (*g)(void));
Note that parentheses around *g is needed. Otherwise, it would specify a function returning void*, instead of a pointer to a function returning void.
Back to arrays
Now, i said at the beginning that arrays can have an incomplete type - which happens if you don't give a size yet. Since we already figured that an array parameter is not existent but instead any array parameter is a pointer, the array's size doesn't matter. That means, the compiler will translate all of the following, and all are the same thing:
int main(int c, char **argv);
int main(int c, char *argv[]);
int main(int c, char *argv[1]);
int main(int c, char *argv[42]);
Of course, it doesn't make much sense to be able to put any size in it, and it's just thrown away. For that reason, C99 came up with a new meaning for those numbers, and allows other things to appear between the brackets:
// says: argv is a non-null pointer pointing to at least 5 char*'s
// allows CPU to pre-load some memory.
int main(int c, char *argv[static 5]);
// says: argv is a constant pointer pointing to a char*
int main(int c, char *argv[const]);
// says the same as the previous one
int main(int c, char ** const argv);
The last two lines say that you won't be able to change "argv" within the function - it has become a const pointer. Only few C compilers support those C99 features though. But these features make it clear that the "array" isn't actually one. It's a pointer.
A word of Warning
Note that all i said above is true only when you have got an array as a parameter of a function. If you work with local arrays, an array won't be a pointer. It will behave as a pointer, because as explained earlier an array will be converted to a pointer when its value is read. But it should not be confused with pointers.
One classic example is the following:
char c[10];
char **c = &c; // does not work.
typedef char array[10];
array *pc = &c; // *does* work.
// same without typedef. Parens needed, because [...] has
// higher precedence than '*'. Analogous to the function example above.
char (*array)[10] = &c;