Implicit conversions and pointers? - c++

Why does an implicit conversion not happen when making a float pointer point to an integer, such as when you assign a float variable an integer value?

I think it's easy to reason about it via allegory.
Think of a pointer as slip of paper with the address of a house written on it. The type of the data is the name of the person who resides in said house.
Now, casting a pointer is like taking that slip of paper, keeping the address the same (for the most part), but changing the name of the person who supposedly lives in the house.
Just because we changed the name on the paper from Alice to Bob, doesn't mean Alice magically becomes Bob. The paper doesn't influence the house.
That's why using such a pointer has undefined behavior. The code think it's addressing a Bob, when in fact it's Alice.

Because a pointer, well, it needs to point someplace. Because that's what a pointer is. When you have an
int *p;
And you dereference it, like, for example:
foo(*p);
You expect to dereference the pointer and end up with an int.
Now, if you start with a float:
float *q;
And let's say, for the sake of argument, you can do this:
int *p=q;
Then where exactly do you expect this pointer to point to, now? It can't point to wherever q is pointing to. Because the only thing over there is a float.
So, you have to do it yourself, manually:
int n= (int)*q;
int *p= &n;
And, of course, you have to make sure that n remains in scope as long as the p pointer gets dereferenced. And, if *q is changed to a different value, it won't affect what p is pointing to. But those would be different questions...

Related

Can anybody explain why *var=i is valid [duplicate]

char a[] = "hello";
My understanding is that a acts like a constant pointer to a string. I know writing a++ won't work, but why?
No, it's not OK to increment an array. Although arrays are freely convertible to pointers, they are not pointers. Therefore, writing a++ will trigger an error.
However, writing
char *p = a;
p++;
is fine, becuase p is a pointer, with value equal to the location of a's initial element.
a++ is not well-formed since a decays to a pointer, and the result of the decay is not an lvalue (so there is no persistent object whose state could be "incremented").
If you want to manipulate pointers to the array, you should first create such a pointer:
char* p = a; // decayed pointer initializes p
a++; // OK
++a; // even OKer
This is a very good question actually. Before discussing this, let's back to the basic concepts.
What happens when we declare a variable ?
int a=10;
Well, we get a memory location to store the variable a. Apart from this an entry is created into Symbol table that contains the address of the variable and the name of the memory location (a in this case).
Once the entry is created, you can never change anything into the symbol table, means you can't update the address. Getting an address for a variable is not in our hand, it's done by our computer system.
Let's say, we get address 400 for our variable a.
Now computer has assigned an address for the variable a, so at a later point, we can't ask computer to change this address 400 because again, it's not in our hand, our computer system does it.
Now you have an idea about what happens when we declare a variable.let's come to our question.
Let's declare an array.
int arr[10]
So, when we declare this array, we create the entry into the symbol table and, store the address and the name of the array into the symbol table.
let's assume we get address 500 for this variable.
Let's see what happens when we want to do something like this :
arr++
when we increment arr, we want to increment 500, that is not possible and not in our hand, because it has been decided by the computer system, so we can't change it.
instead of doing this we can declare a pointer variable
int * p= &arr;
What happens in this situation is: again an entry is created into the symbol table that stores the name and the address of the pointer variable p.
So when we try to increment p by doing p++, we are not changing the value into the symbol table, instead we are changing the value of the address of the pointer variable, that we can do and we are allowed to do.
Also it's very obvious that if we will increment the a the ultimately we are going to loss the address of our array. if we loss the address of array then how will we access the array at a later point ?
It is never legal in C to assign to an expression of array type. Increment (++) involves assignment, and is thus also not legal.
What you showed at the top is a special syntax for initializing a char array variable.
I think this answer here explains "why" it's not a good idea;
It's because array is treated as a constant pointer in the function it is declared.
There is a reason for it. Array variable is supposed to point to the first element of the array or first memory instance of the block of the contiguous memory locations in which it is stored. So, if we will have the liberty to to change(increment or decrement ) the array pointer, it won't point to the first memory location of the block. Thus it will loose it's purpose.

How to change the address a pointer is pointing to in C++

