C++ pointer passed by reference [duplicate] - c++

This question already has answers here:
why no implicit conversion from pointer to reference to const pointer
(4 answers)
Closed 1 year ago.
The following code won't compile:
void function(const char*& i){
// do something
}
int main() {
char a = 'a';
char *p = &a;
function(p);
return 0;
}
Can someone explain to me why?
What is the code doing? the code in the main function is passing a normal pointer to char to a pointer to a constant char.
As far as I know, as long as the passed pointer does not get violated in the function, the call should be allowed.
the address and value of a normal pointer to char may be modified, so such a pointer cannot be violated if passed by reference to a function whose sole argument is a pointer to a constant char because such a pointer can only modify its address, and that does not violate the restrictions of a normal pointer to char.
Edit:
The reason it does not compile is because when char* is converted to const char*, it results in an rvalue of type const char*. in C++, a non-const reference cannot be attached to an rvalue.
So the solution is simply to make the reference constant by adding const to give the argument the type constant pointer ... to a constant.
void function(const char* const& i){
// do something
}
int main() {
char a = 'a';
char *p = &a;
function(p);
return 0;
}

what you're doing is no much different from
const char* function(){
return "const char*";
}
int main() {
char *p = function(); // not compile
}
It's obviously wrong to have a non-const char* point to a constant
re comment: it is obviously very different. the const char*& means "I will not modify the value of a pointer to char passed to me"
NO it does not means that (godbolt)
void function(const char*& i){
i = "const char*"; // compiles fine
}
int main() {
const char *p;
function(p);
}

Related

Understanding char* - C++

I am writing a code in C++ right now, and I have a dilemma.
EDIT: I added the class relevant definition
_fullName is defined in the class as a private dm(char _fullName)
my class contains the getter method below:
char* getFullName() const { return this->_fullName; }
However, I had in the past cases in which I returned char* with const(const char*)
I can change the getter method to this one:
const char* getFullName() const { return this->_fullName; }
Both versions are compiling but I don't know how to choose.
I would take the second version, but I wonder Why even the version without the const is compiling? shouldn't it give an error when I remove the const keyword, because the function is a CONST member function and therefore the dms are const as well and cannot be returned without the const keyword???
This is the class relevant definition:
class Professional
{
private:
char* _ID;
char* _fullName;
int _age;
char* _profession;
}
First understand what const attached to a member function means. It determines the const-ness of the implicit this used for the member. Given this:
struct S
{
char value[10];
const char *mfn() const { return value; }
};
within the confines of mfn the implicit this is const S *. Furthermore, all references to members obtained therein are also const. In this case, that means value as an expression representation is const char (&)[10] before any further conversion are attached therein.
That's important.
In the correct posted example above there is an automatic conversion to temporary pointer, since const char(&)[10] converts to const char* without objection. However, the following will fail:
struct S
{
char value[10];
char *mfn() const { return value; }
};
The reason this will fail is simply because there is no conversion possible. value, remember, is const char (&)[10], and can only implicitly convert to const char*.
But how could it succeed? Well, consider this:
struct S
{
char *ptr;
char *mfn() const { return ptr; }
};
This will work. The reason is subtle, but obvious once you think about it. ptr is a char*. The attachment of const to this makes that char * const&, not const char *& (there is a difference; the former is a reference to a non-mutable pointer to mutable data, the latter is a reference to a mutable pointer to non-mutable data). Since return ptr is not mutating ptr (or anything else in the object), it is viable as a result.
In short, in your case it works because the pointer you are returning isn't via some implicit conversion from a const underlayment; it's just a value.
You have a few things going on here, in your example of the int num member this is not the same as a char * member.
lets expand your example a bit:
class Professional
{
int* func() const
{
return &myInt; // Fails because it returns a reference to a member variable
}
char* func() const
{
return &myChar; // Fails because it returns a reference to a member variable
}
int* func() const
{
return pInt; // ok because it returns a COPY of the member pointer
}
char* func() const
{
return pChar; // ok because it returns a COPY of the member pointer
}
int myInt;
char myChar;
int *pInt;
char *pChar;
Note: the two pointers getting returned by copy are ok. Its the pointers that are copies not the thing being pointed to. The memory that is pointed to is nothing to do with this class.
As to an answer to your question: there is a rule of thumb that is to apply const as much as possible - this helps to show other users your intent and gains benefits from compiler warnings / errors if a user tries to use your class in a way you did not intend. So in this case pass back a const char *.
Note: See this answer for more specific details here: What is the difference between const int*, const int * const, and int const *?

Why a constant integer pointer point to a non constant integer allowed?

I'm currently trying to learn some C++ and came across following unintuitive behavior. As t is a pointer to a const int I would expect *t to stay the same as long as we do not change t.
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int a = 3;
const int* t = &a; //Why is this allowed? a is NOT const int
a = 4;
cout << *t << endl; //This does then print 4
//*t = 4; //Throws error.
return 0;
}
Can anyone explain why this is does compile?
const int* t just means you can't change the value t pointing to by t, nothing more. The original value might be changed, but it has nothing to do with t's responsibility.
If you want to ensure the value won't be changed, you should let t point to a const, such as
const int a = 3;
const int* t = &a;
And for this case, you can't make a int* pointer point to it.
int* t = &a; // error
As t is a pointer to a const int I would expect *t to stay the same as long as we do not change t.
You cannot make that assumption in general, because t might point to a non-const object, such as in your example.
const int* t = &a; //Why is this allowed? a is NOT const int
Can anyone explain why this is does compile?
The rules of c++ allow the implicit conversion of T* to const T*. It is allowed, because it's very useful to have a pointer-to-const (or reference) to an non-const object. Pointer to const simply means that the object cannot be modified "through" the pointer. The object itself could be const, or non-const.
As an example of why it is useful, you could have some modifiable state as a private member of an object, and return const view to it so that others can observe, but not modify. A practical example of such is std::string::c_str(). It returns a const char* even though the internal buffer of the std::string is non-const.
As t is a pointer to a const int I would expect *t to stay the same as long as we do not change t.
The answer is simple: the const keyword in a pointer type declaration does not mean 'it is constant' but rather 'you are not allowed to modify it'.
This is useful for example when you create a variable and then call another function to do something with it, but you want to forbid modification:
extern int countZerosInArray( const int *array, int arrayLen);
int myVariableArray[ 100 ];
// ... fill the array - i.e. modify it!
int noOfZeros = countZerosInArray(myVariableArray, 100);
The countZerosInArray function is told it has read-only access to the array, although the array itself of course is not constant.
const int* t = &a; // int* or const int* can assgin to const int*

