Understanding pointers

I know this is an Arduino forum and not really a platform to learn C, but I know a lot of folks here are really good when it comes to programming and besides what I am asking will be used in Arduino projects.

I am trying to learn pointers but it doesn't behave as what I expected. I explained it in the comments of my code.

#include <stdio.h>

int main()
{
	int x = 1;
	int y = 2;
	int *p;
	
	p = &x;
	printf("%d", p); //p = address of x
	puts("");
	printf("%d", *p); //*p = value of x, where x = 1
	puts("");
	
	y = *p; //y = 1 because *p = x = 1
	printf("%d", y);
	puts("");
	
	*p = 0; //*p = 0;
	printf("%d", y); // y = I expected 0. But why 1? why not 0?
	puts("");
	printf("%d", x); //x = 0 since *p is 0
	
}
	*p = 0; //*p = 0;  // p is pointing at the location of x, so this changes the value of x.
	printf("%d", y); // y = 1. I expected 0. But why 1? why not 0? // you have not changed   
                                   the value of y. To do so you have to write either y = newValue ; or
                                   p = &y ;  *p = newValue;

If

y = *p;

then why

*p = 0;

does not make

y = 0?

get into the habit of reading this out loud in your head

*ptr

reads "the value pointed to by ptr"

this next bit of code is NOT a permanent attachment of the two variables, it is a simple assignment:

y = *p;  // make y equal to the value pointed to by p
*p = 0;  // make the value pointed to by p equal to zero
y = 0? // why would y be 0?only if you reversed the two lines above

So does '*p' actually holds a REAL value, or is it just pointing to a value which is assigned by 'p'?

cyberjupiter:
So does '*p' actually holds a REAL value, or is it just pointing to a value which is assigned by 'p'?

pointers do not hold 'real values' they hold a type and a location

int* p is a pointer it has two properties; it points to some memory location and is of a type (that i very important later on when you understand and start to use them).

dereferencing it (i.e. *p) will allow you to either assign a value to that location:

*p = 10;

or retrieve the value pointed to by p:

someVar = *p;

It seems to me that everytime I assign a variable for example

*p = 1;
y = *p;

'y' copies what the '*p' CURRENTLY points to, in this case '1'

If I reassign

*p = 3;

and prints 'y', I would get the previous value of '*p', which is '1'

If I reassign

*p = 3;
y = *p;

and prints 'y', I would get the last assigned value of '*p', which is '3'.

Forgive me if I seem to be making very idiotic statements, but it looks to me that 'y' will not be changed even if '*p' is changed, unless 'y' is reassigned to '*p'.

It's hard to digest '*p' into my brain.

cyberjupiter:
'y' will not be changed even if '*p' is changed, unless 'y' is reassigned to '*p'.[/b]

exactly.

y is changed if assigned a new value directly:

int y;
y=someNewValue;

or is changed by by dereferencing some pointer that points to y:

int y;
int* p = &y; // a new int pointer p which points to the location of y
*p = someNewValue;
Serial.println(y);  // prints someNewValue

adding...

a pointer ptr0:

int y;
int* ptr0 = &y; // a new int pointer ptr0 which points to the location of y

can be changed to point to another pointer's location:

int y = 10;
int x = 4;
int* ptr0 = &y; // a new int pointer ptr0 which points to the location of y
int* ptr1 = &x;   // a new int pointer ptr1 which points to the location of x
Serial.println(*ptr0); // prints "10"
Serial.println(*ptr1); // prints "4"
ptr0 = ptr1;  //change ptr0 to point to the location pointed to by ptr1
Serial.println(*ptr0); // prints "4"

In that case..

If I have code such as this(same as the the original post, with unnecessary stuff commented out)

void main()
{
   int x = 1;
   int y = 2;
   int *p;

   p = &x;

   y = *p;
}

I would like to deduce this statements;

1. Changing '*p' will only change the value it points to, but does not change 'y'
2. Reassigning 'x' to a new value changes both the value 'x' and the value pointed to by 'p', and still does not change 'y'
3. 'y' CAN only be changed by assigning "p = &y", or by normal assignment "y = newValue"

void main()
{
   int x = 1;  // create a new variable x and assign it the value 1
   int y = 2;  // create a new variable y and assign it the value 2
   int *p;  // create a new int pointer

   p = &x;  // make the int pointer p point to the location of x

   y = *p;  // assign y the value pointed to by p -> p points to x -> x = 1
                // y now and until it is changed again contains 1
}

cyberjupiter:
I would like to deduce this statements;

