Affecting a "static" struct in another struct in heap - c

So I solved my problem, wasn't that hard, but I'm wandering why the first version wasn't working.
So here, an example of my problem :
typedef struct a {
int i;
} A;
typedef struct b {
int i;
A a;
} B;
typedef B * PB;
PB create_B(int ia, int ib) {
PB b = malloc(sizeof(B));
b->i = ib;
b->a = {ia};
}
I get an error from the compiler saying :
"error: expected expression before ‘{’ token"
at line: b->a = {ia};
But i don't really get what is the problem.
I solved it casting the structure :
PB create_B(int ia, int ib) {
PB b = malloc(sizeof(B));
b->i = ib;
b->a = (A){ia};
}
But the types are well defined no ? I mean it's kind of obvious to me that {ia} is of type A since b->a is of type A aswell.
I am probably wrong on this last saying (compiler is probably right). So if you have an example where this situation isn't obvious and really need a cast, it would be really appreciated, or jut an explanation at least.
Thank you for your time.
Barioth
PS :
I could have done that too i guess
PB create_B(int ia, int ib) {
PB b = malloc(sizeof(B));
*b = (B){ib, {ia}};
}
But i still need a cast...

{ia} is not an expression in C and cannot be used in an expression statement.
{ia} is part of a syntax for definitions. In a definition, a list of initial values may be given in braces after an =. (And the braces may be omitted when initializing a scalar object.) This is a special syntax for initializing in a definition and is not an assignment like using = in an expression.
(A){ia} is an expression; it is a construct called a compound literal. After a type name in parentheses, initial values are given inside braces. This creates an object of the stated type. That object may then be used in an expression, such as as the right operand of an assignment.

Related

initializing array of structure with array elements in it

#include <stdio.h>
int main()
{
typedef struct s
{
int a;
int b[5];
char c[2];
}st;
st vs[1];
vs[0] = {1,{1,2,3,4,5},{'c','d'}};
printf("%d:a\n",vs[1].a);
printf("%d:b[0]\t %d:b[4]\n",vs[0].b[0],vs[0].b[4]);
printf("%c:c[0]\t %c:c[1]\n",vs[0].c[0],vs[0].c[1]);
return 0;
}
why does this doesn't work?
on
gcc -o main *.c
I get this error
main.c: In function 'main':
main.c:15:12: error: expected expression before '{' token
vs[0] ={1,{1,2,3,4,5},{'c','d'}};
But if I have this:
#include <stdio.h>
int main()
{
typedef struct s
{
int a;
int b[5];
char c[2];
}st;
st vs[] = {
{1,{1,2,3,4,5},{'c','d'}}
};
printf("%d:a\n",vs[0].a);
printf("%d:b[0]\t %d:b[4]\n",vs[0].b[0],vs[0].b[4]);
printf("%c:c[0]\t %c:c[1]\n",vs[0].c[0],vs[0].c[1]);
return 0;
}
it works. What is the logic in this.
How can I make it work using st vs[1] method?
You can only do braced initialization when you declare a variable. So,
st vs[] = {
{1,{1,2,3,4,5},{'c','d'}}
};
is allowed. But
vs[0] = {1,{1,2,3,4,5},{'c','d'}};
is not. Because this is not a initialization but assignment.
However, you can use C99's compound literal, see C11, 6.5.2.5:
vs[0] = (struct s){1,{1,2,3,4,5},{'c','d'}};
Initialization is when you declare a variable and provide initial values for it as part of the declaration. For example this is legal:
st vs[1] = { {1,{1,2,3,4,5},{'c','d'}} };
Your code is actually attempting assignment. Assignment is when an existing variable has a value assigned to it. The reason your code doesn't work is that {1,{1,2,3,4,5},{'c','d'}} isn't a value.
In a statement (not a declaration), each expression must be readable by the compiler on its own merit, and a more complicated statement is made up of various expressions joined by operators. So the compiler doesn't know what to do with {1,{1,2,3,4,5},{'c','d'}} - at this stage it has no idea that that is supposed to be a st.
Since C99 there is a new language construct you can use here, called compound literal:
vs[0] = (const st){1,{1,2,3,4,5},{'c','d'}};
Note that this is not a cast operator being applied to some sort of braced expression; it is a single syntactic construct (Typename){ initializers } .
My use of const is a micro-optimization, it may help the compiler store the literal in a read-only block of the executable and allow constant folding.

typedef'ng a pointer and const

I was looking at an example which showed that why typedef'ng a pointer is a bad practice. The part I didn't understand about the example is that why the compiler wasn't able to catch the problem. I elaborated the example into the following code:
#include <stdio.h>
typedef int *TYPE;
void set_type(TYPE t) {
*t = 12;
}
void foo(const TYPE mytype) {
set_type(mytype); // Error expected, but in fact compiles
}
int main() {
TYPE a;
int b = 10;
a = &b;
printf("A is %d\n",*a);
foo(a);
printf("A is %d\n",*a);
return 0;
}
So, I was able to change the value of a. Even though, the example explained that you would have to do, typedef const int *TYPE, to solve the problem, I dont understand why the compiler was not able to catch the error when I am setting TYPE to be const in the function argument itself. I am sure I am missing something very basic.
The issue here is confusion about what const is being applied to: is it applied to the pointer value itself, or the value being pointed to?
const TYPE x is saying that the pointer value should be constant. This is roughly equivalent to int * const x. Note that the following code does result in an error:
int b = 10;
const TYPE p = NULL;
p = &b; // error here (assign to const)
What you were expecting is const int * x, which makes the value pointed to by x a constant.
Since the typedef hides the fact that TYPE is a pointer type, there's no way to specify that the thing pointed to by TYPE should be const, aside from declaring another typedef:
typedef const int * CONST_TYPE;
However, at this point the typedef seems to be causing more trouble than it solves... Probably not the best idea.

