C Pointer Processing (basics) - c

I'm still struggling to get comfortable with pointers. Not the concept - I understand memory locations, pointer increments matching variable length, etc - it's the syntax. Here's an example that I think is one reason I get confused/can't get an intuitive grip on it:
int a = 42;
Allocates and puts 42 in an int-sized memory space
int *pa = &a;
Allocates a pointer in memory that points to the address containing the variable "a".
printf("%d \n", *pa);
Prints 42.
Simple/basic. What bothers me is that:
int *pa = &a;
Would seem to indicate that *pa and &a are equal; equal to the memory address of a. But in:
printf("%d \n", *pa);
*pa is the contents of the address pa points to. So *pa appears to be two different things (address or int) depending on context. And makes me concerned that "=" != "=".
Now I'm not trying to complain about/redefine/question the language, I'm just wondering if anyone has any tips that will help me understand this better, make it make more intuitive sense. I assume it makes perfect logical sense if you really know the language; I'm hoping someone can explain it so it seems logical to me, too.

int * is not the same as the * in printf("%d \n", *pa);.
Specifically, int *, the entire thing, is basically a type: A "pointer to an int" type.
In other words, int * is a type.
However, invoking *pa means to dereference the pointer pa. So, * is an operator: the deference operator.
Also, to be pedantic, = is actually the assignment operator.
Three general cases for *:
Pointer type. * will follow a type. Example: int * is the pointer-to-an-int type.
Dereference operator. This is a unary operator, and dereferences a pointer to get the "underlying value" in the memory address.
Multiplication operator. This is a binary operator.

Your confusion seems to be because you initialize and declare the pa pointer at the same time, see this
int a = 42;
int *pa;
pa = &a;
now *pa and &a do not seem to be equal.

In C, there are 3 main uses of the * symbol. It takes place as part of a type, a unary operator, and an arithmetic operator.
The first case, as part of a type is used to initialize a pointer. int* foo means that foo is a pointer to an integer, that means foo holds the address of a pointer.
Ex int* pa = &a, pa == address of a.
The second case, as a unary operator is called the dereferencing operator. Unary is when the * has only a value on it's right. Like this it will act as a dereferencing operator. Dereferencing is expressing the value at a given address.
Ex following from the previous example
pa = &a
if (*pa == 1) Look at what value is at the address p is holding
The third case is trivial, but worth mentioning in how it differs from how it acts as a unary operator. As an arithmetic operator, it needs a value to the left and the right.
Exint x = 5 * 5
TL;DR In int *pa, the * is part of the type, not the variable. It might be more clear to see it as int* pa. When it is not a part of a type, the * is a dereferencing operator, meaning to look at the value present at that address.

It might make more intuitive sense if you used a syntax that explicitly shows pa as a variable with a different type than a. This can be accomplished with simple spacing:
int a = 42;
int* pa = &a;
printf("%d", *pa);
Note that all I've done here is shifted the spacing in the declaration of pa so that the * is attached to its type rather than the variable itself.
Mind you, I do think that the syntax can be construed as confusing - it wouldn't be the first confusing thing about C. Personally I might have preferred the use of something like ! for dereferencing:
int a = 42;
int* pa = &a;
printf ("%d", !pa); /* this is fantasy C */
Of course, then you'd have to come up with something else for logical not...

Related

Address-of operator in C

In C programming, does the address-of operator & result in object's first address?
For example:
int a[2] = {10, 20};
int* arrays_first_address = &a;
As &a means "array's first address" then can I generalize it so the address-of operator results in object's first address?
There's a subtle difference between a and &a.
a is an array which in most expressions decays into a pointer to its first element, int* in this case. Meaning that writing a and &a[0] is 100% equivalent in most contexts.
&a is one of the exceptions where array decay does not happen, so you get a pointer to an array, type int(*)[2]. This can be regarded as "a pointer to the whole array" rather than just the first item. It is not compatible with int*, which is the reason why your code isn't valid C. (No it doesn't compile fine, it's a constraint violation, please see What must a C compiler do when it finds an error?)
However, the whole array and the first item in that array are naturally located at the very same address. So no matter pointer type you will get the same address.
I suggest to run this program :
int a[2] = {10, 20};
printf("a=%p\n", a);
printf("&a=%p\n", &a);
printf("&(a[0])=%p\n", &(a[0]) );
And you should have answer.
In C, an array is also see as a pointer, but there is no memory really alloc with this value. So it's a convention to says that "a" and "&a" have the same value.

