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 *.
Related
If a pointer "p" holds the address of a variable "a". if a=12 ( just taking an integer ) . If the address of "a" is 1024 (just an assumption for asking my doubt). That means the value in "p" is 1024. This 1024 is address but it is basically a number . Then why it doesn't work when we declare the integer pointer variable "p" as integer variable "p". like:
int p, a=12;
p=&a;
printf("value of a is : %d", *p );
The example could be properly written (with some additional output) as:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main(void)
{
intptr_t p;
int a = 12;
p = (intptr_t)(void *)&a;
printf("value of a at %" PRIdPTR " is : %d\n", p, *(int *)(void *)p);
return 0;
}
That relies on the following facts:
A pointer to any object can be converted to void * and back to a pointer to the original object type and it will compare equal to the original pointer to the object (so it will still point to it).
A pointer to void can be converted to a intptr_t or a uintptr_t value (by a cast operator) and back again and it will compare equal to the original pointer.
The PRIdPTR macro defined by #include <inttypes.h> expands to a string literal containing a printf conversion specifier (possibly preceded by a length modifier) suitable for printing the value of a parameter of type intptr_t as a signed decimal number. It is being included in the printf format string by string literal concatenation.
A void * pointer value is usually printed using the %p printf format, for example:
printf("value of a at %p is : %d\n", (void *)p, *(int *)(void *)p);
or:
printf("value of a at %p is : %d\n", (void *)&a, a);
To declare p as a pointer to int do it the following way:
int *p; /* p is a pointer to int */
so, with initializers:
int a = 12, /* a is an integer var and it's initialized to 12 */
*p = &a; /* p is an integer pointer and it's initialized to the addreess of a */
or as assignments:
a = 12; /* a is assigned the value 12 */
p = &a; /* p is assigned the address of a */
works, and *p will have the same value as a.
printf("value of a is : *p==%d (or what should be the same: a==%d)", *p, a);
*p means the to take data from the place which p stores.
The * operator when applied to an operand p basically means "read what's on address stored in p and interpret it as the type indicated by the pointer type p is declared as"
You're missing the last part. In your case, p is not a pointer, so the dereference operator does not make sense to use.
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.
Bellow there is a simple code which asks the last name, and 2 grades for 5 persons separately. It also
finds the mean of all the grades and who has the higher grade.The question is about " * " symbol.
My professor is calling a function which is called readstudent(Tstudent *pstu);
What does * before pstu means, and why is it necessary?
Also when we go through readstudent(Tstudent *pstu) why there is "&" for grade 1 and 2 and there is no "&" for the name?
#include <stdio.h>
#include <string.h>
typedef struct student
{
char name[20];
float grade1;
float grade2;
} TStudent;
void readstudent( TStudent *pstu );
void printstudent( TStudent stu );
int main( void )
{
int N = 5;
TStudent a[N]; int i, imax; float max, mo, sum;
for(i=0; i<N; i++)
readstudent( &a[i] );
printf("\n Oi karteles twn foitntwv einai:\n");
for(i=0; i<N; i++)
printstudent( a[i]);
sum = 0;
for(i=0; i<N; i++)
sum = sum + (a[i].grade1+a[i].grade2)/2;
mo = (float)sum / N;
printf("\nO mesos oros bathmologias tns taksns einai %2.2f\n", mo);
imax = 0;
max = (a[0].grade1+a[0].grade2)/2;
for(i=0; i<N; i++)
if ((a[i].grade1+a[i].grade2)/2 > max)
{
max = (a[i].grade1+a[i].grade2)/2;
imax = i;
}
printf("\nO/H foitntns/tria me ton ypsnlotero meso oro (%4.2f) einai o/h %s.\n", max, a[imax].name);
return 0;
}
void readstudent( TStudent *pstu)
{
printf("Eisagwgh foitntn/trias: epwnymo <keno> bathmos1 <keno> bathmos2 <keno>: \n");
scanf("%s", pstu->name);
scanf("%f", &pstu->grade1);
scanf("%f", &pstu->grade2);
}
void printstudent( TStudent stu)
{
printf("Epwnymo: %s\n", stu.name);
printf("Bathmos-1: %4.2f\n", stu.grade1);
printf("Bathmos-2: %4.2f\n", stu.grade2);
}
Thanks for your time, appreciate your help!
So, quick crash course on pointers in C.
First of all, why do we use pointers in C? Basically, we have to use pointers for the following reasons:
To allow functions to modify their parameters
To track dynamically allocated memory
Pointers come in handy in other ways, because they offer a form of indirection. They allow us to manipulate other objects without having to know the other objects' names.
Indirection is a powerful tool in programming, one that you've already seen if you've dealt with arrays. Instead of creating 100 unique integer variables, we can create an array of integers, and use subscripting to refer to a specific object. That is, instead of writing
int var0 = 0;
int var1 = 1;
int var2 = 2;
...
int var99 = 99;
we can write
int var[100];
for ( int i = 0; i < 100; i++ )
var[i] = i;
Array subscript notation allows us to refer to an object indirectly, rather than by a unique name. It provides a shortcut for managing large numbers of objects by referring to them with a single expression. Pointers serve much the same purpose. Suppose we have several integer variables named x, y, and z. We can create a pointer p to refer to each one in turn:
int x = 10;
int y = 20;
int z = 30;
int *p;
Let's start by playing with x. We set p to point to x using the unary & address-of operator:
p = &x; // int * = int *
The type of the variable p is int *. The type of the expression &x is int *, and the value of the expression is the address of x. We can then change the value of x through p using the unary * indirection operator:
*p = 15; // int = int
Since the type of the variable p is int *, the type of the expression *p is int, and that expression designates the same object that the expression x does. So in the line above, we're changing the value stored in x indirectly through p. We can do the same thing with y and z:
p = &y;
*p = 25;
p = &z;
*p = 35;
Okay, cool, but why not just assign to x, y, and z directly? Why go through the pain of assigning their addresses to p and assigning values through *p?
Normally we wouldn't do it that way, but there's a case where it can't be avoided. Suppose we want to write a function that modifies the value of one or more of its parameters, like so:
void foo( int x )
{
x = 2 * x;
}
and call it like this:
int main( void )
{
int val = 2;
printf( "before foo: %d\n", val );
foo( val );
printf( "after foo: %d\n", val );
return 0;
}
What we want to see is
before foo: 2
after foo: 4
but what we get is
before foo: 2
after foo: 2
It doesn't work because C uses a parameter-passing convention called "pass-by-value" - in short, the formal parameter x in the function definition designates a separate object in memory than the actual parameter val. Writing a new value to x doesn't affect val. In order for foo to modify the actual parameter val, we must pass a pointer to val:
void foo( int *x ) // x == &val
{ // *x == val
*x = *x * 2;
}
int main( void )
{
int val = 2;
printf( "before foo: %d\n", val );
foo( &val );
printf( "after foo: %d\n", val );
return 0;
}
Now we get the output we expect - val is modified by foo. The expression *x refers to the same object that val does. And now we can write something like
foo( &y ); // x == &y, *x == y
foo( &z ); // x == &z, *x == z
This is our first use case - allowing a function to modify its parameters.
There are times during a program's execution where you need to allocate some extra memory. Since this allocation occurs at runtime, there's no way to specify a name for this extra memory the same way you do for a regular variable. IOW, there's no way to write
int x = new_memory();
because variable names don't exist at runtime (they're not preserved in the generated machine code). Again, we must refer to this dynamically allocated memory indirectly through a pointer:
int *p = malloc( sizeof *p ); sizeof *p == sizeof (int)
This allocates enough space for a single int object, and assigns the address of that new space to p. You can allocate blocks of arbitrary size:
int *arr = malloc( sizeof *arr * 100 );
allocates enough space for 100 int objects, and sets arr to point to the first of them.
This is our second use case - tracking dynamically allocated memory.
A quick note on pointer syntax. There are two operators associated with pointer operations. The unary & operator is used to obtain the address of an object, while the unary * dereferences a pointer. Assume we have an int object named x and a pointer to an int named p:
p = &x; // assign the address of x to p
*p = 10; // assign a new value to whatever p points to
In a declaration, the unary * indicates that the thing being declared has pointer type:
int *p; // p has type "pointer to int"
When you initialize a pointer in a declaration like
int *p = &x;
p is not being dereferenced. That is the same as writing
int *p;
p = &x;
The * operator binds to the thing being declared, not to the type specifier. You can write that same declaration as
int* p;
int * p;
int*p;
and it will always be parsed as int (*p);.
For any type T, the following are true:
T *p; // p has type "pointer to T"
T *p[N]; // p has type "array of pointers to T"
T (*p)[N]; // p has type "pointer to array of T"
T *p(); // p has type "function returning pointer to T"
T (*p)(); // p has type "pointer to function returning T"
Complex pointer declarations can get hard to read, since the unary * is a prefix operator and has lower precedence than the [] and () operators. For example:
T *(*(*foo)())[N];
foo is a pointer to a function returning a pointer to an N-element array of pointers to T.
With your code, we're dealing with the first case - we want the readstudent function to modify the contents of an existing instance of struct student. And readstudent does that by calling scanf to read values into each separate member:
scanf("%s", pstu->name);
scanf("%f", &pstu->grade1);
scanf("%f", &pstu->grade2);
Remember that scanf expects its arguments to be pointers - again, we're trying to modify the contents of an object, so we have to pass a pointer to that object as the parameter.
&pstu->grade1 evaluates to the address of the grade1 member of the object that pstu points to. &pstu->grade2 evaluates to the address of the grade2 member of the object that pstu points to.
So what the heck is going on with pstu->name?
Arrays are special in C. Unless it is the operand of the sizeof or unary & operators, or is a string literal used to initialize an array in a character declaration like
char foo[] = "test";
an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T" and the value of the expression will be the address of the first element of the array.
We won't go into the weeds on this, but this was a deliberate design decision by Ritchie when he was first creating the C language, and it does serve a purpose. It also means that arrays lose their "array-ness" under most circumstances, and what you wind up dealing with is actually a pointer to the first element, not the whole array itself. In the case of the scanf call, we're passing the equivalent of &pstu->name[0].
I'll answer a slightly different question first; but related.
"what does void printstudent( TStudent stu ); do?"
The answer is it takes a copy of the of the argument, and then does something with it.
By taking a copy of the data; it's unable to edit what was originally passed in.
Now we get to "what does void readstudent( TStudent *pstu );" do:
which is that it takes a copy of the pointer to some data. This will allow it to edit the data that is being pointed to.
As Jesper states; there are many other uses of *; but these are the basics that you need to know to understand THIS usage
* means different things in different contexts. Remember that C (and C++) is a context sensitive language.
When you declare a variable, like; int* foo; the * means that foo is a "pointer to int".
When you write a statement like printf("%d", *foo); the * means dereference the pointer stored in foo and give me the int value it points to.
When used in a function declaration like void f(int* bar) it means that the function accepts a pointer to an integer as its argument.
It can also mean multiplication, like in int something = baz * 42;
Or it can just be a plain character in a character literal, with no special meaning. Like const char[] foo = "bar*baz*";.
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.
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