Explain the following syntax, i am not able to comprehend this - c

int a=4;
int *p=&a;
This syntax is right but when we write like this
int a;
int *p;
*p=&a;
The third line is an error and i know that but, why is it possible to do so in first code
int *p=&a;
We even do this when we pass the value by reference to functions ...
Thanks for the reply

with int *p=&a;, you are
declaring a variable (p) which is a pointer to an int
assigning the address of a to p
An equivalent code would be
int *p; // declare a pointer variable 'p'
p = &a; // assign the address of a to 'p'
The third line *p=&a; is an error because *p denotes the (integer) value of the pointer whose address is p, the value is an int and not a address of an int (i.e., not a pointer to an int)

The type is int *. So if the general pattern is:
T a;
T b;
a = b;
then with T = int *, the pattern is:
int * p;
p = &n; // n is an int
The "*" in the type specifier int * should not be confused with the almost entirely unrelated unary operator that is also called "*".

when you type
int *p;
you are declaring the pointer p.
using the * again after it has been declared would de-reference the pointer.
so
*p = &a;
would be saying "The value within pointer p = the reference to the value a"
the correct solution is
int *p;
p = &a

Related

Why can we only initialize a pointer with an array?

I have this code:
#include <stdio.h>
int main(void) {
int b[] = {1,2,3};
int *a = b; //works
int c = 1;
int *d = c; //doesn't work
}
Why is it that it works to initialize the pointer with an array but not an int?
int *d = c; it does work. It is simply converting the integer number held in c into a pointer. The compiler will issue the warning (unless you cast explicitly).
You can use it, for example, to read from a particular address of memory.
unsigned read_from_memory_address(unsigned address)
{
unsigned *x = (unsigned *)address;
return *x;
}
Of course, how this function will behave (or what type address should have) is implementation defined.
Pointers keep references to objects. If you want pointer to reference an integer variable you need to supply the reference (address) of this variable.
int *x = &c;
Arrays in expressions decay to pointer to first element of the array. That is why you do not need to use & in front of the array (you can, but the pointer will have a different type - in this case pointer to array).
int array[3];
int *x = array; //decays to pointer to first element
int (*y)[3] = &array; //pointer to array of 3 `int` elements

How to interpret assignment to pointer in C

In C, the statement int *var_name; by convention means that *var_name is of type int, which implies that var_name is an integer pointer.
But now consider this sequence of statements.
int a = 5;
int *var_name = &a;
But here how are we assigning address of a to *var_name which is of type int?
You are not assigning the address to *var_name, but to var_name. And this variable is of type "pointer to int", as you found.
Oh, and it is an initialization, not an assignment.
That's just the way the syntax in C works.
int *p = &a;
is completely equivalent to:
int *p;
p = &a;
It's not so difficult to understand why it would not make sense if it worked the way you thought. Consider this code:
int *p;
p = &a;
*p = 42;
Now imagine flipping the last two statements, like this:
int *p;
*p = 42; // To which address do we write 42? p is not initialized.
p = &a;
So although the meaning of int *p = &a;, which is int *p; p = &a; might be unintuitive, it's actually the only sane way to define it.
In this declaration:
int *var_name = &a;
there is declared the variable var_name of the pointer type int * and this variable (pointer) is initialized by the address of the variable a.
It seems you mixing the symbol * in declarations and in expressions.
In declarations it denotes a pointer. In expressions it denotes the dereference operator.
Consider the following demonstration program:
#include <stdio.h>
int main( void )
{
int a = 5;
int *var_name = &a;
printf( "The address stored in var_name is %p\n", ( void * )var_name );
printf( "The address of the variable a is %p\n", ( void * )&a );
printf( "The value of the object pointed to by var_name is %d\n", *var_name );
printf( "The value stored in the variable a is %d\n", a );
}
Its output might look like
The address stored in var_name is 00EFFAC0
The address of the variable a is 00EFFAC0
The value of the object pointed to by var_name is 5
The value stored in the variable a is 5
That is in this line:
int *var_name = &a;
*var_name means a declarator of a pointer type.
In this call:
printf( "The value of the object pointed to by var_name is %d\n", *var_name );
*var_name means an expression with the dereference operator *.

