My understanding is that the -> operator is shorthand for dereferencing a pointer to a struct, and accessing the value of one struct member.
struct point {
int x;
int y;
};
struct point my_point = { 3, 7 };
struct point *p = &my_point; /* p is a pointer to my_point */
(*p).x = 8; /* set the first member of the struct */
p->x = 8; /* equivalent method to set the first member of the struct */
So the last 2 lines of the example above are equivalent. But I've encountered some code similar to this:
*p->x = 8
Using both the asterisk and arrow together. What does this do? Would this try to "double dereference" the pointer and assign to memory address 8, or something else? Maybe undefined behavior, or just a compiler error?
*p->x is equivalent to *(p->x) - you are dereferencing the result of p->x, which implies the x member itself has pointer type. Given a line like
*p->x = 8;
that implies x has type int *:
struct foo {
...
int *x;
...
};
Note that x must be assigned a valid pointer value before you can assign to *x. You can allocate memory dynamically:
struct foo *p = malloc( sizeof *p ); // dynamically allocate space for 1 instance of struct foo
if ( !p )
// handle allocation failure and exit here.
p->x = malloc( sizeof *p->x ); // dynamically allocate space for 1 int.
if ( !p->x )
// handle allocation failure and exit here.
Or you can set x to point to an existing int object:
int a;
...
p->x = &a;
*p->x = 8;
For a structure
struct tagp
{
int *x=someaddress;
}p0;
struct tagp *p=&p0;
*p->x accesses the address stored in the pointer x inside the structure. It is same as *((*p).x) and *(p0.x) which accesses the memory at Someaddress.
Check this link
Related
I don't understand some topic from book Extreme C on page 300. It's about "multiple inheritance".
typedef struct { ... } a_t;
typedef struct { ... } b_t;
typedef struct {
a_t a;
b_t b;
...
} c_t;
c_t c_obj;
a_t* a_ptr = (a_ptr*)&c_obj;
b_t* b_ptr = (b_ptr*)&c_obj; //it's the problem
c_t* c_ptr = &c_obj;
Why we should do something like that??
c_t c_obj;
a_t* a_ptr = (a_ptr*)&c_obj;
b_t* b_ptr = (b_ptr*)(&c_obj + sizeof(a_t)); //?Is the address a_ptr the same as address c_obj?
c_t* c_ptr = &c_obj;
Thank you very much for all your help.
Why we should do...?
We should not do this!
First, sizeof a might be wrong to advance the address. If b_t as larger alignment requirements than a_t this will not yield the correct offset.
Second, the expression is wrong:
(&c_obj + sizeof(a_t))
This will take address of c_obj which has type c_t*. Then it will add a multiple of sizeof (c_t) which again points to object of type c_t but with an address that is illegal.
Third: Your casts are all wrong. You need to use name of a type, not a variable.
If you want to get address of b, there is a macro in C lib available offsetof:
offsetof(c_t,b)
evaluates to the offset in bytes of member b inside type c_t.
Then you can apply this to your address:
b_ptr=(b_t*) ((unsigned char*)&c_obj) + offsetof(c_t,b));
The first cast to unsigned char is required to use byte arithmetics.
Of course, there is a much simpler way to do this:
b_ptr=&c_obj.b;
Maybe the point of the book was to show that you cannot just use address of a struct and cast it to a pointer to another struct but you have to take care about the location of the members inside that struct. That is correct.
But the dirty details were a bit off.
Keep it simple:
c_t c_obj;
a_t* a_ptr = &c_obj.a;
b_t* b_ptr = &c_obj.b;
c_t* c_ptr = &c_obj;
The problem with:
b_t* b_ptr = (b_ptr*)&c_obj;//it's the problem
is that b_ptr ends up pointing to c_obj.a.
The problems with:
b_t* b_ptr = (b_ptr*)(&c_obj + sizeof(a_t));//?Is the address a_ptr the same as address c_obj?
are:
You are trying to adjust the pointer by sizeof(a_t) bytes, but pointer arithmetic is scaled by the size of the dereferenced type of the pointer. In this case, the pointer type is c_t* (from the expression &c_obj), and the dereferenced type is c_t, so the pointer is actually being adjusted by sizeof(c_t) * sizeof(a_t) bytes.
There may be padding after some of the members of c_t. In particular, there may be padding between the a and b members, so the b member may not be at the offset that you think it is. The offset of b from the start of c_t in bytes can be determined using the expression offsetof(c_t, b).
The address of an object of a structure type is equal to the address of the first member of the structure type.
So using your example
typedef struct {
a_t a;
b_t b;
...
} c_t;
c_t c_obj;
a_t* a_ptr = (a_ptr*)&c_obj;
then indeed the address of the data member a is equal to the address of the object c_obj.
However for the data member b this relation is broken because the data member b is not the first data member of the structure c_t.
As for this statement
b_t* b_ptr = (b_ptr*)(&c_obj + sizeof(a_t));
then it is entirely wrong. For starters in this sub-expression &c_obj + sizeof(a_t) there is used the pointer arithmetic and the value of the expression &c_obj is incremented by the value sizeof( c_t ) * sizeof( a_t ) .
It seems you mean
b_t* b_ptr = (b_ptr*)(( char * )&c_obj + sizeof(a_t));
However in any case the expression in the right side in general will not yield the address of the data member b due to a possible alignment,
Consider the following demonstrative program.
#include <stdio.h>
struct A
{
int x;
};
struct B
{
double y;
};
struct C
{
struct A a;
struct B b;
};
int main(void)
{
struct C c = { { 1 }, { 2.2 } };
printf( "&c.a = %p\n( char * )( &c.c ) + sizeof( struct A ) = %p\n&c.b = %p\n",
( void * )&c.a, ( void * ) ( ( char * )&c.a + sizeof( struct A ) ), ( void * )&c.b );
return 0;
}
Its output might look like
&c.a = 0x7ffe5e0697c0
( char * )( &c.c ) + sizeof( struct A ) = 0x7ffe5e0697c4
&c.b = 0x7ffe5e0697c8
As you see the data member a was appended with bytes to align the next data member b to double.
I would like to know, how to access first member of struct through pointer. I have tried this:
#include <stdio.h>
#include <stdlib.h>
struct foo
{
int a;
char *str;
};
int main()
{
struct foo *p = malloc(sizeof(struct foo));
int val = 10;
*(int**)p = &val; //set the value of the first member of struct foo
printf("%i\n",p->a);
}
but that print some garbage. How can I set it in similar manner?
What you're doing there is setting the value of p->a to the address of val (possibly truncated to 32 bits, depending on the implementation).
To access the field via a pointer, you have to take the field's address and then assign to the dereferenced pointer.
int *pa = &p->a;
*pa = val;
Of course you can also just write p->a = val. Note that p->a is just an abbreviation for (*p).a.
The assignment should be:
*(int*)p = val;
You want to assign to an int member, so the pointer has to be a pointer to int, not pointer to pointer to int. And the value being assigned must be int; &val is a pointer to int.
I know that if I have a pointer in C programming language, and I have to point to a struct, I do:
struct mystruct S;
struct mystruct *ptr;
ptr=&S;
ptr->member=5;
I understood this, but I do not understand the reason why, if I do:
ptr=&S;
(*ptr).member=5;
*ptr should point to the first address of the struct, but why doesn't it work if I do this:
*ptr.member=5;
Operators have precedence: the member access operator . has the highest precedence, while dereference * has the next highest precedence. So *p.member attempts to find the member member of a pointer to mystruct and then dereference it. Since a *mystruct does not have a member called member, this is an error.
Because the access to member operator (the dot) has precedence over the dereferenciation (*).
So, your expression is equivalent to:
*(p.member) = 5
And p.member is not a pointer.
Unary * has a lower precedence than the . and -> member selection operators, so *p.member is parsed as *(p.member); in other words, you're attempting to dereference the result of p.member. This has two problems:
p is a pointer type, so the compiler will complain that you're trying to use the . operator on something that isn't a struct or union type;
member isn't a pointer type, so you can't apply the unary * to it.
(*p).member is equivalent to p->member; both dereference p before accessing member.
If you have a structure
struct A
{
int x;
};
and an object of the structure type
A a;
then to access its data member x you have to write
a.x = 5;
Or you can write
( &a )->x = 5;
Now if you have a pointer of type struct A * that initialized by the address of the object a
struct A *pa = &a;
then expression *pa gives the object a itself. So you may write
( *pa ).x = 5;
So now compare. On the one hand
a.x = 5; and ( *pa ).x = 5;
and on the other hand
( &a )->x = 5; and pa->x = 5;
You have a struct and a pointer to the struct:
struct mystruct S;
struct mystruct *ptr;
Now you store in ptr the address of that struct
ptr = &S;
When you need to access one member of that struct through a pointer, you have TWO alternative syntaxes
(*ptr).member = 5;
and
ptr->member = 5;
The two syntaxes are equivalent and do exactly the same action.
Is only a matter of personal taste.
In your question you have an error, because you wrote:
(*p).member = 5;
Instead of
(*ptr).member = 5;
Hence the error
One last tip:
(*ptr).member = 5;
and
*ptr.member = 5;
Are different things
(*ptr).member = 5; means that you get the address pointed by ptr and then store 5 in the field named member
*ptr.member = 5; means that you get the address pointed by ptr.member and then store 5 in the memory pointed by that address.
I've recently found this page:
Making PyObject_HEAD conform to standard C
and I'm curious about this paragraph:
Standard C has one specific exception to its aliasing rules precisely designed to support the case of Python: a value of a struct type may also be accessed through a pointer to the first field. E.g. if a struct starts with an int , the struct * may also be cast to an int * , allowing to write int values into the first field.
So I wrote this code to check with my compilers:
struct with_int {
int a;
char b;
};
int main(void)
{
struct with_int *i = malloc(sizeof(struct with_int));
i->a = 5;
((int *)&i)->a = 8;
}
but I'm getting error: request for member 'a' in something not a struct or union.
Did I get the above paragraph right? If no, what am I doing wrong?
Also, if someone knows where C standard is referring to this rule, please point it out here. Thanks.
Your interpretation1 is correct, but the code isn't.
The pointer i already points to the object, and thus to the first element, so you only need to cast it to the correct type:
int* n = ( int* )i;
then you simply dereference it:
*n = 345;
Or in one step:
*( int* )i = 345;
1 (Quoted from: ISO:IEC 9899:201X 6.7.2.1 Structure and union specifiers 15)
Within a structure object, the non-bit-field members and the units in which bit-fields
reside have addresses that increase in the order in which they are declared. A pointer to a
structure object, suitably converted, points to its initial member (or if that member is a
bit-field, then to the unit in which it resides), and vice versa. There may be unnamed
padding within a structure object, but not at its beginning.
You have a few issues, but this works for me:
#include <malloc.h>
#include <stdio.h>
struct with_int {
int a;
char b;
};
int main(void)
{
struct with_int *i = (struct with_int *)malloc(sizeof(struct with_int));
i->a = 5;
*(int *)i = 8;
printf("%d\n", i->a);
}
Output is:
8
Like other answers have pointed out, I think you meant:
// Interpret (struct with_int *) as (int *), then
// dereference it to assign the value 8.
*((int *) i) = 8;
and not:
((int *) &i)->a = 8;
However, none of the answers explain specifically why that error makes sense.
Let me explain what ((int *) &i)->a means:
i is a variable that holds an address to a (struct with_int). &i is the address on main() function's stack space. This means &i is an address, that contains an address to a (struct with_int). In other words, &i is a pointer to a pointer to (struct with_int). Then the cast (int *) of this would tell the compiler to interpret this stack address as an int pointer, that is, address of an int. Finally, with that ->a, you are asking the compiler to fetch the struct member a from this int pointer and then assign the value 8 to it. It doesn't make sense to fetch a struct member from an int pointer. Hence, you get error: request for member 'a' in something not a struct or union.
Hope this helps.
I've been learning structs and I've come to the pointers to structs, where I'm currently struggling with this.
I've got this piece of code:
struct point {
int x;
int y;
} *ptr;
ptr->x = 8;
ptr->y = 8;
Running this gives a segmentation error. What I want to do is assign the value of 8 to x /y, to which, as far as I understand it, ptr is pointing to.
Your ptr is a pointer to struct point.
However, there is no struct point it is pointing to.
struct point {
int x;
int y;
} *ptr;
struct point pt; // add this...
ptr = &pt; // ...and this.
ptr->x = 8;
ptr->y = 8;
You have created a pointer called ptr but not initialized it. When you dereference it with ptr-> (or *ptr), you invoke undefined behavior which in your case is crashing the program (but could do anything).
This would be better:
struct point {
int x;
int y;
};
struct point sp = {0,0};
struct point *ptr = &sp;
sp.x = 8;
ptr->y = 8;
The problem is that the pointer ptr does not point to any valid memory buffer, assign it to a allocated or automatic storage instead:
// way 1
struct point p;
ptr = &p;
ptr->x = 8;
ptr->y = 8;
// way 2
ptr = malloc(sizeof *ptr);
ptr->x = 8;
ptr->y = 8;
// when you are done remember to release the allocated memory
free(ptr);
Let me explain you the simple way.
1.
Variables hold the data(values to want them to hold) and pointers hold only the memory address of the variables(which are just a section of memory). Pointers are used to just hold the address of the variables so they cannot hold any user data. We can although create a pointer to a variable and manipulate that variable using the specific pointer. We first need to create the variable, then we create a pointer which references that variable, then we do anything with the pointer and the variable will be manipulated.
struct point
{
int x;
int y;
};
struct point var1; //declare a variable
struct point *ptr=&var1;// declare a pointer to that variable
ptr->x = 8; // manipulate the variable
ptr->y = 8;
Or
2.
If you insist on using pointers only, then you need to allocate memory dynamically and then assign the base address of the allocated memory to the pointer.
struct point
{
int x;
int y;
} *ptr;
ptr=(struct point*)malloc(sizeof(struct point)); // this will allocate memory required to hold your structure
ptr->x = 8; //manipulate the memory content pointed by your pointer.
ptr->y = 8;
You need to assign a valid memory location to ptr, which is a pointer to struct point. You could either use malloc, or declare a variable with struct point and assign its address to ptr (like the above answers).
Btw, if ptr has file scope, then it is initialized with zero, i.e., the NULL pointer; otherwise, evaluating ptr is undefined behavior (you could get any value). In both cases, trying to dereference ptr is undefined behavior and thus you could get the segfault (in some implementation you might modified some memory location unintendedly).