Weird behavior of pointer

When I compile the given code it doesn't produce any error or warnings. My question here is shouldn't the compiler produce error when compiling the following line *err = "Error message"; because we are dereferencing a pointer to pointer to constant char and assigning a string to it.
Is it allowable to assign anything inside a pointer anything other than address and exactly what is happening in this given scenario?
#include <stdio.h>
void set_error(const char**);
int main(int argc, const char* argv[])
{
const char* err;
set_error(&err);
printf("%s",err);
return 0;
}
void set_error(const char** err1)
{
*err1 = "Error message";
}
const char** err1
That's a pointer to a non-constant pointer to a constant object. Dereferencing it gives a non-constant pointer (to a constant object), which can be assigned to.
To prevent assigning to the const char*, that would also have to be const:
const char * const * err1
"Error message" is not a std::string. It's a const char[]. All string literals in C++ are const char[]. In C, they're char[].
Is it allowable to assign anything inside a pointer anything other than address and exactly what is happening in this given scenario?
You can assign pointer to a pointer. You think about pointer as an address, that's fine to understand concept, but do not mix it with data type. Data type is a pointer, not address. For example to assign address in memory to a pointer you need to cast it to a pointer:
char *pointer = reinterpret_cast<char *>( 0xA000000 );
You may ask how this would compile?
int array[10];
int *ptr = array;
That comes from C - array can be implicitly converted to a pointer to the first element. So it is pointer to pointer assignment again. Now about string literal with double quotes. It is an array as well:
const char str[] = "str";
const char str[] = { 's', 't', 'r', '\0' };
These 2 statements are pretty much the same. And as array can be implicitly converted to pointer to the first element it is fine to assign it to const char *

