Pointer dereference in an assignment - c

I was watching a lecture and got confused at a point when professor said
that ptr=&x denotes a variable ptr assigned the address of the variable x.
And for y=*ptr+1 he said *ptr denotes the value stored at x (or the value of x).
I became slightly confused here as *ptr should be pointing towards the address of x right, not the value stored at x? Can someone please elaborate it a bit more?

Consider,
int a = 10;
Now, in memory we have something like
+------+
| |
| 10 |
| |
+------+
0x121 a
Now, consider a pointer variable of type int
int* ap = &a;
This looks like,
+-------+
| |
| 10 |
| |
0x121 +-------+
a
+-------+
| |
| 0x121 |
| |
+-------+
ap
a is a label to the memory location and ap is the address. To get the value at that address you use *. This is called dereferencing the pointer.
*ap
This gives you 10
Read some good tutorial on pointer.

It is ptr that points to x, not *ptr. *ptr is not even a pointer (assuming x isn't one).
The variable ptr contains a pointer to the variable x, i.e. the address of the variable x. The value of the expression ptr is a pointer to x. The value of the expression *ptr is the value at the location that ptr points to: that's what the dereference operator * means. Since ptr points to x, the value of *ptr is the value of x.

A pointer points to an address where a value is stored.
int *ptr;
int x = 2;
ptr = &x;
Here, ptr is an int pointer and x is an int (obviously). If we want ptr to "keep track" of the value of x then we assign ptr the address of x. So when we dereference ptr we get the value stored at the address that ptr points to. So if we want to change the value that ptr "stores" then we dereference it.
*ptr = 5;
This changes the value at the address ptr points to from 2 to 5.

Given:
int x = 42;
int *ptr = &x;
x is an integer object (of type int), and ptr is a pointer object (of type int* or pointer-to-int).
Unary & is the address operator. Applying it to an object of type FOO gives you the address of that object (or, equivalently, a pointer to that object); that address/pointer value is of type FOO*, or pointer-to-FOO. The operand of unary & must be the name of an object, not just a value; &42 is illegal nonsense. (The symbol & is also used for the binary bitwise and operator, which is completely unrelated to the address operator.)
Unary * is the dereference operator, the inverse of &. Its operand must be value of some pointer type. *ptr refers to the object to which ptr points.
Given the above declarations, and assuming the value of ptr hasn't been changed, the expressions x and *ptr mean the same thing; they both refer to the same int object (whose value happens to be 42). Similarly, the expressions &x and ptr mean the same thing; they both yield the address of x, an address that has been stored in the pointer object ptr.
It's important to note that *ptr doesn't just refer to the current value of x, it refers to the object x itself -- just like the name x does. If you use *ptr in a value context, this doesn't matter; you'll just get the value of x. But if you use it on the left side of an assignment, for example, it doesn't evaluate to 42. It evaluates to the object x itself, and lets you modify that object. (The distinction here is whether *ptr is used as an lvalue.)

The variable ptr stores the address of x. To retrieve the value stored at x, we dereference ptr with the unary * operator; hence, the expression *ptr evaluates to the value of x.
Put another way, if
p == &x;
then
*p == x;

Related

can anybody help me to solve this pointer question in c

can anybody help me understand this code (in c)..
#include <stdio.h>
void main()
{
const int a =5;int b;
int *p;
p= (int *) &a;
b=a;
*p= *p +1;
printf(" value of p is = %d\n", *p);
printf(" value of b is = %d\n", b);
printf(" value of a is = %d\n",a);
}
result is
: value of p is = 6
: value of b is = 5
: value of a is = 6
With the instruction p = (int *)&a; you made p to point at a.
As a result expression *p refers to the variable a, hence *p = *p + 1; worked as equivalent to a = a + 1; – variable a got assigned its previous value (which was 5) incremented by 1.
So it's finally 6.
This, however, is an Undefined Behavior, as #interjay points out in this comment – the a variable is declared as const, which means it must not be modified. As a result the compiler might choose to allocate it in a read-only area of memory. It did not in your case, and an assignment succeeded, but in other case the modfication of the variable might silently fail (with a value remaining 5) or yield a memory access exception (and terminate the program) or whatever.
The intent of this code is to update the value of a through the pointer p. Let's strip away some things and start with the basics:
int a = 5;
int *p = &a;
We have an object named a that stores the integer value 5. We have another object named p that stores the address of a. After the two declarations above, the following conditions are true:
p == &a == some address value
*p == a == 5
The expression *p is equivalent to the expression a - assigning a new value to *p is the same as assigning a new value to a, so
*p = *p + 1
is the same as writing
a = a + 1
However, in the code you posted a has been declared as a const int. That means you are telling the compiler that the value of a is not supposed to change over its lifetime. The compiler will flag any statement like
a = a + 1
or
a++;
as an error. The compiler may also store a in read-only memory; if you never take the address of a (that is, if it's never the operand of unary &), the compiler may not reserve any storage for it at all and just replace any instance of it with the value (IOW, anywhere you would expect to see a reference to a in the machine code you would just see a literal 5), meaning there's nothing to write to at all.
But this code cheats - it declares p as a pointer to a non-const int. The type of the expression &a is const int * (pointer to const int), but the type of p is just int * (pointer to int). In the assignment
p = (int *) &a;
you are casting away the const qualifier on a. So when you write a new value to *p, the compiler doesn't know that you're trying to modify something that was declared as const so it won't flag it as an error.
The C language definition says that trying to update a const-qualified object through a non-const-qualified lvalue1 results in undefined behavior - the compiler is not required to handle the situation in any particular way. The result can be any one of:
a runtime error;
the value of a remaining unchanged;
behaving exactly as expected;
or something else entirely.
An lvalue is any expression that designates an object such that the object my be read or modified. Both a and *p are lvalues that refer to an integer object containing the value 5
Before the explanation, let me tell you that this is part is a bit problematic, and can lead to undefined behavior:
const int a =5;
p= (int *) &a;
You should remove const, because in this case you want to modify the contents of a through pointers. Some compilers (such as clang, as someone mentioned in the comments) might perform optimizations, like replacing where the const variable is used with its value, to reduce the number of memory access operations.
Let's imagine that each variable is a little box where you can put numbers. So you have 3 boxes:
+---+ +---+ +---+
| 5 | | | | |
+---+ +---+ +---+
a b p
Now let's go over each statement and see what is happening.
int *p;
p= (int *) &a;
p is defined as a pointer, which is a type of variable that can hold the address of something in memory. In this case, it is assigned the address of variable a. So our boxes now look like this:
+---------------+
v |
+---+ +---+ +----+
| 5 | | | | &a |
+---+ +---+ +----+
a b p
p simply contains the memory address of a. You can print it with printf("%u", a), and you will see some number. That is the address of a.
b=a;
Here we are copying the value of a into b, so our boxes become:
+---------------+
v |
+---+ +---+ +----+
| 5 | | 5 | | &a |
+---+ +---+ +----+
a b p
*p= *p +1;
Using the *p syntax, we can dereference the pointer, that means that we can access the memory that p is pointing to (follow the arrow). In this case, *p will allow us to get or set the contents of the a variable. Our boxes now become like this:
+---------------+
v |
+---+ +---+ +----+
| 6 | | 5 | | &a |
+---+ +---+ +----+
a b p
printf(" value of p is = %d\n", *p);
Here you are again dereferencing p, meaning that we are getting the contents of the memory at address p. In our case, this will get the contents of the a variable which is 6.
printf(" value of b is = %d\n", b);
Looking at the b box, we can see that it contains 5.
printf(" value of a is = %d\n",a);
We modified a using the pointer. Looking at the a box, we can see that it contains the value 6.
We go line by line
const int a =5;int b;
In this line, variable b is defined as int and variable a is defined as const int, which means that its value is constant at all lower steps and is equal to 5.
int *p;
p= (int *) &a;
In these two lines, a variable called p is defined as a pointer int, whose value (must be an address from memory cells) is equal to the address of the variable a.
This means that both variables a and p point to a common memory cell.
In other words:
(*p == a) //IS TRUE. Both are equal to 5
and next line:
b = a;
That is, the value of the variable b is also equal to a, which is equal to 5
*p= *p +1;
In this line, a unit is added to the value corresponding to the address p.
We know that the variables a and p point to a common cell of memory.
In fact, this means that we indirectly added a unit to the variable a, which means that both variables have a value of (5 + 1).
And finally, the reason for the output of the last three lines is clear
The problem is entirely in the following line:
p= (int *) &a;
Without the type cast, the line would read:
p = &a;
The type of a is const int.
The type of p is int *.
It is obvious that the compiler should warn about discarding the const qualifier:
warning: assigning to 'int *' from 'const int *' discards qualifiers
[-Wincompatible-pointer-types-discards-qualifiers]
This demonstrates why you should always try to avoid explicit type casting (unless strictly necessary). The author of this code shot themselves in the foot. They introduced undefined behaviour and the obvious problem was hidden, because the warning was discarded or suppressed

Multidimensional array addressing C

In the following piece of code, I am getting the first two values of addresses same(call it x). I have run it on gcc compiler of ubuntu v18.04.4 LTS.
int a[2][2] = {0};
printf("%p %p %d\n", a, *a, **a);
This mean that:
a contains the address x.
a is pointing to the location x(as it is a pointer which is storing x).
this means *a is stored in location x and it also contains the value x(as in the output of above code).
now, on dereferncing *a i.e, **a, I am getting output as 0 which means that *a (whose value is x) is pointing to some location in which 0 is stored.
Now, from 1. , address of *a is x (as a points to *a and is storing x) and address of the number 0 is also x (as *a points to a[0][0] which is 0 and *a is storing x).
So my question is what exactly is stored at the location x?
Or have I mistaken something in making the conclusions?
Your assertion that a contains an address seems to indicate that you think a is a pointer. It is not a pointer but an array. They are related, but they are not the same thing.
An array, in most contexts, decays to a pointer to its first member. In this case, this means that in an expression a is the same as &a[0] and *a is the same as a[0] which is the same as &a[0][0]. This also means that the address of an array is the same as the address of its first member, which is what you're seeing when you print a and *a.
This would probably be better illustrated with a diagram:
----- ------- ---- ---
0x100 | 0 | a[0][0] a[0] a
----- -------
0x104 | 0 | a[0][1]
----- ------- ----
0x108 | 0 | a[1][0] a[1]
----- -------
0x10c | 0 | a[1][1]
----- ------- ---- ---
From here, you can see that a starts at address 0x100 (x in your example) and contains a total of 4 int values. Also note that the subarray a[0] has the same address as a, as does the initial int element a[0][0].
Generalizing this, the address of an array and the address of its first element, even though the types are different, are the same. So:
a is an array whose address is 0x100. It contains element of type int[2].
a[0] is an array whose address is 0x100. It contains element of type int.
a[0][0] is an int whose address is 0x100.
I have not understood what is the magic 'x'.;)
You declared a two-dimensional array
int a[2][2] = {0};
Array designators used in expressions (with rare exceptions as for example using them in the sizeof operator) are implicitly converted to pointers to their first elements.
So the expression a used in this call
printf("%p %p %d\n", a, *a, **a);
is converted to the pointer of the type int ( * )[2] to the first element of the array. That is it is the address of the memory extent occupied by the array.
Using the indirection operator * the expression *a yields the first element of the type int[2] of the original array a.
Again this array designator *a in the call of printf is implicitly converted to pointer of the type int * to its first element that has the type int. This pointer will contain the same address of the memory extent occupied by the original array.
In this expression **a there are applied two indirection operators. The first indirection operator yields the first element of the two-dimensional array that is it yields an array of the type int[2]. This array used as an operand of the second indirection operator at once is implicitly converted to pointer to its first element that has the type int *. The second indirection operator yields the object pointed to by the pointer that is the object of the original array a[0][0] that is outputted by the printf call shown above. As this element was explicitly initialized by 0 then 0 is outputted as the value of the element.
To make it more clear the first indirection operator *a is equivalent to using the subscript operator a[0]. And the second indirection operator applied to this expression *a[0] is equivalent to the expression a[0][0].

How double pointer really behaves this way?

Is not that true that double pointer store address of a pointer only?
How it can then store an integer address?
{
int **ptr,a;
a = 10;
ptr = &a;
printf("value of a = %d\n",*ptr); //why it works?
printf("value of a = %d\n",**ptr); //why it doesnt work?
}
As for your problem, because you make ptr point to &a, then doing *ptr will lead to the same result as doing *(&a) which gives you the value of where &a is pointing, which is the value of a. It's semantically incorrect though, and could lead to other problems if the size of int * (which is what *ptr really is) is different from the size of int (which is what a is).
When you do **ptr you treat the value of a as a pointer, and dereference it. Since 10 is unlikely to be a valid pointer on a modern PC you will get undefined behavior.
You say "double pointer store address of a pointer", and that's correct. A pointer to a pointer can store an address (pointer) of a pointer. But &a is not an address of a pointer, it's the address of the non-pointer variable a.
For a "double pointer" (pointer to pointer really) to work, you need something like
int a = 10;
int *ptr = &a; // Make ptr point to the variable a
int **ptrptr = &ptr; // Make ptrptr point to the variable ptr
After this, *ptrptr == ptr, and **ptrptr == *ptr and **ptrptr == a.
Somewhat graphically the above could be seen something like
+--------+ +-----+ +---+
| ptrptr | --> | ptr | --> | a |
+--------+ +-----+ +---+
Is not that true that double pointer store address of a pointer only?
No. A pointer of any type can store address of anything. But ideally programmer should make sure that address of valid type is stored in it.
By doing ptr = &a; you are storing address of an integer in a double pointer variable.
printf("value of a = %d\n",*ptr); //why it works?
*ptr will return value at address stored by ptr. Since address stored is of an integer variable, it returns the integer value. But note that, the returned value will have address type since ptr is a double pointer. However, in printf(), you are using %d to print the value. So pointer type value returned by *ptr will be typecasted to integer and get printed. So you get proper output.
printf("value of a = %d\n",**ptr); //why it doesnt work?
This is not working because it is equivalent to (*(*ptr)). So you are trying to read integer value stored at address 10. I think either it is not a valid address on your machine or your program doesn't have permission to read that address.
PS: You must be getting compiler warnings. They give some hints.

How to evaluate double pointers in c?

I am learning c, and I am quite confused about this double pointer question.
int x = 44;
int *p = &x;
int **t = &p;
bool a = (*t = &x);
I need to tell whether a will be true or false, and the correct answer is true. My thoughts were that t points to the address of p, and p points to the address of x. I know if you put **t, it should point to the address of x, but I thought if you just put *t it should point to the address of p. Can anyone explain?
int x = 44;
Declares integer variable x, which stores value of 44.
int *p = &x;
Declares integer pointer variable called p, p now stores the address of x.
int **t = &p;
Declares pointer to pointer of type int called t, t stores the address of p. (Pointers have addresses too)
bool a = (*t = &x);
In C;
'*' = Extracts the value from an address (Dereference)
'&' = Gives address of variable (Reference)
Since t is a pointer to the value stored in p. *t will be the value stored in p, which is the address of x. (We figured this out in the second line)
On the other hand since the & is used on variable x. This will extract the address of x.
Therefore *t == &x, which sets the boolean value a to true.
I know if you put **t, it should point to the address of x, but I thought if you just put *t it should point to the address of p.
Well, that is both right and wrong. The "point to the address of" should read "designate" and it is right.
First of all, you declared 3 variables
int x = 42;
int *p = &x;
int **t = &p;
Now this could be read as x is an int, *p is an int and **t is an int. Then we initialize x to value 42, then p to address of x, and t to address of p.
Given
int *p = &x;
the two L-value expressions x and *p not only are both of type int, and have the same value; they designate the same object. Just like 10565305 and Amy Finck designate the same user. This is also called aliasing - *p aliases x, just like Amy Fink and User 10565305 are your aliases on Stack Overflow (and the name x is not the object itself, just like you're a person, not a name).
Likewise with int **t = &p, we now notice that just like above, *t and p designate the same object, p. And ps current value is that of expression &x. Hence *t == &x must be true.
As for *ts type, if **t is an int, then *t must be int * (the law of conservation of stars in pointers ;) which of course matches the type of p, and type of &x.
It will be true. Here is the explanation:
In bool a = (*t = &x); the variable t holds address of p. You are de-referencing t i.e *t will point to the content stored in location of p.
The content stored in address of p is address of x. Remember *p = &x. Comparing *t == &x will then be true.
In the question you have mentioned *t = &x, if that is the original code it is still true, as assignment in (*t = &x); returns a non-null pointer. When that non-null pointer is converted to a boolean, it becomes true.
The first line declares a variable 'x' of type 'int', and assigns the numeric literal value 44 to that variable.
int x = 44;
The next line (2) declares a variable 'p' of type 'pointer to int', and assigns the value of the expression '&x' (which is the address of x, a pointer to int),
int *p = &x;
The next line (3) declares a variable 't' of type 'pointer to, pointer to int' (a pointer that contains a pointer to an int type), and assigns the expression '&p' (which is the address of p, a pointer to int,
int **t = &p;
The variable t is a 'doubly-indirected pointer'.
Now comes the 'tricky part'.
The next line (4) declares a variable 'a' which is a bool(ean) variable (true/false), and assigns the value of the expression on the rhs (right hand side, '(*t = &x)'. The parenthesis are there to ensure the intended order of precedence is observed. So we evaluate the expression '*t = &x'.
bool a = (*t = &x);
Here is the 'tricky' part, the code provided has an assignment '=' operator! If this were comparison, then the '==' operator would appear. So this statement takes the address of x (pointer to int), and stores it into *t (the location pointed at by t, and that location is a pointer to int).
Were this comparison, the expression would compare the same values, and would be true. But this is assignment. And an assignment expression returns the value assigned, which is the address of x (pointer to x). On most systems, that pointer is a location in memory (and could only be zero(NULL) if the variable were stored at the zero address).
The expression is of type 'pointer to int', but is converted (cast) to type bool. Since C considers false=0 and true anything not equal to 0, the value is converted from (likely not NULL) pointer to int to bool (true).
Had the parenthesis been omitted, then the assignment would still occur (right to left order of evaluation for assignment operator), but then the cast would occur. But remove the parenthesis, compile it and see what your compiler says.
You said:
I need to tell whether a will be true or false, and the correct answer is true. My thoughts were that t points to the address of p, and p points to the address of x. I know if you put **t, it should point to the address of x, but I thought if you just put *t it should point to the address of p. Can anyone explain?
Here is my attempt an an explanation:
The bold part is where you are confused. **t == x == *p, and *t == &x == p.
**t references the value stored in at x's address, not the address itself.
*t =p references the address of x, and dereferencing either of them give you the value of x.
Does this explanation clear things up? I can expand or make a sample program if it helps.
sample scratch code would be to printf these values to gain clarity:
int x = 42; //&x = 0x1234DEAD (or some other address, just picked one for an example)
int * p = &x; // p = 0x1234DEAD and &p = 0x5678BEEF (agian an example address)
int **t = &p; // t = 0x5678BEEF
printf("%d and %d and %d\n",**t, *p, x); //should be 42;
printf("%p and %p\n",*t, p); //should be 0x1234DEAD;
printf("%p\n",t); //should be 0x5678BEEF;
My thoughts were that t points to the address of p
Yes.
and p points to the address of x
Yes.
I know if you put **t, it should point to the address of x
No, **t is x.
but I thought if you just put *t it should point to the address of p.
No, *t is p.
The dereference operator "gives you" the pointed-to thing. Hence, since, p is also &x (because that's what you set it to), *t == &x.
It's moot though because you didn't actually compare with ==, you assigned with =, so your expression evaluates to the result of that assignment, which is &x, which is a non-NULL pointer, so the whole thing is "true-like". (Only a null pointer converts to false).

When to use * in pointer assignment? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
As I'm learning C I often see pointers.
I get that a pointer is holding the hexadecimal value of a distinct location in memory. So a pointer is nothing other than e.g.:0x7fff5fbff85c
Every pointer is also of a distinct type.
int var = 10;
int *ptr = &var;
Ptr here points to the location of var. To get the value of var I have to dereference the pointer with *ptr.
Like
printf("Var = %d", *ptr);
would print `Var = 10;
However If I do a non inline declaration of a pointer like:
int var = 10;
int *ptr;
ptr = &var;
I don't have to use the * in the third line when I'm actually assigning the memory adress to the pointer.
But when I got a function that takes a pointer:
int var = 10;
void assignPointer(int *ptr) {
*ptr = 10;
}
Oh, wait! As I'm writing this I recognized that there are two different assignments for pointers:
*ptr = 10;
and
ptr = &var;
What is the difference? Am I in the first case first dereferencing the pointer, assigning 10 to the location that its holding?
And in the second case I'am assigning the actual location to the pointer.
I'm a little bit confused when to use the * and when not to in terms of assignment.
And if I'm working with arrays, why do I need pointers at all?
int array[];
"array" here is already holding the hexadecimal memory location. Doesn't that make it a pointer? So If I wanted to assign something to array wouldn't I write:
*array = [10, 2];
First I'm dereferencing, then I'm assigning.
I'm lost :(
EDIT: Maybe it's a bit unclear.
I don't know when you have to use a * when you are working with pointers an when not.
Everything that is carrying a hexadecimal is a pointer right?
The variable name of an array is carrying it's hexadecimal memory location. So why isn't it a pointer?
EDIT2: Thank you people you helped me a lot!
I don't know when you have to use a * when you are working with pointers an when not. Everything that is carrying a hexadecimal is a pointer right? The variable name of an array is carrying it's hexadecimal memory location. So why isn't it a pointer?
Last thing first - the name of an array is not a pointer; it does not store an address anywhere. When you define an array, it will be laid out more or less like the following:
+---+
arr: | | arr[0] Increasing address
+---+ |
| | arr[1] |
+---+ |
... |
+---+ |
| | arr[n-1] V
+---+
There is no storage set aside for an object arr separate from the array elements arr[0] through arr[n-1]. C does not store any metadata such as length or starting address as part of the array object.
Instead, there is a rule that says if an array expression appears in your code and that expression is not the operand of the sizeof or unary & operators, it will be converted ("decay") to a pointer expression, and the value of the pointer expression will be the address of the first element of the array.
So given the declaration
T arr[N]; // for any type T
then the following are true:
Expression Type Decays to Value
---------- ---- --------- -----
arr T [N] T * Address of first element
&arr T (*)[N] n/a Address of array (same value
as above
*arr T n/a Value of arr[0]
arr[i] T n/a Value of i'th element
&arr[i] T * n/a Address of i'th element
sizeof arr size_t Number of storage units (bytes)
taken up by arr
The expressions arr, &arr, and &arr[0] all yield the same value (the address of the first element of the array is the same as the address of the array), but their types aren't all the same; arr and &arr[0] have type T *, while &arr has type T (*)[N] (pointer to N-element array of T).
Everything that is carrying a hexadecimal is a pointer right?
Hexadecimal is just a particular representation of binary data; it's not a type in and of itself. And not everything that can be written or displayed in hex is a pointer. I can assign the value 0xDEADBEEF to any 32-bit integer type; that doesn't make it a pointer.
The exact representation of a pointer can vary between architectures; it can even vary between different pointer types on the same architecture. For a flat memory model (like any modern desktop architecture) it will be a simple integral value. For a segmented architecture (like the old 8086/DOS days) it could be a pair of values for page # and offset.
A pointer value may not be as wide as the type used to store it. For example, the old Motorola 68000 only had 24 address lines, so any pointer value would only be 24 bits wide. However, to make life easier, most compilers used 32-bit types to represent pointers, leaving the upper 8 bits unused (powers of 2 are convenient).
I don't know when you have to use a * when you are working with pointers an when not.
Pretty simple - when you want to refer to the pointed-to entity, use the *; when you want to refer to the pointer itself, leave it off.
Another way to look at it - the expression *ptr is equivalent to the expression var, so any time you want to refer to the contents of var you would use *ptr.
A more concrete example might help. Assume the following:
void bar( T *p )
{
*p = new_value(); // write new value to *p
}
void foo( void )
{
T var;
bar( &var ); // write a new value to var
}
In the example above, the following are true:
p == &var
*p == var
If I write something to *p, I'm actually updating var. If I write something to p, I'm setting it to point to something other than var.
This code above is actually the primary reason why pointers exist in the first place. In C, all function arguments are passed by value; that is, the formal parameter in the function definition is a separate object from the actual parameter in the function call. Any updates to the formal parameter are not reflected in the actual parameter. If we change the code as follows:
void bar( T p )
{
p = new_value(); // write new value to p
}
void foo( void )
{
T var;
bar( var ); // var is not updated
}
The value of p is changed, but since p is a different object in memory from var, the value in var remains unchanged. The only way for a function to update the actual parameter is through a pointer.
So, if you want to update the thing p points to, write to *p. If you want to set p to point to a different object, write to p:
int x = 0, y = 1;
int *p = &x; // p initially points to x
printf( "&x = %p, x = %d, p = %p, *p = %d\n", (void *) &x, x, (void *) p, *p );
*p = 3;
printf( "&x = %p, x = %d, p = %p, *p = %d\n", (void *) &x, x, (void *) p, *p );
p = y; // set p to point to y
printf( "&y = %p, y = %d, p = %p, *p = %d\n", (void *) &y, y, (void *) p, *p );
At this point you're probably asking, "why do I use the asterisk in int *p = &x and not in p = y?" In the first case, we're declaring p as a pointer and initializing it in the same operation, and the * is required by the declaration syntax. In that case, we're writing to p, not *p. It would be equivalent to writing
int *p;
p = &x;
Also note that in a declaration the * is bound to the variable name, not the type specifier; it's parsed as int (*p);.
C declarations are based on the types of expressions, not objects. If p is a pointer to an int, and we want to refer to the pointed-to value, we use the * operator to dereference it, like so:
x = *p;
The type of the expression *p is int, so the declaration is written as
int *p;
C syntax is weird like this. When you declare a variable, the * is only there to indicate the pointer type. It does not actually dereference anything. Thus,
int *foo = &bar;
is as if you wrote
int *foo;
foo = &bar;
Pointers are declared similar to regular variables.The asterisk character precede the name of the pointer during declaration to distinguish it as a pointer.At declaration you are not de-referencing,e.g.:
int a = 0;
int *p = &a // here the pointer of type int is declared and assigned the address of the variable a
After the declaration statement,to assign the pointer an address or value,you use it's name without the asterisk character,e.g:
int a;
int *p;
p = &a;
To assign the target of the pointer a value,you dereference it by preceding the pointer name with *:
int a = 0;
int *p;
p = &a;
*p = 1;
Dereferenced pointer is the memory it points to. Just don't confuse declaring the pointer and using it.
It may be a bit easier to understand if you write * in declaration near the type:
int* p;
In
int some_int = 10;
int* p = &some_int; // the same as int *p; p = &some_int;
*p = 20; // actually does some_int = 20;
You are pretty much correct.
Am I in the first case first dereferencing the pointer, assigning 10 to the location that its holding? And in the second case I'am assigning the actual location to the pointer.
Exactly. These are two logically different actions as you see.
"array" here is already holding the hexadecimal memory location. Doesn't that make it a pointer?
And you got the grasp of it as well here. For the sake of your understanding I would say that arrays are pointers. However in reality it is not that simple -- arrays only decay into pointers in most circumstances. If you are really into that matter, you can find a couple of great posts here.
But, since it is only a pointer, you can't "assign to array". How to handle an array in pointer context is usually explained in a pretty good way in any C book under the "Strings" section.
You are right about the difference between assignment and dereferencing.
What you need to understand is that your array variable is a pointer to the first element of your continuous memory zone
So you can access the first element by dereferencing the pointer :
*array = 10;
You can access the nth element by dereferencing a pointer to the nth element :
*(array + (n * sizeof(my_array_type)) ) = 10;
Where the address is the pointer to the first element plus the offset to the nth element (computed using the size of an element in this array times n).
You can also use the equivalent syntax the access the nth element :
array[n] = 10;
One of your examples isn't valid. *ptr = 10;. The reason is that 10 is a value but there is no memory assigned to it.
You can think of your examples as "assigning something to point at the address" or "the address of something is". So,
int *ptr is a pointer to the address of something. So ptr = &val; means ptr equals the address of val. Then you can say *ptr = 10; or val = 10; cause both *ptr and val are looking at the same memory location and, therefore, the same value. (Note I didn't say "pointing").

Resources