I am trying to understand the difference between these two things in C to understand conceptually the differences.
Here is example:
int y = *(int *)x;
vs.
int * y = (int*)x;
The second option is casting x to a int pointer, but not doing anything with the pointer yet (aside from storing it). At some point in the future, that pointer could be dereferenced to produce an int (assuming aliasing rules aren't being broken, the original pointer is valid, etc.) or to store an int (by assigning to the dereferenced pointer, e.g. *y = 5;).
The first option is the second option, followed immediately by dereferencing the resulting pointer to get the value it points to. The new pointer isn't saved off, it's just used to load the int it points to, then the pointer is discarded and only the int is stored.
Related
In int *x x is a pointer to integer.
If we initialize with a statement something like this: int *x = &p now x is pointing to the address of "p".
The value that it produces is: 6422036
Does that mean in int *x x is a pointer to the type int or it's a pointer to an integer value?
Is it conceptually something like int *x = &int as default?
When I compile this:
#include <stdio.h>
main ()
{
int *x;
printf("%d", x);
return 0;
}
It gives the value 16.
What does it mean?
I think your question is based on a misunderstanding, so I am going to do some bean-counting on your phrasings. (Not contradicting ikegami by the way, just trying to provide a different approach or viewpoint.)
In int *x x is a pointer to integer.
Yes.
if we initialize the statement with something like this: int *x = &p now x is pointing to the address of p.
Not exactly, now x contains the address of p (which hopefully is an int). It is considered to point to p.
The value that it produces is: 6422036
If you say so, but that is not reproducable and you should probably never think or know about that value. Any other value at this point would means the same - or nothing.
Does that mean in int *x x is a pointer to the type int or it's a pointer to an integer value?
Yes.
To be precise, for a C programmer those are one and the same thing.
Whatever it is pointing to is an integer value, i.e. it is of int type. (Skipping the differences of unsigned int, long int, short etc., I am convinced you are not asking about that.)
If you see a difference between those two, then your understanding is not C (I suspect it comes from a different language, see introspection as discussed by ikegami.)
is it conceptually something like int *x = &int as default?
No. There is no such thing as &int in C. It is more like
int *x; /* Don't you dare dereference this before you assigned a decent address.
and be sure to assign an address of something you are actually allowed
to at least read - or expect little demons flying out of your nose. */
Note that "demons flying out of your nose" is practically a technical term used among programmers to describe that absolutely anything can happen, usually undesired things. Most undesired possible result is that it passes all tests and then fails catastrophically in the most inconvenient situation.
Actually it is called undefined behaviour.
C doesn't have reflection. There's no int type in memory, just values of that type. As such, x isn't a pointer to the type int. It is indeed a pointer to an integer value.
Given int *x, we can say:
*x is an int
x is an int*, which is to a pointer to an int.
That assumes x has been properly initialized and isn't NULL. This isn't the case in your program. Reading x before giving it a value is a bug.
Also, providing a pointer to %d is a bug. To display a pointer, you need
printf("%p\n", (void*)x); // One of the weird times when a `void*` cast is needed.
Again, this is only legit after you initialize x.
A valid program:
#include <stdio.h>
int main(void)
{
int i = 123;
int *p = &i;
printf("%p\n", (void*)p);
printf("%p\n", (void*)&i);
printf("%p\n", (void*)&p);
printf("%d\n", i);
printf("%d\n", *p);
return 0;
}
Does that mean in int *x x is a pointer to the type int or it's a pointer to an integer value?
x is an object stores values of type int *; that is, it stores the address of an int object.
It gives the value 16.
What does it mean?
It means you've invoked undefined behavior - you're using the wrong format specifier for the type.
The proper way to print a pointer value is
printf( "%p\n", (void *) x );
In the declaration
int *x;
the initial value of x is indeterminate - it could be anything, from 0x00000000 to 0x00000010 (16) to 0xDEADBEEF to anything else.
There's nothing magic about pointer variables - they store values of a specific type, like an int variable stores integer values and double variable stores floating-point values.
Pointer declaration syntax and operations on pointers are a little non-intuitive and hard to grasp at first, but pointer values themselves are relatively simple things to understand; they're just addresses1 of objects (or functions) in memory.
There's no single pointer type - an int * is a distinct type from a double *, which is a distinct type from a char *, etc. Different pointer types may have different sizes or representations, but on platforms like x86 they all have the same representation.
In a declaration, the presence of a unary * in the declarator means the variable has pointer type:
T *p; // p is a pointer to T
T *ap[N]; // ap is an array of pointers to T
T (*pa)[N]; // pa is a pointer to an array of T
T *fp(); // fp is a function returning a value of type pointer to T
T (*pf)(); // pf is a pointer to a function returning a value of type T
T **pp; // pp is a pointer to pointer to T - it stores the address of
// an object of type T *
In an expression, the presence of the unary * operator means we want to dereference the pointer and obtain the value of the thing it points to:
int x = 10;
int *p = &x; // save the address of x in p
printf( "%d\n", *p ); // print the value stored in x by dereferencing p
More properly, they're abstractions of addresses. Whether those addresses are physical or virtual depends on the environment you're operating in.
I am trying to figure out all the possible ways I could fill in int pointer k considering the following givens:
int i = 40;
int *p = &i;
int *k = ___;
So far I came up with "&i" and "p". However, is it possible to fill in the blank with "*&p" or "&*p"?
My understanding of "*&p" is that it is dereferencing the address of an integer pointer. Which to me means if printed out would output the content of p, which is &i. Or is that not possible when initializing an int pointer? Or is it even possible at all anytime?
I understand "&*p" as the memory address of the integer *p points to. This one I am really unsure about also.
If anyone has any recommendations or suggestions I will greatly appreciate it! Really trying to understand pointers better.
Pointer Basics
A pointer is simply a normal variable that holds the address of something else as its value. In other words, a pointer points to the address where something else can be found. Where you normally think of a variable holding an immediate values, such as int i = 40;, a pointer (e.g. int *p = &i;) would simply hold the address where 40 is stored in memory.
If you need the value stored at the memory address p points to, you dereference p using the unary '*' operator, e.g. int j = *p; will initialize j = 40).
Since p points to the address where 40 is stored, if you change that value at that address (e.g. *p = 41;) 41 is now stored at the address where 40 was before. Since p points to the address of i and you have changed the value at that address, i now equals 41. However j resides in another memory location and its value was set before you changed the value at the address for i, the value for j remains 40.
If you want to create a second pointer (e.g. int *k;) you are just creating another variable that holds an address as its value. If you want k to reference the same address held by p as its value, you simply initialize k the same way you woul intialize any other varaible by assigning its value when it is declared, e.g. int *k = p; (which is the same as assigning k = p; at some point after initialization).
Pointer Arithmetic
Pointer arithmetic works the same way regardless of the type of object pointed to because the type of the pointer controls the pointer arithmetic, e.g. with a char * pointer, pointer+1 points to the next byte (next char), for an int * pointer (normal 4-byte integer), pointer+1 will point to the next int at an offset 4-bytes after pointer. (so a pointer, is just a pointer.... where arithmetic is automatically handled by the type)
Chaining & and * Together
The operators available to take the address of an object and dereference pointers are the unary '&' (address of) operator and the unary '*' (dereference) operator. '&' in taking the address of an object adds one level of indirection. '*' in dereferening a pointer to get the value (or thing) pointed to by the pointer removes one level of indirection. So as #KamilCuk explained in example in his comment it does not matter how many times you apply one after the other, one simply adds and the other removes a level of indirection making all but the final operator superfluous.
(note: when dealing with an array-of-pointers, the postfix [..] operator used to obtain the pointer at an index of the array also acts to derefernce the array of pointers removing one level of indirection)
Your Options
Given your declarations:
int i = 40;
int *p = &i;
int *k = ___;
and the pointer summary above, you have two options, both are equivalent. You can either initialize the pointer k with the address of i directly, e.g.
int *k = &i;
or you can initialize k by assinging the address held by p, e.g.
int *k = p;
Either way, k now holds, as its value, the memory location for i where 40 is currently stored.
I am a little bit unsure what you're trying to do but,
int* p = &i;
now, saying &*p is really just like saying p since this gives you the address.
Just that p is much clearer.
The rule is (quoting C11 standard footnote 102) that for any pointer E
&*E is equivalent to E
You can have as many &*&*&*... in front of any pointer type variable that is on the right side of =.
With the &*&*&* sequence below I denote: zero or more &* sequences. I've put a space after it so it's, like, somehow visible. So: we can assign pointer k to the address of i:
int *k = &*&*&* &i;
and assign k to the same value as p has:
int *k = &*&*&* p;
We can also take the address of pointer p, so do &p, it will have int** - ie. it will be a pointer to a pointer to int. And then we can dereference that address. So *&p. It will be always equal to p.
int *k = &*&*&* *&p;
is it possible to fill in the blank with "*&p" or "&*p"?
Yes, both are correct. The *&p first takes the address of p variables then deferences it, as I said above. The *&variable should be always equal to the value of variable. The second &*p is equal to p.
My understanding of "*&p" is that it is dereferencing the address of an integer pointer. Which to me means if printed out would output the content of p, which is &i. Or is that not possible when initializing an int pointer? Or is it even possible at all anytime?
Yes and yes. It is possible, anytime, with any type. The &* is possible with complete types only.
Side note: It's get really funny with functions. The dereference operator * is ignored in front of a function or a function pointer. This is just a rule in C. See ex. this question. You can have a infinite sequence of * and & in front of a function or a function pointer as long as there are no && sequences in it. It gets ridiculous:
void func(void);
void (*funcptr)(void) = ***&***********&*&*&*&****func;
void (*funcptr2)(void) = ***&***&***&***&***&*******&******&**funcptr;
Both funcptr and funcptr2 are assigned the same value and both point to function func.
If I have a pointer to an array of char*s, in other words, a char** named p1, what would I get if I do (char*)p1? I’m guessing there would be some loss of precision. What information would I lose, and what would p1 now be pointing to? Thanks!
If you had asked about converting an int ** to an int *, the answer would be different. Let’s consider that first, because I suspect it is more representative of the question you intended to ask, and the char * case is more complicated because there is a special purpose involved in that.
Suppose you have several int: int a, b, c, d;. You can make an array of pointers to them: int *p[] = { &a, &b, &c, &d };. You can also make a pointer to one of these pointers: int **q = &p[1];. Now q points to p[1], which contains the address of b.
When you write *q, the compiler knows q points to a pointer to an int, so it knows *q points to an int. If you write **q, the compiler, knowing that *q points to an int, will get *q from memory and use that as an address to get an int.
What happens if you convert q to an int * and try to use it, as in printf("%d\n", * (int *) q);? When you convert q to an int * you are (falsely) telling the compiler to treat it as a pointer to an int. Then, * (int *) q tells the compiler to go to that address and get an int.
This is invalid code—its behavior is not defined by the C standard. Specifically, it violates C 2018 6.5 7, which says that an object shall be accessed only by an lvalue expression that has a correct type—either a type compatible with that of the actual object or certain other cases, none of which apply here. At the place q points, there is a pointer to an int, but you tried to access it as if it were an int, and that is not allowed.
Now let’s consider the char ** to char * case. As before, you might take some char **q and convert it to char *. Now, you are telling the compiler to go to the place q points, where there is a pointer to a char, and to access that memory location as if there were a char there.
C has special rules for this case. You are allowed to examine the bytes that make up objects by accessing them through a char *. So, if you convert a char ** to char * and use it, as in * (char *) q, the result will be the first (lowest addressed) byte that makes up the pointer there. You can even look at the rest of the bytes, using code like this:
char *t = (char *) q;
printf("%d\n", t[0]);
printf("%d\n", t[1]);
printf("%d\n", t[2]);
printf("%d\n", t[3]);
This code will show you the decimal values for the first four bytes that make up the pointer to char that is at the location specified by q.
In summary, converting a char ** to char * will allow you to examine the bytes that represent a char *. However, in general, you should not convert pointers of one indirection level to pointers of another indirection level.
I find pointers make much more sense when I think of them as memory addresses rather than some abstract high level thing.
So a char** is a memory address which points to, a memory address which points to, a character.
0x0020 -> 0x0010 -> 0x0041 'A'
When you cast you change the interpretation of the data, not the actual data. So the char* is
0x0020 -> 0x0010 (unprintable)
This is almost certainly not useful. Interpreting this random data as a null terminated string would be potentially disastrous.
I have to questions about pointers; one theoretical and one practical.
Why, when declaring a pointer in C, must I preface the *var with a type. If a pointer is simply a variable that contains a memory address why does the compiler/language need any more information than that it is a pointer. What is the difference between an int * and a char *. Does this imply that an int * is pointing a some location that contains 2-4 bytes of memory and a char * contains only 1? I have never read anything about the underlying reasoning for why the type matters if ultimately it is a variable pointing to some hexadecimal number as evidence by %p printing them.
Secondly, given this code
int t = 10;
int *i = &t;
int *j = i;
--
*i == 10;
*j == 10;
Why is it that *j is equal to 10 instead of **j being 10? If j is a pointer to i which is a pointer to t which is 10 don't i need to double dereference the variable j? When writing this code in xcode it forces me to use *j.
So these are a few examples of confusion I have had with pointers.
The datatype is required in order to know how many bytes to read when the pointer is dereferenced.
int *i = &t;
Here, the value stored in i is the address of t.
int *j = i;
So now, the value stored in j is the value stored in i which is the address of t. If you wanted to do a double dereference, you'd need to store the address of i.
int **j = &i
why does the compiler/language need any more information than that it is a pointer
To use the pointer only, the compiler doesn't. The type void* means "a pointer to anything".
However, to use the value that is being pointed to, the compiler needs to know the type of what is being pointed to, so that it knows what can be done with it. Dereferencing a void* will cause a compiler error, unless you first cast it to a typed pointer.
Secondly, given this code
j is not a pointer to i. The assignment int *j = i; sets j to the same value as i, which is the address to t (so j would now point to t).
To make j a pointer to i, you would need to declare it as int **j = &i;
why does the compiler/language need any more information than that it is a pointer.
That's because different data types are of different size and size of data types are needed to allocate memory.
What is the difference between an int * and a char *.
int * is a pointer to int and char * is a pointer to a char.
Why is it that *j is equal to 10 instead of **j being 10? If j is a pointer to i which is a pointer to t which is 10 don't i need to double dereference the variable j?
int *j = i; tells the compiler that declare j as pointer to int and point this pointer to the memory location where pointer i points to. Therefore j is a pointer to variable t.
C is a statically typed language. There are other languages, like JavaScript for example, which are dynamically typed, where you can assign objects of different types to the same variable.
Both approaches have their advantages and disadvantages, the most important advantage of statically typed languages is that many errors can be caught at compilation.
It's a design decision.
I'm new to C and came across some code dealing with pointers and could use some help deciphering it. What does this mean? It appears to be casting variable p to be a pointer to an int. I'm confused by the (int *) code.
*(int *)p = 0x113
It casts p to a pointer-to-int, and then stores the (integer) value 0x113 at the referenced location.
When you run across something like this, the best way to approach it is to separate it an take it one step at a time. Start with what is immediately casting the variable at issue and go from there. Here is it
* (int *) p
Starting at the middle, you have a cast to a pointer of type int:
(int *)
The cast is operating on variable p. So you know you are casting p to int *. So the following just says cast variable p to type int *:
(int *)p
Then the last piece of the puzzle is the * which says dereference the whole 'shebang'. So in its final form, you are simply dereferencing p which has been cast to int *:
*(int *)p
It says "treat p as a pointer to type int, then store value of 0x113 in the 4 bytes pointed to by p" (assuming int is 4 bytes).
The effect is that if, for example, p is declared as a pointer to char, this command will be able to modify 4 bytes instead of just one (size of char).