Proper way to read 'int * ptr=&x'

The following code is easily interpreted as
int x=4;
int *ptr; // ptr is a pointer to an int
ptr=&x; // the address of x is assigned to the pointer ptr
But the following equivalent code, may read misleadingly like
int *ptr=&x; // the address of x is assigned to *ptr, which is an integer
that is it seems to be interpreted as assigning the address of x to the pointed value *ptr (int *ptr )= &x
The correct interpretation as the one when declaration and initialization are separated should be written something like int *(ptr = &x),to make evident that the assignment is to the pointer and not to the pointed location but this gives an error, why is that? And what is the best way to read and think of int *ptr=&x?
This is, admittedly a weird part of C and it's mostly due to C's evolution.
In C's syntax, declarations aim to mirror use, so that after int *x;, *x resolves to an int and *x=42 assigns to that int. But initializations, which are started with = after the specifiers declarator part of a declaration, are syntactically and semantically different from an assignments.
(Initialization can "assign" to static/filescope variables and such an assignment generates no code: it simply contributes to the makeup of the resulting binary. Assignments always generate code unless optimizations can delete it)
Initializations and assignments used to be very differently looking in prehistoric C, where you'd initialize without the = sign as in int x 42;. (Even after the = was added to the syntax of initializations, it was long impossible to initialize local, nonstatic, variables which meant situations such as int *p = &x; didn't arise all that often.)
The old syntax had problems (would int x (42); also declare and initialize x or would it be a function declaration?) and that's why it was replaced, but I like how it emphasized that initializations are different from assignments.
Unfortunately with the new syntax (as in int x, *p = &x;) this distinction is not all that apparent, and you simply have to remember that when you have type specifiers (int) at the left end, then the = does not denote an assignment where you can just look at *p = &x but rather that it's an initialization where you have to look at the whole declaration and see what's declared (x as an int and p as a pointer to int) . The = in that context then initializes the declared identifier.
int * is the type, so it makes perfect sense. It's just that pointer notation in C can take some effort to get used to. But look at this code
typedef int* int_ptr;
int x;
int_ptr ptr = &x;
Same thing. However, it's often advised to NOT typedef pointers.
The confusion comes from that * serves two roles. It is BOTH to name a type AND to dereference a pointer. An example of the first is sizeof(int*)
If you declare several pointers at once it looks messier, but it's still the same. In general, it's recommended to not declare more than one pointer at once. Because if we would like to do the above thing with two pointers, it would look like this:
int *pa = &x, *pb = &x;
That's the same as
int *pa = &x;
int *pb = &x;
And this does something completely different and will generate a warning because you're assigning the address of a variable to the pb variable that has type int
int *pa = &x, pb = &x;
However, using the typedef from above, you can (but probably shouldn't) do this:
int_ptr pa=&x, pb = &x;
But one way to think of it is that it makes no sense at all in any situation to dereference an uninitialized pointer.
And what is the best way to read and think of int *ptr=&x?
Take the fact that it does not make sense to dereference an uninitialized pointer. And you're doing an initialization of a pointer, and therefore you should initialize it with a (valid) address.
Ok, I see that, another thing. If the type is int* why is it almost always written like with the * next to the pointer variable instead, like int *ptr?, it would make more sense, even if it is the same to write it like int* ptr.
Because, then it would be MUCH easier to forget the asterisk if you declare several pointers at once. That would give the impression that int* p,q; declares two pointers.
C pointer syntax is clunky. It's a very old language. Just get used to it. It will never change. Just for fun, here is a page that can tell what a declaration is https://cdecl.org/ so try these:
int (*p)[3]
int *p[3]
const int *p[3]
int *const p[3]
const int (*p)[3]
int (*const p)[3]
You could write
int ( *ptr ) = &x;
or even like
int ( * ( ptr ) ) = &x;
Though this record
int *ptr = &x;
is clear for each C programmer because it is a declaration and not an assignment statement. Moreover in C opposite to C++ declarations are not statements.
That is 1) you may not enclose a declaration in parentheses as you wrote (int *ptr )= &x and 2) you may enclose a declarator in parentheses.
If to follow your logic then you should write the declaration like
int *p = ( p = &x );
that makes the declaration more confusing.:)
Here is a demonstrative program that shows some examples of declarations and initializations of a pointer.
#include <stdio.h>
int main(void)
{
int x = 10;
int *p1 = &x;
int ( *p2 ) = &x;
int ( *( p3 ) ) = &x;
int typedef *T;
T ( p4 ) = &x;
printf( "*p1 = %d\n", *p1 );
printf( "*p2 = %d\n", *p2 );
printf( "*p3 = %d\n", *p3 );
printf( "*p4 = %d\n", *p4 );
return 0;
}
The program output is
*p1 = 10
*p2 = 10
*p3 = 10
*p4 = 10
Pay attention to that in C as in many other languages some symbols are overloaded and their meanings depend on the context. For example the symbol & can denote the address of operator and the bitwise AND operator and by the way in C++ this symbol also can denote a reference.
Compare the following.
int n = 5; // (a) defines 'int' variable 'n' and initializes it to '5'
int *p; // (b) defines 'int*' pointer variable 'p`
p = &n; // initializes 'p' to '&n'
int *p1 = p; // (c) defines 'int*' pointer variable 'p1' and initializes it to 'p'
// syntactically, it looks just like (a), but for a pointer type
int *p2 = &n; // (d) same as (b) and (c) combined into a one-liner
int n3 = 7, *p3 = &n3; // (e) same as (a), (b) and (c) combined into a one-liner
when declare a pointer, int p is equal to int p; int* is a type.