Explain: Converting 'char **' to 'const char **', Conversion loses qualifiers [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Implicit cast from char** to const char**
Given the following code:
void foo( const char ** buffer );
void bar()
{
char * buffer;
foo( &buffer );
}
Why is it that if the foo() function has a const char * parameter the compiler doesn't complain when passing in a char * variable into it? But when using char **, it cannot convert it to const char **? Does the compiler add any const qualifiers in the former case?
I've read section 4.4 of the C++ standard and it just confused me further.
Yes, you cannot implicitly convert from a T ** to a const T **, because the compiler can no longer guarantee that the const-ness won't be violated.
Consider the following code (borrowed from the C FAQ question on exactly this topic: Why can't I pass a char ** to a function which expects a const char **?):
const char c = 'x';
char *p1;
const char **p2 = &p1; // 3
*p2 = &c;
*p1 = 'X'; // 5
If the compiler allowed line 3, then line 5 would end up writing to a const object.
Consider:
char const someText[] = "abcd";
void
foo( char const** buffer )
{
*buffer = someText;
}
void
bar()
{
char* buffer;
foo( &buffer );
*buffer = 'x';
}
If this were legal, it would be possible to modify a const object
without an intervening const_cast. The conversion is forbidden
because it violates const-ness.
You are probably confusing the level of indirection the const applies to.
A char** can be described as pointer to a pointer to a character whereas a const char** can be described as pointer to a pointer to a constant character.
So when we write this differently, we have pointer to A (where A = pointer to character) and we have pointer to B (where B = pointer to a constant character).
Clearly now (I hope) A and B are distinct types, as such a pointer to A can not be assigned toa a pointer to B (and vice versa).

'const int' vs. 'int const' as function parameters in C++ and C

Consider:
int testfunc1 (const int a)
{
return a;
}
int testfunc2 (int const a)
{
return a;
}
Are these two functions the same in every aspect or is there a difference?
I'm interested in an answer for the C language, but if there is something interesting in the C++ language, I'd like to know as well.
The trick is to read the declaration backwards (right-to-left):
const int a = 1; // read as "a is an integer which is constant"
int const a = 1; // read as "a is a constant integer"
Both are the same thing. Therefore:
a = 2; // Can't do because a is constant
The reading backwards trick especially comes in handy when you're dealing with more complex declarations such as:
const char *s; // read as "s is a pointer to a char that is constant"
char c;
char *const t = &c; // read as "t is a constant pointer to a char"
*s = 'A'; // Can't do because the char is constant
s++; // Can do because the pointer isn't constant
*t = 'A'; // Can do because the char isn't constant
t++; // Can't do because the pointer is constant
const T and T const are identical. With pointer types it becomes more complicated:
const char* is a pointer to a constant char
char const* is a pointer to a constant char
char* const is a constant pointer to a (mutable) char
In other words, (1) and (2) are identical. The only way of making the pointer (rather than the pointee) const is to use a suffix-const.
This is why many people prefer to always put const to the right side of the type (“East const” style): it makes its location relative to the type consistent and easy to remember (it also anecdotally seems to make it easier to teach to beginners).
There is no difference. They both declare "a" to be an integer that cannot be changed.
The place where differences start to appear is when you use pointers.
Both of these:
const int *a
int const *a
declare "a" to be a pointer to an integer that doesn't change. "a" can be assigned to, but "*a" cannot.
int * const a
declares "a" to be a constant pointer to an integer. "*a" can be assigned to, but "a" cannot.
const int * const a
declares "a" to be a constant pointer to a constant integer. Neither "a" nor "*a" can be assigned to.
static int one = 1;
int testfunc3 (const int *a)
{
*a = 1; /* Error */
a = &one;
return *a;
}
int testfunc4 (int * const a)
{
*a = 1;
a = &one; /* Error */
return *a;
}
int testfunc5 (const int * const a)
{
*a = 1; /* Error */
a = &one; /* Error */
return *a;
}
Prakash is correct that the declarations are the same, although a little more explanation of the pointer case might be in order.
"const int* p" is a pointer to an int that does not allow the int to be changed through that pointer. "int* const p" is a pointer to an int that cannot be changed to point to another int.
See https://isocpp.org/wiki/faq/const-correctness#const-ptr-vs-ptr-const.
const int is identical to int const, as is true with all scalar types in C. In general, declaring a scalar function parameter as const is not needed, since C's call-by-value semantics mean that any changes to the variable are local to its enclosing function.
They are the same, but in C++ there's a good reason to always use const on the right. You'll be consistent everywhere because const member functions must be declared this way:
int getInt() const;
It changes the this pointer in the function from Foo * const to Foo const * const. See here.
Yes, they are same for just int
and different for int*
This isn't a direct answer but a related tip. To keep things straight, I always use the convection "put const on the outside", where by "outside" I mean the far left or far right. That way there is no confusion -- the const applies to the closest thing (either the type or the *). E.g.,
int * const foo = ...; // Pointer cannot change, pointed to value can change
const int * bar = ...; // Pointer can change, pointed to value cannot change
int * baz = ...; // Pointer can change, pointed to value can change
const int * const qux = ...; // Pointer cannot change, pointed to value cannot change
I think in this case they are the same, but here is an example where order matters:
const int* cantChangeTheData;
int* const cantChangeTheAddress;