Bonus Episode (after Ep. 15) — Recap of what we have learned so far
Welcome back!
More than one month has passed since my last episode. I have been unable to study, practice, and write anything concerning programming due to impending assignments in my music notation work. If you follow this blog you will have noticed how I have been far from silent, yet, I could not continue this series with the same regularity.
Now, before moving on with Episode 16 on C’s structures, I want to take a look back at what we learned so far, as it will help us catch up and get ready for the next step.
Let’s go!
Episode 1: Xcode p1
In the first episode of this series, we looked at the tools we would be using throughout our journey: a Mac, and Xcode. In it, most would be done in a Command Line Tool, selecting C as its language. I have been storing all the projects of this learning path here on GitHub, feel free to access them.
Episode 2: Xcode p2
In the second episode, we looked at Xcode’s UI: Navigators to the left, Inspectors to the right, and the Editor area in the center. A Debug area will expand from below to show our program’s output.
We learned that a comment is something that the IDE will not run and is introduced (in its basic form) by a double forward slash //
(or shortcut Cmd-Shift-7.
At the top of the file, we usually have one or more #include
to import functionalities into the program from files we create, or that macOS gives us. Then, the main
function is what governs the whole program. We gave a passing glance at what a function is, creating an example to change a simple time into a compound time (e.g., 2/4 into 6/8). An important takeaway is that parameters are in the function definition, while they are called arguments when a function is called.
Episode 3: a C program
In the third episode, we dived into what a C program is. It is a list of declarations, made up of one of more identifiers (lines of code). Each of these have specifiers/qualifiers, declarators/initializers, and, optionally, an attribute specific sequence. The greatest takeaway here is that declarators/initialisers are just the names of objects. For example, my first name, Michele, is my declarator, my initialiser! If you think of it, when you are born, you are “initialised” with a name!
We introduced the concept of object-oriented programming, and that every object has a size, a duration and/or lifetime, and a value. Finally, we dipped our toes into the concept of scope, possibly one of the most important things to grasp at this stage.
Episode 4: comments
The fourth episode was dedicated to comments, both C++ style, introduced by //
, and C style, introduce and closed by /* */
. Xcode has some special comments, such as: // MARK: - Section name
, // FIXME: -
, // TODO: -
, and #warning:
.
We then touched the surface of the ASCII standard, seeing how text is actually represented by numbers (or our computers would not be able to tell it apart). Finally, we met the %c
conversion specifiers, variadic functions (functions that can accept an indefinite number > 1 of arguments), the ternary conditional operator (i % 2 == 0 ? Y : N)
, and the modulo operator (a % b).
Episode 5: phases of translation
This episode was tough, in which we looked at the phases of translation, that is what happens when we compile our code. The most interesting phase to me is Phase 4, the preprocessor stage, where all files are reduced to single symbols that contain all that rich meaning at their inside!
Episode 6: identifiers & scope
In the sixth episode we delved deeply into identifiers, how objects are called, and scope, the context in which what we are using is accessible.
Episode 7: lifetime
In episode seven, we finally discussed lifetime, or how objects persist in memory before getting destroyed (recycled!). The concept of memory allocation is paramount here! We learned that 1 byte is made of 8 bits, and that an integer is 4 bytes long (usually!).
Takeaways:
- Objects have a fixed lifetime, and ordinarily this is predefined by the programming language itself
- Typically, we do not have to worry about allocating and deallocating memory, but we must be aware of objects existing in a precise time and space frame.
Episode 8: namespaces
Episode eight introduced to us the concept of namespaces, a fancy term for object categories in C. There are six of them: label (case:
or default:
in a switch
statement), tag (struct
for structures, union
for unions, and enum
for enumerations), member (that is, inside the same object), attribute (which will become standard not before 2023), which is made of two possible specifiers [[...]]
and ::
, and the global namespace which collects everything else.
Episode 9: types
In episode nine, we started the long and ongoing series on C types, that is, the kinds of objects we can encounter in our code. Types are classified into four branches: void
, basic types, enumerated types, and derived types.
Basic types are dividid into characters, integers (signed or unsigned), and floating-point types. Enumerated types are just enum
s. Derived types are arrays, structures, unions, functions, pointers, and atomic types.
Episode 10: compatible & composite types
In this episode, we looked at compatible and composite types. In short, compatible types are either the same type or very close to that, while composite types are created from two or more compatible types. It was a more theoretical than practical lesson.
Episode 11: Boolean, logical operators & characters
In Episode 11, we finally left theory behind to delve into practical example, starting with arithmetic types. First, a Boolean type is the computer representation of the true
and false
value. Then, logical operators are fundamentals to make code work afterwards:
- The logical and operator is written as two ampersand characters, one next to the other
&&
and returnstrue
if both the statement to its left and the one to its right evaluate astrue
. - The logical or operator is written as two pipe characters
||
. This expression will evaluate totrue
if either of the two statements around it istrue
.
Another important thing is the meaning of the single equal sign =
, called the assignment operator, as it assigns the value to the right of it to the object position to the left of it, effectively storing it inside the object.
Finally, we faced characters and the fact of them being just numbers disguised.
Episode 12: Integers, conversion specifiers, and non-decimal numbers
In Episode 12, we continued our tour of arithmetic types, looking at integers, finally with some examples. My favourite part of this lesson was the conversion exercise between decimal and binary, octal, and hexadecimal!
Episode 13: floating-point types
This episode was completely devoted to floating-point (or fractional) numbers and to their application in C. I did not have the courage—nor the knowledge—to venture into complex and imaginary numbers, as it is really is not my field.
Episode 14: enumerated types
Episode 14 made us plunge into the world of enumerated types, that is, a common ground for a group of related values that will be stored as integers. We finally had the possibility of relating this type to the musical language, as notes are just a list of “related values” ordered according to a convention.
Episode 15: arrays
In this episode, the last of our review before finally progressing into uncharted territory, we attacked derived types, starting with arrays. An array is made of a sequence of objects of the same type, doesn’t change size, and starts counting from 0
. A most fascinating aspect of arrays in C is how one can declare their size in multiple ways, using integers, sizeof()
functions, text strings. They are so powerful!
Conversion specifiers
Before moving on to the next episode, I want to compile a list of conversion specifiers, as this is possibly the thing I have spent the most time on when looking for information. Excerpts from the official C documentation are included beside each example. Extremely difficult parts are added in footnotes for completeness.
%c
: character. Supportschar
andunsigned char
. Writes a single character. The argument is first converted tounsigned char
1.%s
: string. Supportschar *
. Writes a character string. The argument must be a pointer to the initial element of an array of characters. Precision specifies the maximum number of bytes to be written. If Precision is not specified, writes every byte up to and not including the first null terminator2.%d
or%i
: signed integer. Supportsshort
,unsigned short
,int
,long
. Converts a signed integer into decimal representation-dddd
3.%o
: octal representation of integer. Supportsshort
,unsigned short
,int
,unsigned int
,long
. Converts an unsigned integer into octal representationoooo
4.%x
or%X
: hexadecimal representation of unsigned integer. Supportsshort
,unsigned short
,int
,unsigned int
,long
. Converts an unsigned integer into hexadecimal representationhhhh
. For thex
conversion, lettersabcdef
are used. For theX
conversion, lettersABCDEF
are used5.%u
,%lu
,%hu
,%llu
. Unsigned integer. Supports, respectivelyunsigned int
andunsigned long
,unsigned int
andunsigned long
,unsigned short
,unsigned long long
6.%f
: floating point. Supportsfloat
. Converts floating-point number to the decimal notation in the style-ddd.ddd
7.%e
or%E
(also possible as%g
or%G
): scientific notation of float values. Supportsfloat
anddouble
. Converts floating-point number to the decimal exponent notation. For thee
conversion style-d.ddde±dd
is used. For theE
conversion style-d.dddE±dd
is used8.%g
or%G
: another possibility for scientific notation of float values9.%a
or%A
: converts floating-point number to the hexadecimal exponent notation. For thea
conversion style-0xh.hhhp±d
is used. For theA
conversion style-0Xh.hhhP±d
is used10.%hi
: signed integer (short). Supportsshort
.%l
,%ld
, or%li
: signed integer. Supportslong
.%lf
: floating point. Supportsdouble
.%Lf
(notice the uppercaseL
): floating point. Supportslong double
.%lli
or%lld
: signed integer. Supportslong long
.%p
: address of pointer. Writes an implementation defined character sequence defining a pointer.%n
: returns the number of characters written so far by this call to the function. The result is written to the value pointed to by the argument. The specification may not contain any flag, field width, or precision.
What’s next?
In the next episode, we will look at the next derived type in the series: structures! See you then!
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.
- If the
l
modifier is used, the argument is first converted to a character string as if by%ls
with awchar_t[2]
argument. ↩ - If the
l
specifier is used, the argument must be a pointer to the initial element of an array ofwchar_t
, which is converted tochar array
as if by a call towcrtomb
with zero-initialized conversion state. ↩ - Precision specifies the minimum number of digits to appear. The default precision is
1.
If both the converted value and the precision are 0 the conversion results in no characters. ↩ - Precision specifies the minimum number of digits to appear. The default precision is
1
. If both the converted value and the precision are0
the conversion results in no characters. In the alternative implementation precision is increased if necessary, to write one leading zero. In that case if both the converted value and the precision are 0
, single0
is written. ↩ - Precision specifies the minimum number of digits to appear. The default precision is
1
. If both the converted value and the precision are 0
the conversion results in no characters. In the alternative implementation 0x or 0X is prefixed to results if the converted value is nonzero. ↩ - Converts an unsigned integer into decimal representation
dddd
.
Precision specifies the minimum number of digits to appear. The default precision is1
. If both the converted value and the precision are 0 the conversion results in no characters.
↩ - Precision specifies the exact number of digits to appear after the decimal point character. The default precision is
6
. In the alternative implementation decimal point character is written even if no digits follow it. ↩ - The exponent contains at least two digits, more digits are used only if necessary. If the value is
0
, the exponent is also 0
. Precision specifies the exact number of digits to appear after the decimal point character. The default precision is6
. In the alternative implementation decimal point character is written even if no digits follow it. ↩ - Converts floating-point number to decimal or decimal exponent notation depending on the value and the precision.
For theg
conversion style conversion with stylee
orf
will be performed.
For theG
conversion style conversion with styleE
orF
will be performed.
LetP
equal the precision if nonzero,6
if the precision is not specified, or1
if the precision is 0
. Then, if a conversion with styleE
would have an exponent ofX
:
– ifP > X ≥ −4
, the conversion is with stylef
orF
and precisionP − 1 − X
.
Otherwise, the conversion is with stylee
orE
and precisionP − 1
.
Unless alternative representation is requested the trailing zeros are removed, also the decimal point character is removed if no fractional part is left. ↩ - The first hexadecimal digit is not
0
if the argument is a normalised floating point value. If the value is 0
, the exponent is also0
. Precision specifies the exact number of digits to appear after the hexadecimal point character. The default precision is sufficient for exact representation of the value. In the alternative implementation decimal point character is written even if no digits follow it. ↩