About Pointers and arrays and types and casting

Say I have the following problem:
main(void) {
int * p;
int nums [3] = {1,5,9};
char c [3] = {'s','t','u'};
p = nums [2];
*p = (int) *c;
}
What does the last line mean?
Let's break it down: *p = (int) *c;
c is a char array.
*c is the first element of the char array, because c[0] = *(c+0) = *(c) = *c
(int) *c casts the first element of the char array c to an integer. This is required, because with...
*p = (int) *c you assign the to an integer casted char to the content of pointer p.
This code will not work, or will cause problems if it does.
the line;
p = nums[2];
sets the value of the pointer p to the value 9. This is not likely a legal value for your pointer. If it were, then the memory location 9 would be set to 115 which is the integer value of 's'.
*c → Decay c to pointer-to-first-element, and access the pointed-to value. Same as c[0].
(int) *c → cast that value to int.
*p = (int) *c → assign that to what p points to.
There are many issues in this code, let's address them first.
Firstly, main(void) is not conforming code. You need to change that to int main(void).
Secondly, p = nums [2]; is wrong. p is of type int *, and nums[2] is of type int. You may not assign an int to a int * and expect something fruitful to happen. Maybe what you meant to write is p = &nums[2];. Without this modification, going further will invoke undefined behavior as you will try to access a memory location that is invalid to your program.
Then, coming to your question,
*p = (int) *c;
it basically dereference cNOTE to get the value, then cast it to an int type and store into the memory location pointed by p. However, in C, this casting is not required. The above statement is equivalent to
*p = *c;
anyway.
NOTE: Array name decays to the pointer to the first element of the array, i.e., in this code, using c is the same as &c[0], roughly.

initialized the value of a pointer in declaring process

something in the pointer confuse me
to declare a pointer to int and then define it
int *p, a;
p = &a;
a = 3;
it can be changed into
int a = 3;
int *p = &a;
I'm confused in the latter case. Isn't the value of *p is the value of the object which p point to ( the value of a in this example) so why in the former case it's
int *p = &a;
which is the address of a but not the value of a. Shouldn't it be
int p = &a
in order to state that p is the pointer and the address it point to is the address of the object a
Additionally, I see in some case there is (int*) p. Does it have any different to normal declaration?
* in declaration
int *p = &a;
is not an indirection operator. It just inform the compiler that p is a pointer type. * acts a dereferencing operator only when it appears in a statement. This means that *p in int *p = &a; is not same as *p as an alias of a.

Resources