Learning the C Programming Language as a Classical Musician

Episode 3

Welcome back!

In the last episode we looked at the structure of a C file on Xcode for macOS, while also giving a brief overview of the IDE’s user interface (UI). Today’s episode will be a bit more technical as we will delve into the basics of the C Programming Language, focussing our attention on some fundamental terminology. Let’s get started.

What is a C program?

The answer to this question is easier than what one may think, and could very well be the same for any language’s program: it is a sequence of text files containing lines of instructions called declarations. We saw this in practice in the previous episode when we say that the main.c file was nothing else than a blank page with, to start with, no more than fifteen lines of code in it. We want to avoid being presumptuous in thinking that it will always be that simple, but, in practice, as even the most complex musical composition is created with the same 12 notes, also the most complex C program is made of the same elements, just cleverly arranged together. What is happening under the hood is that the compiler is translating those declarations into machine-readable language, as the computer has no idea what our English words mean. There are programming languages that go far deeper into the system and are known as low-level languages, as they sit low next to the base. You can imagine this as a pyramid, where the ground is the Central Processing Unit (CPU)’s home, and you start to build up from there.

What is a declaration?

A declaration is a construct of the C language that introduces one or more identifiers (needed for the machine to understand what kind of data you are passing) into the program, and it is used to specify their meaning and properties to the machine. For starters, it is “one line of code” followed by a semicolon ;. It is made of three parts, the third of which is optional: a list of specifiers and qualifiers, a list of declarators and initializers, and an optional list of attribute-specific sequences. All this sounds much harder than it actually is, so let’s begin with the first one.

Specifiers and qualifiers need to be in a “whitespace-separated list”1 and, at least, they need to contain a type specifier, such as int or void. Other specifiers and qualifiers are possible (storage-class specifier, type qualifiers, function specifiers and alignment specifiers) but, at least in the beginning, we will not encounter them.

Declarators and initializers are, instead, a “comma-separated list”2 of names, for example int majorKeys, notes; where we declared two integer objects called majorKeys and notes. Each declarator may or may not be initialised, that is we may or may not give it a value, by adding an equal sign = and then a value. During my Swift learning it worked that if you had a list of declarators on one line, and then you added an initialiser to it, all objects would get the same value. It is not so in C: if I write int majorKeys, notes = 7; only notes will get a value, the compiler will throw a warning and give majorKeys a temporary default value of 1.

The attribute specific sequence is, as said, optional, and applies to all the declaration before it (we will look at an example when talking about the switch statement). Here are a few explained examples:

int a, b = 42; // "int" is the type specifier,
                    // "a" is a declarator,
                    // "b" is a declarator and 42 is its initialiser
const int c; // "int" is the type specifier,
             // "const" is the type qualifier, meaning "constant", cannot be changed
             // "c" is the declarator

A declarator—the name of the object, for starters—can assume different forms and can be increasingly complex. The following may be a bit shocking, but I will try to explain them as thoroughly and simply as possible. Take this line of code:

int a = 1, *p = NULL, f(void), (*pf)(double);

Here we have a line with four objects. The first one is simple: int is the type specifier, a is the declarator and 1 is its initialiser, providing a with a value. Now, being, on the same line, int also applies to the other objects in it. *p, to be read “star p”, is an object of type pointer to int, something we will delve into much later, but in short, it is like the address you write on a postcard for now. = NULL is its initial value, another special thing I am throwing at you to build your curiosity up! f(void) introduces us to the syntax used for functions; int is still applying to it as if we had written int f(void); by itself and it is its return type. f(void) thus is the declarator of a function taking void (that is, nothing) as parameter, and returning an integer. In Swift and more modern languages void will be substituted with, well, nothing at all! The last example is the most complex one so far: the declarator is *pf, and it is enclosed in parentheses because of the pointer syntax preceding it. This is a pointer (that is an arrow pointing to a specific address in the computer’s memory) to a function called pf that accepts a single parameter of type double (a kind of decimal number) and returns an integer.

If you find this hard, do not worry because it is. Everything will slowly set in and become clearer in time.

What is a definition?

A definition stems from the declaration itself, as it provides all information about the declared identifiers. For example, the functions we have just seen are just declarations because they do not provide any functionality at all. We need to add something in the function’s body for it to be meaningful:

