Menu

Structures

So far, we’ve looked at single data type variables. This just means, all our variables are used for a single purpose. We want to store a single integer number? Use an int. For a sentence? Array of characters, etc.
What about a Complex Number?
A complex number in math, is a number of the form: a + ib, where i is the square root of -1.
A complex number, z. Such that: z = a + ib contains a real part and an imaginary part.
We express these by writing:
Re(z) = a
and
Im(z) = b
Hence, to store a complex number we need a variable that contains 2 integers, the real part and the imaginary part.
To accomplish this task, we can create our own type.
This is called a “Structure”

Let’s build a simple example of a structure that will represent complex numbers.

We declare our structure like so:

struct Complex{
int real;
int imag;
};

Note that, I’m just using the integer type to represent my real and imaginary parts for the purpose of this example, however, feel free to make them float types or doubles if you want to have complex numbers such as: 2.3 + i3.9
Here’s an example of a structure that represents complex numbers.
To use it in our code we can do the following:

Note, sometimes you don’t want to keep writing “struct Complex” every time you want to declare a new complex number.
To get around that, we can use something called tyepdef in C.
You can do the following in your code:

Structures and Functions
In C, we can’t use normal arithmetic operators on structs.
Say we declare 2 Complex numbers and want to assign their sum to a third complex number.
The way to add 2 complex numbers z1 and z2 would be the following:
z1 = a + ib
z2 = c + id
z3 = a+c + i(b+d)
The real part of z3, the sum, is the sum of the real parts of z1 and z2, likewise the imaginary part of z3 is the sum of the imaginary parts of z1 and z2.
In C, if we write the following code:

This will result in an error, since the C compiler doesn’t know how to add these 2 objects.
We need to write our own function that accepts 2 complex numbers as arguments and returns their sum.
We will first write a straightforward and basic version of this, and than later improve it.Version 1

Okay, so here is the most primitive way to write our addition function for complex numbers. It accepts 2 arguments, inside it we declare a new complex number, we assign its real part to the sum of the real parts of its arguments. We do the same for the imaginary part. Finally we return our new object.
This code works fine, however let’s take a look at what’s happening in memory to get a better idea of why we can make this better.
First let’s take a look at C code that actually uses this function to add 2 complex numbers.

Let’s see how this will look in memory.
As you can see, in main we first create 3 Complex numbers.
Now, we pass 2 of these by VALUE to our add function.
Inside the add function, we create another Complex number, do the adding, and then make a copy of it and return it to Main.
One way to make this code better is to avoid making multiple copies of our Complex objects. Why don’t we pass them by pointers instead of by value.
Before we look at the code for passing the structures by pointer, we need to look at a new operator in C.
The arrow:->
Recall that when we have a structure, we access it’s internal components with the dot operator like so:

Complex x;
x.real = 2;

Now, let’s access our struct with a pointer.

Complex x;
Complex* ptr = &x;

Now, we have a pointer of type Complex* (complex pointer) this is pointing to a complex object.
If we want to access the internal members of the object through the pointer we have to first dereference the pointer, than use the dot operator, like so:

Complex x;
Complex* ptr = &x;
(*ptr).real = 2;

However, this code is messy and fairly error prone. Thankfully, C gives us a much cleaner way to do this.
When accessing the structure members through a pointer we can use the arrow operator. ->
We write the following.

Complex x;
Complex* ptr = &x;
ptr->real = 2;

And thus, no need to dereference. Just write the pointer name, followed by the arrow, ->, followed by the name of the struct member you wish to access.

As you can see, we are passing the addresses of the objects into our add function, and returning a pointer to somewhere in the heap.
At the end of our program, we free the memory allocated on the heap.
Inside the add function we allocate memory the size of a single Complex object.
Also, we write the keyword “const” in the parameters to indicate that we are not modifying the values of the arguments. This just prevents accidently changing their values in the function, and is considered good style.
Let’s have a look at the memory diagrams to get a better idea.Okay, first we have 2 objects declared in Main, and one pointer to a Complex object.
Next, we pass the addresses of these objects to our add function.
Inside the add function, we use malloc to dynamically allocate space for a Complex object on the heap, and assign its members the sum of the members of the arguments.

Inside add function returns the pointer to our object and goes out of scope.
Finally, the last thing we do is free the dynamically allocated memory.