Functions, structs and pointers
Pointers to struct provide a convenient way to access struct's members. The concept of pointers to struct is the same as pointer to any other variable: we first have to declare the variable and the pointer to it, then make the pointer point to that variable's memory address. The advantage of using pointers to structures is that in case we have a function that does something which requires data from a struct we don't have to pass all the struct's values to the function, just a reference, a pointer which can directly access the struct's members.
Errors of logic:
- If the pointer to struct is not pointing to a struct, trying to use it to access a struct's member will cause the program to crash;
- Pointers to struct and structs must match each other's type to avoid errors.
To understand the example below it's required to have a good understanding about pointers, functions and structs
- A function that swaps all values of all members of two structs of the same type:
typedef struct Product Pro;
struct Product { char Type[1]; int Year; };
/* Receives two addresses of two structs, A and B, and swaps the values of all members of both */
void Swap (Pro *A, Pro *B) {Pro Temp, *C;
C = &Temp;
*C = *A;
*A = *B;
*B = *C;
}
/* Calling the function */
Swap(&X, &Y);
It's the same example about swapping the values of two variables, this time done with structs and pointers to struct. Note that both structs must be of the same type, else program won't compile.
Note: in the above example, X and Y are of the same "Pro" type. When we call a function with memory addresses as arguments, the address itself doesn't hold information about the variable's type, so we must be careful to not mix up pointers to a struct of one type and memory addresses of structs of a different type.
- A function that swaps the value of a specific member of two structs:
typedef struct Product Pro;
struct Product { char Type[1]; int Year; };
/* Receives two addresses of two structs, A and B, and swaps the values of the members called "Year" of both */
void Swap (Pro *A, Pro *B) {Pro Temp, *C;
C = &Temp;
C->Year = A->Year;
A->Year = B->Year;
B->Year = C->Year;
}
/* Calling the function */
Swap(&X, &Y);
The arrow operator: both C->Year and (*C).Year mean the same thing. In case of "asterisk" and "dot" we have to use parenthesis because the asterisk has precedence over the dot, meaning that the compiler will read *(C.Year) and will print an error because there is no pointer with that name. The arrow operator is a mnemonic sign to remind that C is a pointer and it's pointing at a struct, of type "Pro", at a member called "Year".
Note: we must be careful to not confuse the pointer to a struct with the struct itself. Therefore, if we write C.Year or B.Type[0], we are telling the compiler that "C" and "B" are structs, which they are not.