While experimenting with pointers, I had the idea to change the address a pointer. I tried the following:
int* pointer;
&pointer = 0x28ff0d; //To point to an empty space in memory
But that threw out an error (Details: (here) in line 2, lvalue required as left operand [...]), so I guess it's impossible? I'm not trying to make a nullpointer, but litterally to change the memory address
For obvious reasons, setting a pointer to a hardcoded address is a bad idea. But, you can do so by reinterpret_cast<>ing the address to the type you're assigning it to, like so:
int * pointer = reinterpret_cast<int *>(0xDEADBEEF);
or
int * pointer = &some_int;
. . .
pointer = reinterpret_cast<int *>(0xDEADBEEF);
Note that dereferencing pointer in this case is undefined behavior... but doing this might still be useful for something like debugging a use-after-free, where a sentinel value like 0xDEADBEEF would clearly communicate that you had already freed that memory.
Obviously the much more common, useful, and safe case for changing the address you are pointing to would be to take the address of a different (real) piece of data:
int * pointer = &some_int;
int new_val = 1234;
pointer = &new_val; // *pointer is now 1234
You can never change the address of a variable. So whatever T is (be it an intrinsic type like int or double, a struct, a pointer or an array, the following is forbidden in C++:
T var;
&var = anything; // WRONG! &var is not a lvalue
The error lvalue required as left operand means that you can only assign to something that can receive a new value, and the address of a variable is not.
A pointer is a variable. Any variable has an address where it's located. So if you've declared a varible like e.g. int x;, then &x is the address where that variable resides.
A pointer is a variable which resides somewhere, but in addition it has a value, which happens to be an address of some other variable. So if you've declared a pointer int* x;, have written something to it, then x will represent some address you've written to it, and *x will be the value pointed to by the pointer.
So your syntactic mistake was using & where you should have just used the variable name, without &. After this is clear, be sure to read the other answers which explain further problems with your code.
int* pointer;
&pointer = 0x28ff0d;
This will throw error because &pointer is not an lvalue. On the left side of the assignment operator there must be an lvalue.

Difference between pointer declaration and indirection

I'm reading a book and I have doubts about what each of these syntax does. The first three lines I can understand but the following do not. Thank you very much if you help me, Julieta
int m; //m is int variable
int *p; //Pointer p pointing to an integer value
p=&m //The memory address of the variable m is assigned to p
float *longitud;
longitud=&cable1;
*longitud=40.5;
The concepts of value, pointer, and reference often trip people up, especially as they are often taught to look at them in terms of implementation and not in terms of the language.
A value is a thing that exists and has meaning. It always has a type (a constraint on its meaning) like int, float, char, and vector<string>.
An object is a value that exists somewhere in memory. (And not, say, mangled into a machine instruction code or produced on-the-fly in some way. That is, I could take out my memory chip and stick my finger on it, were my fingers nimble enough.)
A reference is an alias — a name for an object. The name is convenient for us as programmers. How the compiler maintains that name does not really matter. All that matters (language perspective!) is that if you have a name, you have direct access to an object.
To put that into perspective, whenever you name an object, you obtain a direct reference to that object. You can manipulate that object directly using its name.
A pointer is a value. Its type is a location in the computer’s memory of some object. With this location, I can gain access to the object’s value. In other words, I can use a pointer to gain a direct reference to an object.
Vocabulary + time = fickle understandings and encourage people to ask useless things2. Let’s clean our minds up a little.
First, a pointer is not a reference, it is an indirect reference. In order to get an actual, or direct, reference to a pointed-to object, we “dereference” the pointer. In other words, we perform a magic that transforms a pointer value to obtain a reference to an object.
The mechanics of how a pointer works are typically framed in terms of how the underlying hardware does something like “follows a pointer to a value”. We draw pictures with arrows and everything. We seem to forget to ask how this magic works. No one asks how variable names work either, but it is the exact same kind of magic. We simply trust when told “the compiler takes care of it”.
What is missed is the distinction between a (direct) reference (an alias or name for an object) and an indirect reference (a pointer or other thing that can be used to obtain a reference to an object).
Before C++ the difference between direct and indirect references really only made sense in the context of a pointer, and it was easy to call a pointer “a reference” instead of the full phrase “an indirect reference”, and so the vocabulary words mixed around in our heads, and we began to misunderstand the actual concepts involved.
Enter C++, stage left. We now have things called “references” in addition to pointers. In terms of the language, they are true aliases for other objects1.
To put it to example:
int x = 7; // "x" is a reference to the integer object with value 7
int& y = x; // "y" is a reference to the same integer object as "x".
int* p = // "p" is a pointer object whose value is an
// indirect reference to some integer object:
&x; // The & operator obtains an indirect reference (or pointer value) to "x"
And here is the last point. There are more than one meaning for "&"!
When attached to a type, it means that the type is a direct reference to some object
When attached to an object, it means that an indirect reference to that object is obtained
1 In C++, the abstraction leaks, because the lifetime of an object is bound only to the original reference. But that’s neither here nor there. There are other topics that deal with that here at SO.
2 So, to answer everyone’s favorite question: is a reference a pointer or not? The answer is, it doesn’t matter. (Unless you are writing a compiler.) You are asking implementation details about magic used to maintain a language-level concept. So sometimes it may be an actual pointer, sometimes it may simply be another entry in the compiler’s local symbol table, and it may even be something else if the compiler writer thinks it useful and appropriate.
3Language gets to be fuzzy. I had previously said "p" is a pointer. Technically, it is an object whose value is a pointer type. We can usually get away by just saying what type of thing an object is, though, and be well-understood. It is only when we are splitting hairs (in context) that the vocabulary needs more care, as it does here.
longitude is a pointer to a float variable
longitud=&cable1 assigns the address of cable1 (presumably a float?) to longitud, which now references cable1.
*longitud=40.5 dereferences longitude and assign it value 40.5. Because longitud references cable1, this assigns the value to cable1. That is *longitud and cable1 are the same thing.
None of this really relates to the question title "Difference between pointer declaration and indirection" - indirection is a general computing concept, and pointers are the means by which indirection is effected in C and C++.
Suppose you add one more (different) line in each section:
int m; // m is int variable
int *p; // pointer p is pointing to an integer value
p = &m; // the memory address of m is assigned to p
*p = 42; // ADDED: assign 42 to m, where p points to
float cable1; // ADDED: the variable where longitud points
float *longitud; // pointer longitud is pointing to a float value
longitud = &cable1; // the memory address of cable1 is assigned to longitud
*longitud = 40.5f; // assign 40.5 to cable1, where longitud points to
This completes the similar examples, which use different variable types.
After executing the lines
float cable1; // ADDED: the variable where longitud points
float *longitud; // pointer longitud is pointing to a float value
longitud = &cable1; // the memory address of cable1 is assigned to longitud
the following conditions are true:
longitude == &cable1
*longitude == cable1
IOW, the expression *longitud is equivalent to the expression cable1. So when you write
*longitud = 40.5f;
this is equivalent to writing
cable1 = 40.5f;
The * operator dereferences the longitud pointer, such that the expression *longitud evaluates to the same thing as cable1.
Cable1 needs to have a place memory before longitud can point to it.
The first 3 lines do this:
Set aside memory for an int.
Create an int pointer.
Get the int pointer to point at the int's memory address. Pointer references int.
The second 3 lines do this:
Create a float pointer.
Get the float pointer to point to a nonexistent address.
Try to assign a float value to that address.
If on line 4 you wrote:
float cable1;
You would have set aside memory and everything would work fine.
On the topic, you mean pointer declaration and dereferencing. I can give a short set of examples, though it mostly takes reading and practice to learn. Try these out and get a feel.
float f = 22.2f; //sets aside memory for a float with the name "f", stores 22.2
float *pf; //declares a float pointer.
pf = &f; //sets pf to point to f's memory address. pf references p.
printf("%f", *pf); //prints the value at the referenced address (22.2)
printf("%x", pf); //prints the memory address of the pointer itself
*pf = 33.3f; //changes the value at f's address to 33.3 (from 22.2)
f = 44.4f; //changes the value at f's address to 44.4 (from 33.3)
float *pf2;
*pf2 = 33.3 //BAD. pf2 is not assigned to an address, no value to change.
*pf2 = f; //BAD. pf2 has no memory address to copy the value to.
*pf2 = pf; //BAD. several reasons.
pf2 = pf; //pf2 now points to f's address, too.
pf2 = &f; //redundant. Same as the last line.
*pf2 = 55.5 //f has changed to 55.5. both pf2 and pf point to it.
Just think of the * as standing for "pointer" when you declare. When you use * later, it means "dereference." Dereferencing a pointer means you want to look at/use/change the referenced value. Later on, you'll learn that pointers can point to other pointers. So the value of a (char **) type is type (char *), rather than type (char).
If you don't have a book, I recommend C Programming - A Modern Approach 2nd Edition. It's a little dated but an excellent way to learn the fundamentals.

Can a pointer point to a value and the pointer value point to the address?

Normal pointer usage as I have been reading in a book is the following:
int *pointer;
int number = 5;
pointer = &number;
Then *pointer has a value of 5.
But does this work the other way around? I mean:
int *pointer;
int number = 5;
*pointer = &number;
Here does pointer contain the value 5 and *pointer holds the address of number?
Thanks.
In
int *pointer;
int number = 5;
*pointer = &number;
you never assign a valid address to pointer, so dereferencing that pointer (as is done by the expression *pointer) is not valid.
Analogy from the department of far-fetched analogies:
You use pointers many times every day without even thinking about it.
A pointer is an indirection - it tells you where something is, or how it can be reached, but not what that thing is.
(In a typed language, you can know what kind of thing it is, but that's another matter.)
Consider, for example, telephone numbers.
These tell you how to reach the person that the phone number belongs to.
Over time, that person may change - perhaps somebody didn't pay their bills and the number was reassigned - but as long as the number is valid, you can use it to reach a person.
Using this analogy, we can define the following operations:
&person gives you a person's phone number, and
*number gives you the person that the number belongs to.
Some rules:
There are only two types in this language - persons and phone numbers.
Only persons can have phone numbers; &number is an error, as is *person.
An unspecified phone number reaches the General Manager of Customer Services at Acme, Inc.
Now, your first example would translate to
PhoneNumber n;
Person Bob;
n = &Bob;
which makes sense; n now holds Bob's phone number.
Your second example would translate to
PhoneNumber n;
Person Bob;
*n = &Bob;
which would say "replace the General Manager of Acme Inc's Customer Services with Bob's phone number", which makes no sense at all.
And your final question,
Here does pointer contain the value 5 and *pointer holds the address of number?
would translate to
Is this phone number the same thing as Bob, and if you call it, will Bob's phone number answer?
which I am sure you can see is a rather strange question.
Your second case will not compile, because the assignment *pointer = &number involves incompatible types (int on the left, a pointer to int on the right) which makes the assignment invalid.
If you somehow coerce the assignment into compiling, then pointer is not initialised. Accessing its value, let alone dereferencing it (e.g. evaluating *pointer or assigning to it as in *pointer = number or *pointer = 5) gives undefined behaviour. Anything can happen then .... depending on circumstances, a common result of undefined behaviour is an abnormal program termination.
*pointer = &number; is not valid C.
*pointer is of type int and &number is of type int*. This isn't a valid form of assignment and will not compile on a standard C compiler.
You can store numbers inside pointer variables, but then you must use an explicit cast to force a type conversion. Some compilers allow it without an explicit cast, but note that doing so is a non-standard extension.
And of course, note that you haven't set pointer to point at an allocated memory address, so you can't store anything inside where it points.
If you do an explicit cast such as
pointer = &something;
*pointer = (int)&number;
then it is allowed in C, but if you try to de-reference that pointer, the behavior is implementation-defined. It could possibly also be undefined behavior in case of misalignment etc. See C11 6.3.2.3:
An integer may be converted to any pointer type. Except as previously
specified, the result is implementation-defined, might not be
correctly aligned, might not point to an entity of the referenced
type, and might be a trap representation.
When you create a pointer variable, initially it will have garbage value (let say 300 address location). Hence when you dereference pointer(*300), it would give another garbage value(value at 300 address location) or error (strictly speaking anything may happen depending on your computer).
In the third step, &number:- which is also another number and your are trying to assign a number to *pointer(may be another number) which not possible. (It is like this:- 5=6). Hence it will be an error.
For you to write an assignment x = y, both x and y must be, or be implicitly convertible to, the same type (or x must have a user-defined assignment operator taking an argument matching the type of y, or ... OK, there are a few possibilities, but you get the idea).
Now, let's look at the statement
*pointer = &number;
Here, *pointer has type int& - you followed the pointer to get a (reference to) the integer stored at that location. Let's ignore, for now, the fact that your pointer was uninitialized and following it results in undefined behaviour.
The right hand side, &number, is taking a pointer to an integer variable, so the type is int*.
So, the expression doesn't make sense at all, just in terms of the type system: there is no way to assign int* to int&. It doesn't mean anything.
Let's relate it back to the English language of your question
Here does pointer contain the value 5 and *pointer holds the address of number?
That translates directly to the type system, and hence also doesn't mean anything. Again, we can break it down
does pointer contain the value 5
a pointer contains a location. The only time it would make sense to talk about a pointer having a literal value (other than nullptr) would be on a platform where there were well-known addresses - this is rare, and '5' is very unlikely to be a well-formed address anyway
*pointer holds the address
well, there is a case where *pointer could hold an address - it's where *pointer is itself is a pointer, meaning the variable pointer is a pointer-to-pointer such as int **. That isn't the case here: we know the type of *pointer in your code, and it is int&, not int*.

About pointer and reference syntax

Embarrassing though it may be I know I am not the only one with this problem.
I have been using C/C++ on and off for many years. I never had a problem grasping the concepts of addresses, pointers, pointers to pointers, and references.
I do constantly find myself tripping over expressing them in C syntax, however. Not the basics like declarations or dereferencing, but more often things like getting the address of a pointer-to-pointer, or pointer to reference, etc. Essentially anything that goes a level or two of indirection beyond the norm. Typically I fumble with various semi-logical combinations of operators until I trip upon the correct one.
Clearly somewhere along the line I missed a rule or two that simplifies and makes it all fall into place. So I guess my question is: do you know of a site or reference that covers this matter with clarity and in some depth?
I don't know of any website but I'll try to explain it in very simple terms. There are only three things you need to understand:
variable will contain the contents of the variable. This means that if the variable is a pointer it will contain the memory address it points to.
*variable (only valid for pointers) will contain the contents of the variable pointed to. If the variable it points to is another pointer, ptr2, then *variable and ptr2 will be the same thing; **variable and *ptr2 are the same thing as well.
&variable will contain the memory address of the variable. If it's a pointer, it will be the memory address of the pointer itself and NOT the variable pointed to or the memory address of the variable pointed to.
Now, let's see a complex example:
void **list = (void **)*(void **)info.List;
list is a pointer to a pointer. Now let's examine the right part of the assignment starting from the end: (void **)info.List. This is also a pointer to a pointer.
Then, you see the *: *(void **)info.List. This means that this is the value the pointer info.List points to.
Now, the whole thing: (void **)*(void **)info.List. This is the value the pointer info.List points to casted to (void **).
I found the right-left-right rule to be useful. It tells you how to read a declaration so that you get all the pointers and references in order. For example:
int *foo();
Using the right-left-right rule, you can translate this to English as "foo is a function that returns a pointer to an integer".
int *(*foo)(); // "foo is a pointer to a function returning a pointer to an int"
int (*foo[])(); // "foo is an array of pointers to functions returning ints"
Most explanations of the right-left-right rule are written for C rather than C++, so they tend to leave out references. They work just like pointers in this context.
int &foo; // "foo is a reference to an integer"
Typedefs can be your friend when things get confusing. Here's an example:
typedef const char * literal_string_pointer;
typedef literal_string_pointer * pointer_to_literal_string_pointer;
void GetPointerToString(pointer_to_literal_string_pointer out_param)
{
*out_param = "hi there";
}
All you need to know is that getting the address of an object returns a pointer to that object, and dereferencing an object takes a pointer and turns it into to object that it's pointing to.
T x;
A a = &x; // A is T*
B b = *a; // B is T
C c = &a; // C is T**
D d = *c; // D is T*
Essentially, the & operator takes a T and gives you a T* and the * operator takes a T* and gives you a T, and that applies to higher levels of abstraction equally e.g.
using & on a T* will give you a T**.
Another way of thinking about it is that the & operator adds a * to the type and the * takes one away, which leads to things like &&*&**i == i.
I'm not sure exactly what you're looking for, but I find it helpful to remember the operator precedence and associativity rules. That said, if you're ever confused, you might as well throw in some more parens to disambiguate, even if it's just for your benefit and not the compiler's.
edit: I think I might understand your question a little better now. I like to think of a chain of pointers like a stack with the value at the bottom. The dereferencing operator (*) pops you down the stack, where you find the value itself at the end. The reference operator (&) lets you push another level of indirection onto the stack. Note that it's always legal to move another step away, but attempting to dereference the value is analogous to popping an empty stack.