Enumeration–Indexed Arrays
One particularly useful pattern I like to use is
indexing arrays with enums.
The problem I had at one point was that I needed to initialize and
later free a series of named sprites.
I initially placed these sprites in a struct and had to access
them as struct members; this is tedious and does not lend itself to
iteration. After thinking about it, I realized that I needed a means
to convert unique names to numbers, which an enumeration does.
struct {
Sprite player;
Sprite enemy;
Sprite background;
}sprites;
// Initialize
sprites.player = LoadSprite(somedata);
sprites.enemy = LoadSprite(otherdata);
sprites.background = LoadSprite(moredata);
…
// Release
ReleaseSprite(sprites.player);
ReleaseSprite(sprites.enemy);
ReleaseSprite(sprites.background);
typedef enum {
kSprite_Player = 0,
kSprite_Enemy,
kSprite_Background,
kSprite_Count,
}kSprite;
SpriteInfo const kSpriteInfo[kSprite_Count] = {
somedata,
otherdata,
moredata
};
Sprite sprites[kSprite_Count];
// Initialize
for (int i=0; kSprite_Count > i; ++i) {
sprites[i] = LoadSprite(kSpriteInfo[i]);
}
…
// Release
for (int i=0; kSprite_Count > i; ++i) {
ReleaseSprite(sprites[i]);
}
In this case, the hard–coded example is shorter. However, the loop
version scales better and is shorter when there are more items.
Variable–Length Structures
One useful albeit quirky pattern in C are variable–length structs.
A simple example would be if you wanted to create a list of strings.
Traditionally, you would allocate memory for the node header—
then separately allocate memory for the content; with this approach
however you get both with a single memory allocation.
This could reduce fragmentation.
#include <stdlib.h>
#include <string.h>
#include <assert.h>
// Variable-Length with Pointer
typedef struct {
int somecooldata;
char *description;
}VariableStructWithPtr;
VariableStructWithPtr* VariableStructWithPtr_Init(
const int data,
const char * const comment
) {
assert(NULL != comment);
const size_t comment_len = strlen(comment);
VariableStructWithPtr * const result = (VariableStructWithPtr*) malloc(
comment_len + sizeof *result
);
if (NULL != result) {
result->somecooldata = data;
result->description = (char*) result + 1;
strcpy(result->description, comment);
}
return result;
}
// Variable-Length with Zero-Width Array
typedef struct {
int somecooldata;
char description[]; // or [0]
}VariableStructWithZeroWidthArr;
VariableStructWithZeroWidthArr* VariableStructWithZeroWidthArr_Init(
const int data,
const char * const comment
) {
assert(NULL != comment);
const size_t comment_len = strlen(comment);
VariableStructWithZeroWidthArr * const result =
(VariableStructWithZeroWidthArr*) malloc(
comment_len + sizeof *result
);
if (NULL != result) {
result->somecooldata = data;
strcpy(result->description, comment);
}
return result;
}
To create a variable–length structure, you need to allocate enough
memory for the base structure, plus extra memory for the
variable–length part. Then, you treat these nodes as pointers.
In that example, there are fields of different types
Web APIs
Web
APIs
are a kind of
API
(Application Programming Interface) that enable programmatically
interacting with services provided via web technologies.
The most basic use of a Web API is to query an online database
(in the semantic sense, just a service that stores information);
this can be extended to also modify said information and can be used
to handle user authentication, asset retrieval and really anything
that benefits from using data from the internet.
One of the most widespread used kinds of Web APIs are RESTful APIs
which use the HTTP
application layer to
transmit XML or JSON encoded
hierarchical data.
There are other kinds of Web API technologies, such as
GraphQL.
Examples
To name a few example APIs:
Some APIs will allow you to anonymously use them, for free; others
will require registring for an API key and some of those will demand
payment.
Here is an example of the Japanese–English dictionary API from Jisho:
https://jisho.org/api/v1/search/words?keyword=koi
{
"meta": {
"status": 200
},
"data": [
{
"slug": "恋",
"is_common": true,
"jlpt": [
"jlpt-n3"
],
"japanese": [
{
"word": "恋",
"reading": "こい"
}
],
"senses": [
{
"english_definitions": [
"(romantic) love"
]
}
]
}
]
}
This data is JSON–encoded, which is one of the data formats that
drive the modern web.
Born by the need to encode, store and transmit JavaScript objects,
parsers and compilers for it have been implemented in basically any
high–level programming language, and doing so is not particularly
challenging.
This data can easily be accessed in JavaScript. One can use
the .json()
method on fetch objects or directly
JSON.parse()
on the text.
Then, each key can be accessed as an attribute of the resulting
object.
For example:
data.data[0].slug + ": " + data.data[0].senses[0].english_definitions[0]
> "恋: (romantic) love"