Pointer to array structure

I have a small program which when compiling throws me the following errors
error #2168: Operands of '+' have incompatible types 'struct agenda' and 'int'.
error #2113: Left operand of '.' has incompatible type 'int'.
error #2088: Lvalue required.
This is the code that I have done
#include <stdio.h>
struct agenda{
int order, cellular;
char name[30], last_name[30], street[30], city[30], mail[50];
}contact[10];
int main(void)
{
struct agenda *ptrcontact;
ptrcontact = &contact[0];
(*ptrcontact+3).order = 3;
printf("\n\n %d", (*ptrcontact).order);
return 0;
}
because it throws these errors and how to fix them?
You need to change
(*ptrcontact+3).order = 3;
to
ptrcontact[3].order = 3;
or, at least,
(*(ptrcontact+3)).order = 3;
or,
(ptrcontact + 3)->order = 3;
Otherwise, as per the precedence rule, * has higher precedence over +, causing the error.
Just to add to that, ptrcontact is a pointer ( to struct agenda) and can be used as an operand to + operator.
OTOH, *ptrcontact is of type struct agenda and cannot be used as an operand to + operator.
You are dereferencing the pointer which yields the struct and obviously you can't add anything to that. Dereference operator has the highest priority, you need to do it like this: (*(ptr + 3)).order or use the arrow instead of star dot: (ptr + 3) -> order
Your problem here is operations priority:
(*ptrcontact+3).order = 3;
This derefers ptrcontract and then tries to add number to dereferred structure. Which gives you exact situation you report.
My recommendations:
Either avoid address ariphmetics in such cases. Operate array indexes.
int baseIndex = 0;
contact[baseIndex + 3].order = 3;
Or if you really have to do so, hide address arithmetic from outside:
(pcontact + 3)->order = 3;
And finally learn C language operations priority or, to do it once (but some C people don't like C++), C++ operations priority
the error is in the lines
(*ptrcontact+3).order = 3; and printf("\n\n %d", (*ptrcontact).order);. In this instructions use -> instead of . the errors will be solved.

Why is sizeof(type) the size of a pointer, not the size of the type itself?

In this code, why is sizeof(x) the size of a pointer, not the size of the type x?
typedef struct {
...
} x;
void foo() {
x *x = malloc(sizeof(x));
}
Because C says:
(C99, 6.2.1p7) "Any other identifier has scope that begins just after the completion of its declarator."
So in your example, the scope of the object x start right after the x *x:
x *x = /* scope of object x starts here */
malloc(sizeof(x));
To convince yourself, put another object declaration of type x right after the declaration of the object x: you will get a compilation error:
void foo(void)
{
x *x = malloc(sizeof(x)); // OK
x *a; // Error, x is now the name of an object
}
Otherwise, as Shahbaz notee in the comments of another answer, this is still not a correct use of malloc. You should call malloc like this:
T *a = malloc(sizeof *a);
and not
T *a = malloc(sizeof a);
This is because sizeof(x) uses the innermost definition of x, which is the pointer. To avoid this problem, don't use the same name for a type and a variable.
It is a bad idea to not give different things different names (not only in programming):
The academic reason for the behavior observer had already been mentioned by my dear fellow annotators.
To give clear advises name diffenet things differnet (here: variable types and variable instances):
typedef struct {
...
} X;
void foo() {
X *x = malloc(sizeof(X));
}
An even more flexible way to code this example would be (as also already mentioned by Shahbaz's comment):
typedef struct {
...
} X;
void foo() {
X *x = malloc(sizeof(*x));
}
The latter example allows you to change the type of x without changing the code doing the allocation.
The drawback of this approach is that you could switch from using references to arrays and verse vica (as type for x) without being notified by the compiler, and break your code doing so.

Pointer and Structure problems

I am suppose to be creating a memory map of this program for my class, but when I try to compile it, I get an error:
invalid operands to binary expression ('double *' and 'double *')
I am a student, please do not edit the code to print out memory locations, I need to write that myself.
main()
{
double testd;
int testi;
FILE *fpt;
struct frog {
double *x, y;
}frog;
struct frog turtle, *apple, tv[3];
testi = 2;
apple = &turtle;
apple->x = &testd
*(turtle).x = 7.3; //this is where im getting the error.
(*apple).y = 3.6;
turtle.y = 1.5;
for (testi = 0; testi < 3; testi++)
tv[testi].x = &(tv[(testi+1)%3].y);
*(tv[1].x) = 6.4;
}
You are missing the ; at the end of the previous line.
You are not wrong to dereference *(turtle).x instead of *(turtle.x). The . operator has higher precedence than the * operator, meaning those two statements are equivalent and you don't even need parentheses: you could just do *turtle.x.
Check out this site for precedence ordering.
You are missing the ; at end of the previous line.
The compiler then interprets the * at the beginning of the line as a multiplication symbol and complains because that doesn't work out so well.
You simply forgot ; after apple->x = &testd statement.
On a side note, in C you have to say struct before a structure, and main function is supposed to return an integer. You also need to include header files with declarations of data structures and functions that you are using (i.e. stdio.h). Not to mention that // comment style is C99, and C programmers don't really use it.. /* */ comments are awesome.

Resources