FAQ > All about structures

Structures are a convenient way of grouping together related variables of possibly differing types. For example, if you wanted to create a single variable that represents a person, a structure is ideal. Such a variable would need several sub-variables, for example:

Person
Name
Age
Height

Creating structures

Well, this is easily done with a simple structure declaration:

struct Person {
char *name;
int age;
float height;
};

As you'll notice, a structure declaration begins with the keyword struct followed by the name of the structure. The name is optional. This sounds weird until you realize that a structure declaration defines a type. In other words, you can declare variables right after the closing brace:

One thing to note however, is that if you omit the name (also known as the structure tag) from the declaration, you must declare variables of the structure in the same declaration. To declare variables of the structure later, you need the name of a type in one of two ways:

Both of these examples require some explanation. The first declares a structure just as we've been talking about, but it doesn't include the declaration of a structure variable. Because the structure has a tag, we can declare a structure variable later, but the struct keyword is required to tell the compiler that Person is a structure. This restriction is removed by C++, but the C solution is to use a typedef, which takes us to the second example.

While it may look funny, using a typedef with a structure declaration is exactly the same as with any other type. It helps to remove the member variables and get a good look at the structure of the typedef:

typedef int INT;
typedef struct {} STRUCT;

Both are the same: the typedef keyword followed by the type to create an alias for, and finally the alias itself. But with larger structures this can become difficult to read, so the declaration is broken up into separate lines and indented to be readable as in our example above. Also notice that the struct keyword isn't needed when using the alias, this is because the keyword was included as a part of the typedef, adding another would be redundant and an error because Person_t isn't a struct, it's a typedef of a struct.

Like any variable, structure variables can be initialized with a list enclosed in braces:

struct Person Prelude = {"Prelude", 25, 5.9f};

Initialization is exactly the same when a variable is declared directly within the structure declaration:

A structure variable can also be initialized by assigning an existing structure variable (in which a copy is made) or by calling a function that returns a structure of the same type.

Accessing structure variables

Now that we have a structure variable, it would be a good idea to try and get access to the member variables. If that weren't possible, structures wouldn't be very useful. To get to a particular member of a structure, the structure-name.member syntax is used, also called the dot operator:

When using the dot operator to access nested structures, just start on the left side with the outermost structure and go in:

printf ( "%d Inches\n", Prelude.height.inches );

When accessing a pointer to a structure, the pointer must first be dereferenced before the dot operator is used:

struct Person *Prelude;
...
printf ( "Name: %s\n", (*Prelude).name );

Now, using this (*structure-name).member syntax is awkward, ugly, and adds even more unnecessary parentheses to a language that already overuses them. So a special operator was added to the language because accessing the member of a pointer to a structure is so common and useful, structure-name->member, also called the arrow operator. Now we don't need to explicitly dereference the pointer or surround it with parentheses:

printf ( "Name: %s\n", Prelude->name );

Structures and Functions

Just like any other type, structures can be assigned to each other as well as passed to and returned from functions or have pointers to them passed to and returned from functions. There are three ways a structure can be passed to a function:

The preferred method in most cases is to pass a pointer to the structure. This saves space for larger structures and can often be faster. In fact, most data structure libraries will have a make_node type function that allocates memory to a pointer and returns it, or takes a pointer to a pointer and allocates memory to that:

Structures can contain pointers to a structure of the same type. Also called a self-referential structure:

struct Node {
void *data;
struct Node *next;
};

This is a typical node structure for a single item in a linked list. While this feature may seem confusing, keep in mind that when a Node variable is declared, only a pointer to a Node is created for the member, not an actual Node. If an actual Node were created, you would have a recursive declaration, and Nodes would be created until you run out of memory. But a pointer is safe because it doesn't behave recursively in this situation.

Two different structures can refer to each other. This is handled in much the same way as a structure referring to itself:

struct a {
struct b *p;
};
struct b {
struct a *p;
};

There is another feature of structures that can be useful sometimes called bit-fields. They're an advanced topic that I will cover in another tutorial, along with another type of structure called a union.