Hi have a function which takes the argument of a pointer, to a pointer to a struct. I'm having trouble accessing the members of my struct. Do struct pointers behave differently to pointers of other types, or am i just missing somethign essential?
struct mystr {
int num;
};
void fun(mystr **out) {
printf("%d",**out.num); <-- where the problem arises
}
No, 'struct pointers' (whatever you mean) work precisely the same way as pointers to other types.
You just need to recall operators precedence:
. structure member access
->structure member access through pointer
(...)
* indirection (dereference)
(...)
So your expression **out.num is interpreted as *(*(out.num)) and your (out.num) is not a pointer, hence applying an asterisk to it is an error.
You need to parenthesise appropriate part of the expression to force a non-default operators binding: (**out).num – dereference out twice first to get to a struct mystr variable, then access that variable's num member.
The -> operator serves as a shortcut for accessing a member of pointed stucture:
(ptr_expr)->member_name is equivalent to (*(ptr_expr)).member_name
so you can replace (**out).num with (*out)->num.
Possible to the solution to use this :
printf("%d",(*out)->num);
instead of
printf("%d",**out.num);
This is the way you should implement, here printf("%d",(*(*out)).num); will print 1.
#include<stdio.h>
#include<stdlib.h>
struct mystr{
int num;
};
void fun(struct mystr **out) {
printf("%d",(*(*out)).num);
}
int main()
{
struct mystr m;
struct mystr *p;
struct mystr **pp;
p=&m;
pp=&p;
m.num=1;
fun(pp);
return 0;
}
Here m is our structure, p is pointer to structure and pp is pointer to the pointer p.
Related
I am new to C and have a question about a specific pointer declaration:
Here is a program i wrote:
#include <stdlib.h>
struct n {
int x;
int y;
};
int main()
{
struct n **p = malloc(sizeof(struct n));
return 0;
}
The declaration here is not be correct but why not?
Here is my thought process:
The man page of malloc specifies that it returns a pointer:
The malloc() and calloc() functions return a pointer to the
allocated memory, which is suitably aligned for any built-in
type.
The type of p is struct n** aka a pointer to another pointer.
But shouldn't this declaration work in theory because:
malloc returns type struct n* (a pointer)
and p points to the pointer that malloc returns
so it is essentially a pointer to another pointer
so the type of p is fulfilled
Sorry if this is a dumb question but i am genuinely confused about why this does not work. Thanks for any help in advance.
The return type of malloc is not struct n *, regardless of how it is called. The return type of malloc is void *.
Initializing a struct n ** object with a value of type void * implicitly converts it to struct n **. This implicit conversion is allowed, because the rules for initialization follow the rules for assignment in C 2018 6.5.16.1 1, which state one of the allowed assignments is:
… the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) one operand is a pointer to an object type, and the other is a pointer to a qualified or unqualified version of void, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;…
and p points to the pointer that malloc returns
No, the value p is initialized to the value that malloc returns. Then p points to the memory malloc allocated.
It is a mistake for this code to allocate enough space for a struct n (using malloc(sizeof(struct n))) but assign the address of that space to the struct n ** that is p. To point to a struct n, use struct n *p = malloc(sizeof (struct n)); or, preferably, struct n *p = malloc(sizeof *p);.
To pointer to a pointer to a struct n, first create some pointer to a struct n, as with the above struct n *p = malloc(sizeof *p);. Then a pointer to that pointer would be struct n **pp = &p;.
If you wanted to allocate space for those pointers-to-pointers, you could do it with struct n **pp = malloc(sizeof *pp);, after which you could fill in the pointer to the struct n with *pp = malloc(sizeof **pp);. However, you should not add this additional layer of allocation without good reason.
Note that the form MyPointer = malloc(sizeof *MyPointer); is often preferred to MyPointer = malloc(sizeof (SomeType)); because the former automatically uses the type that MyPointer points to. The latter is prone to errors, such as somebody misintepreting the type of MyPointer and not setting SomeType correctly or somebody later changing the declaration of MyPointer but omitting to make the corresponding change to SomeType in the malloc call.
This doesn't really work. In this example, malloc is returning a void *, which points to a newly allocated place in the heap that is large enough to hold a struct n.
Note that malloc() returns type void *, which is basically a pointer to any potential type, malloc() DOES NOT return type struct n * (a pointer to your declared struct type). void * has the special property of being able to be cast to any other type of pointer, and back again.
All together this means that your code doesn't actually work, since the first dereference of your struct n** would be a struct n, not a struct n*. If you tried to dereference twice, you would most likely get an invalid memory reference and crash.
The reason that your code can compile and run without crashing is because:
The compiler automatically casts void * to struct n **
You never attempt to actually dereference your pointer, which means you never attempt an invalid memory reference.
Simplify the problem and understanding may come:
int main()
{
struct n data;
struct n *pData = &data; // skipped in your version
struct n **ppData = &pData;
// struct n **ppData = &data; // Will not compile
// struct n **ppData = (struct n **)&data; // Casting but wrong!
return 0;
}
Because malloc() returns a void ptr, you are free to store the pointer into anything that is a pointer datatype. On your head if you put it into the wrong datatype...
Watch here:
struct mystruct{
int a;
int b;
};
int main(void){
struct mystruct* ptr;
ptr = malloc( 10*sizeof( struct mystruct ) );
In this way I have allocated an array of struct.
If you try to print, for example ptr[4], you will notice a pointer.
When I have a pointer and I have access to a member, I have to use the -> operator right?
But if I do:
ptr[4]->a
It doesn't work! I must do
ptr[4].a
to make it work... why? I have a pointer!
ptr[4] = (ptr+4) right?
Also in normal arrays this happen:
struct mystruct array[10];
array[4].a
but array is a pointer!
array[4] is not the same as array + 4. It's the same as *(array + 4).
array + 4 is certainly a pointer, but array[4] is the value pointed to by the pointer (which, of course, might also be a pointer if array were an array of some pointer type.)
Since x->y is essentially the same as (*x).y, you could rewrite array[4].a as (array + 4)->a, but you'd have a hard time getting that past most code reviewers.
when you use square brackets on a pointer, it's similar to dereferencing the point. Therefore, it requests the p[].a syntax, and not the p[]->a
(p + 4)->a is essentially the same as p[4].a
If ptr has type struct mystruct *, then ptr[i] has type struct mystruct; IOW, ptr[i] is not a pointer value. Thus, you need to use the . component selection operator instead of ->.
I came across a piece of code that looks like this, where nodeptr and bodyptr are pointers to a struct, and type is a member of the struct.
#define Type(x) (((nodeptr) (x))->type)
What does it mean to have two pointers next to each other in brackets? I get that the -> notation gets the member of the struct, but am not sure about the first part of the line. I'm fairly new to C and am trying to get my head around pointers!
It's a cast.
In this part, ((nodeptr)(bodyptr)), The pointer bodyptr is casted as pointer of type nodeptr, then it accesses the member type of the structure pointed to by bodyptr.
I.e.
void *GetStructPtr(void); //The function returns a pointer to void
typedef struct //This is our structure
{
float a;
int type;
} node;
type def node *nodeptr; //This is our pointer type
void my func(void)
{
void *bodyptr; //Here we have a generic void pointer
bodyptr = GetStructPtr(); //Assign to it the vallue returned from function
//In the next line we cast our void* to a pointer to a structure node
//and then access its member type.
((nodeptr)bodyptr)->type = 0;
}
In your case it has been inserted in a macro to make it easier to use.
It is cast. The pointer bodyptr is being casted to nodeptr and then type member accessed. This means that instead of accessing type member directly from bodyptr it is first converted to pointer of type nodeptr and only then accessed. It is useful e.g. when first pointer is just a pointer to raw memory, of type void * and you want to treat this memory as given type, maybe some struct.
Example:
struct e {
int a;
double b;
};
struct e foo { 1, 2.0 };
void *pFoo = &foo; // p points at foo now
// I know p is now address of object of type struct e
// and I want to get it's 'a' element BUT I can't
// do p->a, p is of void* type, yet I can do
int a = ((struct e*)(pFoo))->a;
I want to declare a int num in struct S. Then the same struct should also have a array B of size num(So B will access num from it's own struct).
while in a function, I can do,
func(int A)
{
int max=A; //I could use A directly, I am just trying to explain my plan.
int B[max];
}
same won't work for struct as such,
struct S {
int num;
int data[num]; //this is wrong, num is undeclared
};
Is there any way I can do this?
Use a flexible array member:
struct S {
int num;
int data[];
};
int x = 42;
struct S *p = malloc(sizeof (struct S) + sizeof (int [x]));
p->num = x;
There are several problems with
struct S {
int num;
int data[num];
};
that cause it to not work the way you want to.
The first is that the num being used in the array member declaration isn't the same num that's the member of the struct type; the compiler treats the num in the array declaration as a regular identifier (i.e., it assumes there's a different variable named num in the same scope as the struct declaration)1.
The second problem is that a struct or union type may not have a variable-length array as a member2. However, the last member in the struct may have an incomplete array type:
struct S {
int num;
int data[];
};
Unfortunately, you're still kind of stuck here; if you create an instance of struct S like
struct S foo;
it doesn't actually allocate any space for the array. You'd need to allocate the struct dynamically:
/**
* Note that sizeof doesn't try to actually dereference foo below
*/
struct S *foo = malloc( sizeof *foo + N * sizeof *foo->arr );
to allocate space for the array itself. Note that you cannot declare an array of struct S or use it as a member of another structure or union type if the last member has an incomplete array type. 3
Honestly, your best option is to define the struct as
struct S {
size_t num;
int *data;
};
and then allocate the memory for data as a separate operation from allocating memory for the struct object itself:
struct S foo;
foo.num = some_value();
foo.data = malloc( sizeof *foo.data * foo.num );
Since struct S now has a known size, you can declare arrays of it, and you can use it as a member of another struct or union type:
struct S blah[10];
struct T {
struct S s;
...
};
1. C supports four different name spaces - label names (disambiguated by label syntax), struct/union/enum tag names (disambiguated by the presence of the struct, union, or enum keyword), struct and union member names (disambiguated by the . and -> component selection operators), and everything else. Since the num in your array declaration is not an operand of . or ->, the compiler treats it as a regular variable name.
2. 6.7.2.1/9: "A member of a structure or union may have any complete object type other than a variably modified type."
2. 6.2.7.1/3: A structure or union shall not contain a member with incomplete or function type (hence,
a structure shall not contain an instance of itself, but may contain a pointer to an instance
of itself), except that the last member of a structure with more than one named member
may have incomplete array type; such a structure (and any union containing, possibly
recursively, a member that is such a structure) shall not be a member of a structure or an
element of an array.
First of all, the member num is not declared until the end of the struct definition, which ends at the last }.
Second, how would it make sense to set the array size to be the value of an uninitialized variable?
What I think you attempt to do with int B[max] is to create a variable length array (VLA). But that won't work either, as they are explicitly forbidden inside structs. 6.7.2.1/9:
A member of a structure or union may have any complete object type other than a
variably modified type.
What you could do instead is to declare a flexible array member, as demonstrated in the answer by Ouah.
The reason the compiler complains when you "flexibly declare" the array in the struct in global memory, is because global memory can only be allocated (declared) at compile-time and at compile time all sizes must be known. (The value of a variable is not known at compile time by definition.)
The reason it accepts a flexible array in a function, is because the function's local variables are created at the moment the function is entered and then the compiler can accept a variable size. (It boils down to the compiler allocating more memory on the stack and offsetting all accesses to local variables with the size - but different compilers could have a different approach.)
#include <stdio.h>
int size;
struct S {
int num;
int a[size]; // illegal: size must be known at compile time
};
int f(int size)
{
int a[size]; // legal as a is allocated on the stack
....
}
The following would be legal:
#include <stdio.h>
#define A_SIZE 10
struct S {
int num;
int a[A_SIZE]; // legal: A_SIZE is known at compile time
};
P.s.: I am not a C99 programmer; I may have some mistakes here.
I have two void pointers inside structures.
typedef struct DATA_T {
BOOLEAN trigger;
void *var_p;
void *data_p;
} DATA_T;
typedef struct ITEM_T {
DATA_T job_data[100];
BOOLEAN job_active;
BOOLEAN job_send;
} ITEM_T;
ITEM_T foo[100];
I assigned the two void pointers to different addresses. Now, I have a value at one pointer and want to set the other pointer = to that value.
foo[i].job_data[j]->data_p = *(int*)foo[i].job_data[j].var_p;
This error is then posted:
error C2232: '->data_p' : left operand has 'struct' type, use '.'
I don't believe I want a . in place of the -> here, because I need to dereference the pointer data_p.
Thanks for your assistance.
The error message is because job_data[j] is not a pointer. It is a DATA_T. So the left-hand side should be foo[i].job_data[j].data_p = .
However there is another error. On the right-hand side, *(int *) produces an int, which cannot be stored in a void *.
If you want to make the two pointers point to the same place then remove the *(int *).
If both pointers actually point to ints, and you want to copy the pointed-to value on both sides, then put *(int *) on both sides.
Elements of job_data array are not pointers, they're in the type of DATA_T.