So, the original code was:
Person * father = (Person *) malloc(sizeof(Person));
Marriage * marriage = (Marriage *) malloc(sizeof(Marriage));
1) Let place explicit boundaries between the type and the variable on each line
(Person *) father = (Person *) malloc(sizeof(Person));
(Marriage *) marriage = (Marriage *) malloc(sizeof(Marriage));
You see? So, here we have a type combined with the asterisk and it says a compiler "hey, this guy is a pointer to the type". And we use the same type on the right side to convert very generic (void *) to exact type.
2) It's time to use the thing we allocated. I could say, your original version is not so wide-spread way due excessive syntax (that's confusing you for sure):
(* marriage).male = father;
Way more preferred way is to say the following:
marriage->male = father;
Just 2 chars as the ->
instead of prepending and appending all that (*
and ).
around the variable name. And final result is just the same.