Can I dereference the address of an integer pointer?

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.

Why the compiler is not showing error on expressions that use arrays like pointers?

I'm new in C programming and currently learning about array and strings. I'm quite confuse in this topic. Coming to my question-
Since an array (for ex- a[]={20,44,4,8}), the name in an expression decays into pointer constant,so whenever if i try to do pointer arithmetic for example- a=a+1 or anything like this the compiler shows error but when the same thing I write in printf() function it is showing the address of the first element rather than showing error. Why?
In an expression for example *(a+1)=2 first (a+1) will be evaluated and then * will dereference it. My question is that if a is a pointer constant then how it can point to any other memory location in an array and how this expression is perfectly legal?
I tried to search about this but couldn't get the accurate result.
Although an array name evaluates to a pointer in some expressions, your a = a+1 assignment tries to assign to an array, which is not allowed.
On the other hand, a+1 expression is allowed, and it evaluates to another pointer. When you pass this value to printf, the function happily prints it. Do not forget to cast the result to void* when you print:
printf("%p\n", (void*)(a+1));
if a is a pointer constant then how it can point to any other memory location in an array and how is *(a+1) expression perfectly legal?
For the same reason that 2+3, a combination of two constants, produces a value that is neither a 2 nor a 3. In your example, a+1 expression does not modify a. Instead, the expression uses it as a "starting point", computes a different value (which happens to be of type pointer), and leaves a unchanged.
The name of the array a is not quite the same as a pointer constant. It merely
acts like a pointer constant in some circumstances. In other circumstances it will
act quite differently; for example, sizeof(a) may have a much larger value
than sizeof(b) where b is truly a pointer.
This code is legal:
int a[] = {20,44,4,8};
int *b;
b = a;
b = b + 1;
because a is enough like a pointer that you can set b to point to the same
address but, unlike a, b really is a pointer and it can be modified.
The last line of code could just as well be:
b = a + 1;
because the right-hand side here is not trying to modify a; it is merely using
the address of the first element of a to compute a new address.
The expression *(a + 1) is effectively another way of writing a[1].
You know what will happen when you write a[1] = 2, right?
It will change what is stored in the second element of a.
(The first element is always a[0] whether you do anything with it or not.)
Storing a new value in a[1] doesn't change the location of the array a.
When array decays in to pointer, the resulting value is a rvalue. It's an value that cannot be assigned to.
So int[4] will become int*const, constant pointer to integer.
Q1:
Types in expression a = a + 1 are:
int[4] = int[4] + int
If we focus on addition first, array decays to pointer:
int[4] = int*const + int
int[4] = int*const // After addition
But now there is a problem:
int*const = int*const
In memory a is an array with 4 ints, and nothing more. There is no place where you could possibly store address with type int*. Compiler will show an error.
Q2:
Types in expression *(a+1)=2 are:
*(int[4] + int) = int
Again, array decays to pointer and addition happens:
*(int*const + int) = int
*(int*const) = int // int* is now equal to &a[1]
Dereferencing int*const is legal. While pointer is constant, value it points to is not:
int = int // Ok, equal types
Types are now perfectly compatible.

Getting value using indirection operator