void makeCompound(int beats, int value); // declaration
void makeCompound(int beats, int value) {
    int subdivisions = beats * 3, duration = value * 2;
    printf("The compound time of %d/%d is %d/%d\n", beats, value, subdivisions, duration); 
} // definition

Other concepts

Objects

The C programming language introduced, back in the 1970s when it was invented, what is known as Object-oriented Programming. This means that a C program creates, destroys, accesses and manipulates objects. An object, in C, is a specific, physical region of memory (also known as data storage) in the computer running its program. I find this fascinating as it helps us understand exactly what programming is about: you are physically writing something somewhere, creating an object, making it do things! It’s creativity! These objects usually represent values, that is, the translation of the meaning of what the object itself contains. To translate it, we need an interpreter, and that is typically the object’s type.

Every object has several characteristics: a size, which is how many bytes it is occupying physically in memory3, a storage duration, that is, how long it is persisting in memory before being destroyed, a lifetime, very similar to the previous, an effective type, which often is equal to its type specifier, and a value, which may be indeterminate (for example if we have not yet initialised the object).

Scope

We will look at other kinds of objects such as functions, structs, unions or enumerations, later, but this little last bit is essential, and I want to cover it now. Imagine you have a concert with your string quartet: if you enter the correct room for the rehearsal, dressed properly, and have the right score with you, everything will go well. If, instead, you bring the score for tomorrow’s concert with the local wind band, wear a swimming costume and go to the wrong building, things may get, embarrassing. What do I want to show with this example? That everything has a scope, that is an environment within which what you are about to do or perform is at its best. In programming, this means that if you declare an integer outside a function and then expect to use it inside that same function declaring another integer of the same name, it will not work as you may expect. Let’s look at this example:

int main(int argc, const char * argv[]) {
    int a, b = 42; 
	const int c = 26; 
    
    a = 13; // initialising a
    printf("a is %d, b is %d, and c is %d\n", a, b, c); // reading into the scope of the `main` function
    
	// This is a for-loop, declares an integer a with a value of 0, will run until a < 10 is true, and add 1 to a after every loop
    for (int a = 0; a < 10; a++) {
        printf("a is %d\n", a); // reading into this loop's scope
    }
    
    printf("a is still %d\n", a); // the integer called a outside of the loop is unchanged
    
    return 0;
}

What’s next?

This is everything basic I think you should know to start learning C. We will go back time and again with each of these concepts until they are well-rooted into our brains.

Next time we will look at how to add comments to your code, at a basic introduction to characters and the ASCII Chart and possibly at what is happening to our C file when the IDE compiles it.

Bottom Line

Thank you for reading today’s article.

If you have any question or suggestion, please leave a comment below or contact me using the dedicated contact form. Assuming you do not already do so, please subscribe to my newsletter on Gumroad, to receive exclusive discounts and free products.

I hope you found this article helpful, if you did, please like it and share it with your friends and peers. Don’t forget to follow me on this blog and to let me know what you think.

If you are interested in my music engraving services and publications don’t forget to visit my Facebook page and the pages where I publish my scores (Gumroad, SheetMusicPlus, ScoreExchange and on Apple Books).

You can also support me by buying Paul Hudson’s Swift programming books from this Affiliate Link or BigMountainStudio’s books from this Affiliate Link.

Thank you so much for reading!

Until the next one, this is Michele, the Music Designer.

  1. That is: <element1> <element2> <element3> and so on, on the same line, separated by a space.
  2. That is: <element1>, <element2>, <element3> and so on, normally on the same line. If on different lines a semicolon needs to be used to end the first line and the type specifier needs to be used again on the following line.
  3. I am willingly stressing on the “physical” concept because it would be a fatal mistake to think that what we create in programming could be something ethereal.

Published by Michele Galvagno

Professional Musical Scores Designer and Engraver Graduated Classical Musician (cello) and Teacher Tech Enthusiast and Apprentice iOS / macOS Developer Grafico di Partiture Musicali Professionista Musicista classico diplomato (violoncello) ed insegnante Appassionato di tecnologia ed apprendista Sviluppatore iOS / macOS

3 thoughts on “Learning the C Programming Language as a Classical Musician

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: