c structs
Summary
Struct type
- grouping heterogenous members
- not a variable, no memory allocated to types
- acts as a blueprint for the members associated with the type
c
struct S {
int x, y;
} c; // combined declaration of struct S and c, a variable of struct S
struct S d; // declaration of d, a variable of struct d
typedef struct S T; // typedef of T as an alias of struct S
struct S a = { 2, 3 }; // using the struct S type
T b = { 4, 5 }; // using the T alias
// combining all under one typedef
typedef struct S {
int x, y;
} T;
// similarly, reordered
struct S {
int x, y;
} typedef T;
// shared name
typedef struct S {
int x, y;
} S;
struct S a = { 2, 3 }; // using the struct S type
S b = { 4, 5 }; // using the S alias
Struct variable
- similar to creating an instance of a class
c
// declaration
point p1;
// initialization during declaration
point p2 = { 1, 2, "2" };
Assignment
c
// cannot initialize after declaration, similar to arrays
point p3;
p3 = { 1, 3, "3" }; // error
// assignment from a pre-existing struct
point p4 = { 1, 4, "4" }, p5;
p5 = p4;
// or by assigning each member
p5.x = p4.x;
p5.y = p4.y;
p5.label = p4.label;
Concept
Structural recursion
- when its own type is used within itself
c
typedef struct SLL {
int v;
struct SLL *next;
} SLL;
// or with a forward declaration
typedef struct SLL SLL;
struct SLL {
int v;
struct SLL *next;
};
Structs as function parameters
- pass-by-value
- struct is copied into the local variable
c
void inverse(point);
int main(void) {
point a = { 1, 2, "hello" };
printf("%d, %d, %s\n", a.x, a.y, a.label); // 1, 2, "hello"
inverse(a);
printf("%d, %d, %s\n", a.x, a.y, a.label); // 1, 2, "hello"
return 0;
}
void inverse(point a) { // a is local to the execution of inverse
int temp = a.x;
a.x = a.y;
a.y = temp;
}
Struct pointers
- allow a function to make modifications to the original struct
c
void inverse(point *);
int main(void) {
point a = { 1, 2, "hello" };
printf("%d, %d, %s\n", a.x, a.y, a.label); // 1, 2, "hello"
inverse(&a);
printf("%d, %d, %s\n", a.x, a.y, a.label); // 2, 1, "hello"
return 0;
}
void inverse(point *a) { // a is a local pointer to the external struct
int temp = (*a).x; // dereference a and get the member x
(*a).x = (*a).y;
(*a).y = temp;
}
the parentheses are required in
(*a).xsince the.operator has precedence over*
Arrow operator
- syntactic sugar
c
// rewritten to use the arrow operator
void inverse(point *a) { // (*a).x becomes a->x
int temp = a->x; // dereference a and get the member x
a->x = a->y;
a->y = temp;
}
Application
Nested structs
c
typedef struct {
int day, month, year;
} date_t;
typedef struct {
int cardNum;
date_t expiryDate;
} card_t;
card_t card1 = {888888, {31, 12, 2020}};
Struct array
c
point line[3] = {{ 1, 2, "A" }, { 2, 4, "B" }}; // only 2 points initialised
// pointers
printf("%p\n", line); // addr
printf("%p\n", &line[0]); // addr
printf("%p\n", line + 1); // addr + 1 * sizeof(point)
printf("%p\n", &line[1]); // addr + 1 * sizeof(point)
// what does the last one get initialized as?
printf("%d\n", line[2]); // 0
printf("%d\n", line[2].x); // 0
printf("%d\n", line[2].y); // 0
printf("%d\n", line[2].label); // 0
// effectively, all the bytes it would have occupied get initialized to 0
keep in mind that the size of a pointer depends on architecture