If value are stored in an address, then what does this declaration do
int a = 10;
It store the value in a or in address of &a. And if it store the value in address of a, then why we can't using indirection to this variable like this:
printf("%d", *a);
If not, then how we can say that the each value has an unique address and we can access them using indirection operator.
Edit: If I think that indirection is used only on pointer, then consider this:
int b[10];
b[0] = 4; // Give it some value
Now we know that b[0] is a scalar quantity and can be used anywhere where scalar value are required. But in this case, we can use indirection to it like this:
printf("%d", *b); // print 4
Isn't interesting to see that we can use pointer on this scalar variable, but cannot use on variable declare without array.
In my opinion, compiler automatically generates an indirection for variable declare like this:
int a = 4;
So, indirection is not possible on this because we are putting another indirection on it which is not legal except in cases when variables are declares like that:
int a = 4;
int *b = &a;
int **c = &b;
Edit 2: You can take scanf("%d", &a) as a proof which says store the value in address of a not in a.
Up to a certain point you are right: a stores an int and lives at the address &a.
But indirection can only be used on pointers. So you could do either of
int a = 10;
int *p = &a;
printf("%d", a);
printf("%d", *(&a));
printf("%d", *p);
When the variable is of type int (rather than int *), the compiler knows that it needs to do the indirection for you, and you shouldn't try to make it do it. That is, when you have int a = 10;, the compiler stores the value at a memory location which is represented by &a (ignoring registers) and it knows that when you write printf("%d\n", a); it is required to fetch the value stored at &a automatically without you having to think about telling it to dereference something.
When the variable is of type int * (e.g. int *p), there are two ways you can read the value:
Fetch the value (an address) that is held in p
Fetch the value held at the address stored in p
These are two different operations, so two notations are needed:
int a = 10;
int *p = &a;
int *q = p;
int r = *p;
Of course, p also has its own address.
It's not really clear what the question is here, so I'll just explain the situation...
Each (global) variable is located somewhere in memory. When it is assigned a value, that value will in memory at the location of the variable.
If you, in C, use the variable, you actually use the value stored at the location of the variable.
One way to see this is that if & takes the address of an object, and * dereferences (follows) a pointer, then * &a is the same as simply a.
When you do
int a = 10;
The compiler allocates memory of enough size to accomodate an int. This location has to be identified(this is at this particular place i.e. the address) and labelled(this location is called a).It then stores the data at that point. The label allows you easier access. If the language was designed in a way that you would only have access to locations via pointers (i.e dereferencing them to get values) it will be difficult.
You can say its like, You live on some piece of land which can be pinpointed by an exact latitude and longitude. But its better to keep a name for that location, MyHouse etc. rather than referring to the latitude/longitude everytime. Both name and longi/lati refer to the same thing.
a is the label. &a is more like longi/lati
Edit: Regarding int b[10]. array names are not plain labels. They also act as pointers and hence you can use * to dereference them
First of all, you cannot use the indirection operator on anything that does not have a pointer type.
Remember that declarations in C are based on the types of expressions, not objects; the declaration
int a = 10;
says that the expression a has type int, and will evaluate to the value of 10 (at least until someone assigns a different value to it). So when you write
printf("%d\n", a);
the compiler knows to retrieve the value stored at the memory location bound to the expression a. Think of this as a direct access.
Now consider the declaration
int *p = &a;
This declaration says that the expression *p has type int, and will evaluate to the value of whatever p is currently pointing to (in this case, *p will evaluate to 10 since p is initialized with the address of a); the indirection operator is part of the declaration (and is bound to the declarator *p, not the type specifier int). The variable p is a pointer to an integer, and it stores the address of another integer variable (in this case, the address of the variable a). Thus, if we want to access the integer value, we must dereference p:
printf("%d\n", *p);
This is an indirect access to the value 10; instead of accessing it through the variable a, we're accessing it through p which points to a.

Strange (for me) behavior of pointers

I'm reading about pointers, but i'm confused about their nature. Here is what I mean.
int x = 4;
//Here I declare p as integer pointer
int *p;
// Here I assign memory address of x to pointer p
p = &x;
// The line below prints result 4 which is expected. If I miss asterisk before p I'll get memory address instead of data which that memory address holds.
printf("%d", *p)
Summarizing when asterisk is mising before pointer it "points" to memory address. If asterisk preceded pointer it "points" to actual data.
So far so good.
But why that segment of code works correctly ?
int someIntVariable = 10;
const int *p = &someIntVariable;
printf("%d", *p);
If I miss asterisk the compiler gives me an warning " warning: initialization makes integer from pointer without a cast"
I expected p (if the compiler allows me to use p without asterisk) to hold memory address of someIntVariable instead of it's "value";
What is happening here ?
In the declaration:
const int *p = &someIntVariable;
The asterisk is not the dereference operator. It simply states p is a pointer. That line has the same effect as
const int *p;
p = &someIntVariable;
Here you are declaring a pointer and assigning a value to the pointer in one step.
It is equivalent to the following code:
const int *p;
p = &someIntVariable;
Here the * is not used as a de-referencing operator. It is used in the context of pointer declaration.
The const int * is a datatype - i.e. pointer to a const int. p is the name of the variable. It is on the LHS.
When asterik is on the RHS it has a different meaning. It means dereference.
I belive you got the warning:initialization makes integer from pointer without a cast,
when you tried these way
int someIntVariable = 10;
const int p = &someIntVariable;
printf("%d", p);
What your trying to do is , Your assigning a address to a normal variable and your expecting it to work but that is not how the normal variables used thats why pointers came into act to do that job and your trying to replace a pointer with normal variable
I still did not find the real answer to it but Just check out these question that I asked I wonder what really the &a returns?

Resources