1. Changing '*p' will only change the value it points to, but does not change 'y'
2. Reassigning 'x' to a new value changes both the value 'x' and the value pointed to by 'p', and still does not change 'y'
3. 'y' CAN only be changed by assigning "p = &y", or by normal assignment "y = newValue"

  1. if p points to y, then y is changed
  2. yes
  3. not quite, y can be changed by normal assignment or by dereferencing a pointer pointing to the location of y... i.e.:
p = &y;  //move p to point to the location of y
*p = newValue;  // make the value pointed to by p (which we know is the same location as y) to newValue

BulldogLowell:

p = &y;  //move p to point to the location of y

*p = newValue;  // make the value pointed to by p (which we know is the same location as y) to newValue

That's what I wanted to say actually.

y = *p;  // assign y the value pointed to by p -> p points to x -> x = 1

This illustration really starting to give me the 'click' on my brain, but I believe it takes practice to understand it better.

Okay one last question,

p = &y;  //move p to point to the location of y
*p = newValue;  // make the value pointed to by p (which we know is the same location as y) to newValue

When we assign "*p = someValue", what it actually changes is not the value in '*p'(as you said *p does not hold any value), but the value to what it points to by p, or in the above code 'value in y'

cyberjupiter:
Okay one last question,

p = &y;  //move p to point to the location of y

*p = newValue;  // make the value pointed to by p (which we know is the same location as y) to newValue




When we assign "*p = someValue", what it actually changes is not the value in '*p'(as you said *p does not hold any value), but the value to what it points to by p, or in the above code 'value in y'

yes, you understand it now!

Pointers are really hard to understand, but as you say one it "clicks" then that is the first hurdle... but since they are used in many differing types of solutions they require 1) practice and 2) practice and 3) even more practice.

I think I see the source of the OP's problem of understanding this.
It is that the "*" operator has two meanings here depending on the context.

  1. When used in a declaration eg: int *p it is used to declare p as a pointer.
  2. when it is used a subsequent statement such as: printf("%d", *p); it is a dereferencing operator to retrieve the value pointed at by p

6v6gt:
I think I see the source of the OP's problem of understanding this.
It is that the "*" operator has two meanings here depending on the context.

  1. When used in a declaration eg: int *p it is used to declare p as a pointer.
  2. when it is used a subsequent statement such as: printf("%d", *p); it is a dereferencing operator to retrieve the value pointed at by p

perhaps, I'm not telepathic however.

you make a good point which is why this syntax:

int *p; // create a new int pointer p

really freaking sucks (IMHO) compared to this (syntactically equal) expression:

int* p; // create a new int pointer p

because (and only because) the first resembles the dereference operator:

*p = someValue;

I think this was done with evil intent to purposefully create a learning obstacle. :wink:

When I taught my son and his friends pointers I avoided the first syntax:

type name;

if initializing a type pointer:

type* name;

when dereferencing a pointer

*name = someValue;

it seems to click faster, because *p looks a heck of a lot like *p yet two completely different things going on...

Yes, yes and yes to both of you.

I thought 'p' and 'p' are separate things...when '' should have been appended to the 'type'.

Well you need to blame

K&R The C Programming Language, page 94

because I am using their book to learn pointers they uses type *p instead of type* p :grinning:

Anyway,
thank you so much Lowell and 6v6gt.

cyberjupiter:
because I am using their book to learn pointers they uses type *p instead of type* p :grinning:

yes...

if (K == EVIL or R == EVIL)
{
  makeThisWayMoreDifficultToUnderstandThanNeedBe()
}

I agree that the notation is inherently confusing.
For learning, I think also that it is useful to see it pictorially say by drawing boxes on a sheet of paper representing example storage locations each with their (simplified) address, putting some content in the boxes. That content is either a pointer (the address of another storage location), or a simple value, and drawing arrows from a pointer to the thing being pointed at.

Edit:
If you are using the original C book you'll find example which will no longer compile because of changes in the language eg declaration of function parameter types.

I thought 'p' and 'p' are separate things...when '' should have been appended to the 'type'.

No, the precedence rules dictate that the pointer binds to the variable, not the type.int* p, x;
Here only p is a pointer to int. x is simply an int variable.

cyberjupiter:

	p = &x;


y = *p; //y = 1 because *p = x = 1

*p = 0; //*p = 0;
printf("%d", y); // y = I expected 0. But why 1? why not 0?
puts("");
printf("%d", x); //x = 0 since *p is 0

}

Why would y be 0? You assigned 1 to it. You assigned 0 to *p, but p was pointing at x at the time, not y.