lite-C 101

Top  Previous  Next

This month we are going to talk about structures. A structure is nothing more than a mixture of data: variables, pointers, strings, and so on. 

In fact, you might have used lots of structs already: CAMERA, PANEL, TEXT, MATERIAL, etc are predefined structures built inside the Acknex engine. 

Here's just one of the examples that can be found inside the atypes.h file that comes with GameStudio and lite-C:

 

typedef struct {

       var blue, green, red;

} COLOR;

 

A typical structure definition looks just like this:

 

typedef struct {        

       int age;        

       int kids;        

       char* name;

} PEOPLE;

 

In this case, we have defined a struct type named PEOPLE which contains 2 integers (age, kids) and a string (name). 

We can now create structs based on our previously defined struct type named PEOPLE:

 

PEOPLE james; // creates a PEOPLE struct named james 

PEOPLE* jacob; // creates a pointer to a PEOPLE struct 

 

Let's open and run the structs1.c file:

 

aum72_workshop1

 

The source code is simple, as always:

 

var johns_age;

var johns_kids;

 

STRING* johns_str = "                    "; // holds up to 20 characters

 

typedef struct {        

       int age;        

       int kids;        

       char* name;

} PEOPLE;

 

PEOPLE* john =

{        

       age = 42;

       kids = 3;        

       name = "John Doe";

}

 

PANEL* johns_pan =

{        

       digits (20, 30, "Age: %.0f", *, 1, johns_age);

       digits (20, 40, "Number of kids: %.0f", *, 1, johns_kids);        

       digits (20, 20, johns_str, *, 0, 0);        

       flags = visible;

}

 

function main()

{        

       johns_age = john.age;

       johns_kids = john.kids;

       str_cpy(johns_str, john.name);

}

 

A structure can't be initialized when it is created, but a struct pointer can be initialized, just like I did it with "john" from our example. The code sets all the fields in our struct: age = 42, kids = 3 and name = "John Doe". Function main simply copies these values to 2 variables and a string so that we can displays them on the screen using a panel. Of course that we can change the values for our struct at runtime, using something like "john.age = 35;" and so on.

 

Some of you might say that we don't really need structs because we can achieve the same results using regular variables, strings and so on. You are right; however, a structure allows us to keep our data much better organized. If I would want to create another person, I would use something as simple as this:

 

PEOPLE* jenny =

{        

       age = 34;

       kids = 1;        

       name = "Jenny Bart";

}

 

Starting to feel the power of structs, aren't you? And we've just barely scratched the surface!

Take a look at the following example (structs2.c) to see what I mean:

 

aum72_workshop2

 

typedef struct {        

       char* author;

       char* title;

       long year;

       char* editor;

} BOOKS;

 

BOOKS entry[100];

 

function main()

{        

       entry[0].author = "Jimmy Page";

       entry[0].title = "Going with the wind";

       entry[0].year = 1999;

       entry[0].editor = "Mc. Miller";

 

       entry[1].author = "Jen Pages";

       entry[1].title = "All your base are belong to us";

       entry[1].year = 2000;

       entry[1].editor = "Worst Press Inc.";

 

       entry[2].author = "Johnny Stark";

       entry[2].title = "Termites all over";

       entry[2].year = 2001;

       entry[2].editor = "Best Failures Inc.";

 

       str_cpy(author1_str, entry[0].author); // these lines display the values on the panel

       str_cpy(author2_str, entry[1].author);

       str_cpy(author3_str, entry[2].author);

       str_cpy(title1_str, entry[0].title);

       str_cpy(title2_str, entry[1].title);

       str_cpy(title3_str, entry[2].title);

       year1 = entry[0].year;

       year2 = entry[1].year;

       year3 = entry[2].year;

       str_cpy(editor1_str, entry[0].editor);

       str_cpy(editor2_str, entry[1].editor);

       str_cpy(editor3_str, entry[2].editor);

}

 

I have removed the definitions for the variables and strings, as well as the panel that displays the values on the screen but all the other code inside structs2.c is here. As you can see, we define a struct type name BOOKS, and then we can create an array of BOOKS structures that contains 100 elements. This means that we can now have the information for up to 100 books in an elegant way, storing the author name, the title of the book, the year and the name of the editor. We could have done the same thing using 300 strings and 100 variables, but everything would have looked much worse, isn't it? And with all those vars, I don't even want to think about the code that allows us to search for a specific author or book...

 

Anyway, I have set the proper values for the first 3 books in order to give you an example on how to use them: the first book will be accessed using entry[0], the second book will be entry[1] and so on.

 

Ready for more pure struct power? Open and run the structs3.c file:

 

aum72_workshop3

 

var results1;

var results2;

 

STRING* team1_str = "                    "; // holds up to 20 characters

STRING* coder1_str = "                    "; // holds up to 20 characters

 

typedef struct {        

       char* name;

       long successes;

       long failures;

} PROGRAMMER;

 

typedef struct {        

       char* team_name;

       PROGRAMMER coders[10];

} TEAM;

 

TEAM abt;

 

PANEL* info_pan =

{        

       digits (20, 20, team1_str, *, 0, 0);

       digits (20, 30, coder1_str, *, 0, 0);

       digits (20, 40, "Successes: %.0f", *, 1, results1);

       digits (20, 50, "Failures: %.0f", *, 1, results2);

       flags = visible;

}

 

function main()

{        

       abt.team_name = "Alpha Betatronics";

       abt.coders[0].name = "Johnny Stamina";

       abt.coders[0].successes = 10;

       abt.coders[0].failures = 3;

 

       str_cpy(team1_str, abt.team_name); // these lines display the values on the panel

       str_cpy(coder1_str, abt.coders[0].name);

       results1 = abt.coders[0].successes;

       results2 = abt.coders[0].failures;

}

 

Take a good look at the code; you will notice that we are defining 2 structs: PROGRAMMER and TEAM. Believe it or not, a struct can include another struct in its definition, and this is exactly what has happened here. The only rule that must be remembered is this: you can't include a structure in another structure before defining it.

 

The struct named PROGRAMMER stores the information for our programmer: his / her name, the number of successes and the number of failed projects. The structure named TEAM stores the name of the team, as well as the information for up to 10 coders (10 PROGRAMMER structs).

 

We have defined a TEAM structure named abt; now we can access all its fields (team_name in our example), as well as all the fields of the included PROGRAMMER struct (name, successes, failures). Function main sets the "team_name" field, as well as all the fields for the first coder as an example.

 

That's pretty much it; you should now be able to throw away that ugly inventory code and rebuild it using structures. Oh, and don't forget to check the "Plug and play" section of the magazine if you want to see a simple database application that uses structs.