Introduction to the C Programming Language
Laboratory Scripts
Dr. Adar Pelah
Dr. Julian Miller original author with
Dr. Andy Hunt, Dr. Peter Mendham, Dr. Andy Pomfret, Dr. Steve Smith,
Dimitrios Zantalis, Amir Dehsarvi and Tautvydas Mickus
September, 2016
Introduction to the C Programming Language Revision 5.1
Contents
Function Reference
Syntax Reference
iv Introduction to the C Programming Language Revision 5.1
Introduction Overview
This section gives a brief introduction to the structure of the C Programming Laboratory course, and the way in which these scripts are written.
The Structure of the Lab Course
There is a C programming laboratory once a week, every week from 2 to 10, in the Autumn term. There is a laboratory script for each lab in the Spring term. The course is assessed via a programming assignment and a written report submitted electronically. The assignment period begins at the end of the taught component of the course.
There are some labs that are in the appendix. These will not be covered in the allocated lab sessions, but nevertheless they are important and should be studied and used when appropriate, especially in assignments.
You can work through each lab at your own pace, however, you will be expected to complete one labo ratorys script before the beginning of the next lab. If you have not finished a script by the end of a lab you may have to complete it in your own time.
Each lab contains two optional sections:
music option, intended for Music Technology students; graphics option, intended for all other students.
You must choose one of these options. If you have time, it is strongly suggested that you attempt parts of the other option. The C programming course is assessed through one assignment. The assignment will be handed out towards the end of term. For each assignment there will also be two options: music and graphics. If you have managed to learn techniques from the other option it will make your assignments all the more impressive!
How These Scripts are Written: Structure and Conventions
These scripts are intended to be worked through in order, however, some sections are highlighted to make it easier for you to refer back to important information later in the course. The normal text of the script will contain both information and instructions for the tasks you should carry out. You must make sure you read the scripts carefully, especially before asking for help you may have missed something important.
Sections where you need to think carefully about what you are doing are shown as exercises and appear like this:
2 Introduction to the C Programming Language Revision 5.1
Exercise 0.1: An Example Exercise
Exercises appear in boxes like this one.
Sometimes you need to do something but the instructions are not given in an exercise box. Usually this is because the action you need to carry out is fairly simple. To make sure these parts of the lab script are easy to find, they have a picture of two gears next to them in the margin.
Like this.
There are two other kinds of special box:
syntax boxes which tell you information about how to form valid statements in the C language; syntax boxes look like this:
Syntax: Some Syntax
the syntax goes here…
. . . and the description of the syntax goes here.
function boxes which tell you how to use C language functions; function boxes look very similar to syntax boxes:
FunctionReference:A Functionwhichdoessomething the function goes here…
. . . and the description of the function goes here.
Dont worry that you dont know what a function is yet this will become clear when you start the first lab!
The descriptions of both syntax and functions use some special symbols. You should try and remember what these mean, ready for when you meet your first syntax or function box:
if something appears in square brackets, like this , then it means that it is optional;
ifsomethingappearsinsquarebracketswithasmallnaboveandtotherightofit,like thisn,
then it means that it is optional and can be repeated as many times as you want;
Dont worry if this does not seem clear now, just remember that when you meet the first syntax or function box you can look back at this section to help you understand the information.
Part I Laboratories
Laboratory 1
Simple C Programs in Code::Blocks
1.1 Developing C programs
In order to write programs in C or Java etc. we need some tools, system tools that is, that help us accomplish this. In particular we need a compiler, a linker, a debugger and an Integrated Development Environment or IDE to aid with the development process.
An IDE combines things that, many years ago, used to be separate. They are:
an editor which allows you to edit the text files that contain the C language which will become
your program these are often known as source files;
a compiler which takes a source files and translates it from text in the C language to machine code which the computer can understand and execute. All programs on your computer are in machine code;
alinkerwhichtakesoneormorecompiledfilesobjectfilesgeneratedbyacompilerandcombines them into a single executable program;
a debugger which allows you to test out your programs in a very controlled way and diagnose problems with them.
To read more about these topics in more detail you could follow the links below reading the introduc tion of each article should suffice:
Compiler: http:en.wikipedia.orgwikiCompiler
Linker: http:en.wikipedia.orgwikiLinkercomputing
Debugger: http:en.wikipedia.orgwikiDebugger
IDE: http:en.wikipedia.orgwikiIntegrateddevelopmentenvironment
1.2 Code::Blocks and MinGW
In this first laboratory you will be introduced to the programming tools we will use on the C program ming course. All the tools that we use for Windows OS are free and open source. This means that you will be able to install them on your own computers with no cost.
To write your C programs you will use two pieces of software in addition to libraries for doing graphics and music MIDI more on this later. The first is called MinGW which stands forMinimalist GNU for Window. This is a C programming development environment and includes the GNU C compiler. The second is an integrated development environment IDE called Code::Blocks. Further information about these is available through the following URLs:
6 Introduction to the C Programming Language Revision 5.1 MinGW http:www.mingw.org
Code::Blocks http:www.codeblocks.orghome
There are more system tools that are used when developing applications such as assemblers, archivers etc. but the aforementioned ones are all we need for completing this course. The idea is to write cross platform code i.e. code that is system independent. You only have to write your code once and you can compile it on different operating systems without any modifications. The C language is ideal for such kind of programming; compilers exists for all major operating systems Windows, Linux, OSX.
1.3 Starting to write C programs
In the first C lab you will be introduced to the following concepts:
the structure of a simple C program; variables, their names and types;
how to do simple mathematics in C; how to call functions;
how to use the printf function.
You should understand all of these concepts by the end of the lab. You will also have been introduced
to the graphics and music libraries.
1.4 Introducing the IDE
The Code::Blocks GUI comprises all the main features of an IDE. It looks something like this:
Locate Code::Blocks on your computer. This can be found by going to the Start icon on your Win dows taskbar, then select All Programs and look for Programming Tools. Select Code::Blocks and you should see something like the image shown in figure above.
On the top of the window we see the familiar menu bar which has all available options for the software.
Below we see various toolbars. Make sure that the compiler toolbar is visible. If not sure go to View Toolbars and make sure that the Compiler option is checked. The compiler toolbar has important functions that we need to select, compile and run our programs. These functions can also be selected through the Build menu.
On the left of the window we see the Management panel. From here we manage our project and all related files.
Themiddlepartofthescreenissplitintotwopanels.Thetoppaneliscurrentlydisplayingthestart panel for Code::Blocks, however this panel will display the text editor when a file is openselected. The bottom panel, Logs others comprises various tabs each containing important information about the output of various operations. An important tab is Build messages which outputs the state of the compilation process all errors will be displayed here.
Revision 5.1 Introduction to the C Programming Language 7 1.5 Creating a Project
In Code::Blocks the highest level of organization is a Workspace, which can contain a number of Projects. Projects are collections of software components. There may be dependencies between these projects. For instance projects may contain a collection of useful software components that are used by a number of other projects. The information about which projects depend on which others is stored in the workspace.
1. Now we are going to create a project. There are two ways of doing this. If Code::Blocks has just been started you can just click on the link Create new project or alternatively you can go to the menu bar and select File New Project.
2. Select Empty Project and press Go.
3. Enter a title for your project Do not use spaces when naming a project. A suggestion for this is helloworld.
4. Choose the folder to create the project in. Please note that Code:Blocks will automatically create a folder with the same name as your project name, in which all related files will be placed.
5. Make sure that the resulting filename has the desired name and location. Press Next.
6. Make sure your selected complier is GNU GCC Compiler.
7. Make sure the Create Debug and Release configuration boxes are ticked.
8. Leave all other options set to their default values. Press Finish. In a few moments you will see an icon appear in the Management panel with the name you gave your project.
9. Click on File New Empty File.
10. Add this new file to the active project Choose Yes to the message box.
11. Enter an appropriate file name e.g. main.c, helloworld.c for example. Use the .c extension to inform the compiler that this is a C program and not C which has extension .cpp.
12. This file should belong to both the Debug and Release versions of the software. So make sure that the Debug and Release boxes are ticked. Press OK.
13. Now in the Manager panel, in the Projects tab if you expand your project tree you should see the new file that you just created. The file should also be visible in the editor panel top half of the middle area of the GUI. If it is not then double click on the source file i.e. main.c or helloworld.c.
1.6 Targets
In projects it is often necessary to have different variants of the project available. Variants are called Build Targets1. They differ with respect to their compiler options, debug information andor choice of files.
When creating a project in the previous section of this guide we checked some boxes labeled Debug and Release. Usually when software is developed, two versions of the program are created: a Debug and a Release version the Debug and Release targets. The Debug version is the one that is used for the main development of the program and contains important debug information often called debug symbols which is helpful when testing the program. For further information you might like to read:
http:en.wikipedia.orgwikiDebugsymbol
1For further information go to Help CodeBlocks and read section 1.4 Create projects from Build Targets
8 Introduction to the C Programming Language Revision 5.1 The Release version of the software is the one that is given to the end user and has all debug symbols
stripped out. This means that it will run much quicker.
So projects in Code::Blocks can comprise many different targets. Each target can have its own settings and its own files. This gives us the ability to have many different programs targets inside one project and keep all related files source files, header files etc. conveniently organised. This idea is fundamental to the creation of the clab project that we will be using for the much of this course. For now let us focus on our newly created project and the two different versions of it that we can create Debug and Release.
1.7 Writing Code, Compiling and Running the Program
1. Make sure your main program file is open in the text editor and type in the following lines:
include stdio.h
int main void
printfHello Worldn;
return 0;
2. Now in the compiler toolbar make sure the selected target is Debug and hit the Build and run button. Look in the Logs others panel in the Build log tab as the compilation process executes.
3. Everythingshouldcompilefineandacommandwindowwillpopupdisplayingtheoutputofour program: Hello World. Below that there is an empty line and then some information about the process our program running on the OS and the execution time.
4. Press any key to close the command window and return to Code::Blocks.
5. NotethattheinformationthatwegetinthecommandwindowisalsodisplayedintheBuildlog tab.
6. Now repeat the process but this time choose Release as your target.
Now close the Code::Blocks IDE.
At this stage we have compiled two different versions of our program; a debug and a release version. Open windows explorer and navigate to the location of your project. Inside your project folder there is a folder called bin short for binaries and inside that folder there are two folders named Debug and Release; each contains the corresponding target. Both targets are files with a name that is the name of your project e.g. helloworld and the extension .exe. These files are executable they are machine code and you can run them. There are a couple of ways of doing this.
1. You can double click the file icon. If you try this you will, very briefly, see a small back window appear like the one that opened when you chose Build and run in the Code::Blocks IDE.
2. The other way to run your executable is to use a MS OS tool called Command Prompt. To locate this tool you need to go to the Start tab on the Windows taskbar at the bottom of your screen. Select All Programs and then choose Accessories. You should see Command Prompt on the list a small black icon. Select this and a black window will open.
The Command Prompt should look something like this:
In this example the Command prompt window shows the path:
Revision 5.1 Introduction to the C Programming Language 9 C:Usersjfm7
When you do this it will show a path corresponding to the computer you are using now. You need to navigate to the folder where the executable program is located. The simplest way to do this is to go back to windows explorer window that shows your executable program and copy the path to it. This can be done by clicking in the top menu box this shows the path and selecting CTRL C which will copy the path. Now in the Command prompt window, type cd followed by a space and right click and select Paste. This will fill in the path after the cd. Now press Return and now the Command Prompt will be ready to run the program. Type the name of your program e.g. helloworld you dont need to type the extension .exe and then press return. Now you will see the message Hello world and the window does not disappear!
This procedure may seem tedious but actually this is often how programmers run their C program executable files. If you want to give a friend a program you have written assuming they are going to run it on a computer using the same operating system type i.e. Windows, you can give them the .exe file and they should be able to run it. Note that sometimes when you do this the computer will complain it cannot find a .dll file, in which case just find it on the internet and copy it to the folder where the executable is. So, once you have the .exe file you do not need the IDE, you have a standalone file that can be run, so your friend would not need a C compiler or the Code::Blocks IDE. This is important to remember.
10 Introduction to the C Programming Language Revision 5.1 1.8 Using the clab Code::Blocks Project
In the previous sections we went through the process of creating a new project containing only one source file and no other dependencies. The exercises in this course and the program you are going to develop as your final assignment, comprise more than one file and depend on third party libraries allegro and portmidi in particular with which we have to link. Because the process of setting up a project using these libraries is lengthy and essentially the same for each project that contains these libraries we have created a ready made project for you, called clab, that contains all necessary files source files, header files, libraries, resource files, documentation for completing the exercises of this course. It is recommended to use this project for creating your own programs too. Doing this will keep all files organised and will eliminate the need to create and set up a new Code::Blocks project every time you want to write a new program. Another advantage of having a single project with multiple targets is that you can just copy the main project folder anywhere and you are sure that all your work is copied and nothing is left behind. So for example you could run this project from a USB drive that you always carry around and use it on different machines assuming that Code::Blocks and MinGW are installed and properly set up on the machine that you run the project.
If you later want to create a separate project for any of the programs you can always do that by creating a project from a target; this is discussed in an appendix on the Code::Blocks IDE.
1.9
Getting the clab Project
Go to the Electronics Department internal web pages. Locate DSE below Information for Taught postgraduates and click it . Then click on Modules. Then click on the link to C Programming for MSc . If you scroll down the page to the section Code::Blocks project required for Lab ex ercises just below that you will see CLab code for Windows available. Click on this link and choose Save As. Save the file clab.zip to the Department of Electronics network drive called M: It should be visible on the lefthand side of the Save As window. Now right click on the file clab.zip and choose Extract All…. Once the unzipping process has finished you should have a folder:
M:clab
1.10 Examining the contents of the clab folder
Using windows explorer, navigate to the clab folder and have a look inside. You should see the following a list of folders which includes the following:
bin folder : This folder contains all compiled executables. This is where the executable programs are created.
include folder: This folder contains the allegro, portmidi library header files and the wrapper files graphics lib.h, amio lib.h.
lib folder: This folder contains the allegro and audiomidi libraries .a and .dll files.
obj folder: This folder contains the object files that are produced after the compilation process. This is of no interest to us at the moment.
.objs folder: This folder contains more object files
src folder: This folder contains all the source code files. For the exercises each file corresponds to a different program target, so each file contains a main function. Your program might contain more than one source file. We will see how to add multiple files to a target later on.
data folder: This folder contains files that the allegro graphics uses to define the fonts that can be used when writing text output to the graphics window.
clab.cbp file: This is the Code::Blocks project file.
Revision 5.1 Introduction to the C Programming Language 11 When writing your program you will be adding files to the include and src folders. This is a typical
folder structure in open source software and is a convenient way to organise your files.
Often there are a few other files that are related to the project e.g. clab.depend and clab.layout which need not concern us at this point.
1.11 Settings of the clab project
The clab project has been set up in such a way so that the allegro, portaudio and portmidi libraries are included and are available for all targets programs that need them. So you dont have to download anything extra or perform any more set up steps to use these two libraries. Everything is there and ready for you to use. Each exercise of this course is a different target, with its own settings and corresponding source files. All you have to do is pretty much select your target, compile and run. Of course the source code must be complete in order for the compilation process to succeed; but completing the exercises is your job. Sometimes a complete working source file will be given and you have to expand on it by writing more code. Just follow the individual lab scripts. Before doing any programming we should take a look inside the clab project and see how things are set up. Understanding and getting comfortable with the project settings is important as you have to create your own targets later on in the course.
Start the Code::Blocks IDE from the Start menu on the far left hand side of the Windows taskbar. You will see a window in the centre of the Code::Blocks IDE entitled File associations. Just click OK. This will automatically associate C programs and other files with the Code::Blocks IDE. Now click on Open an existing project. A window entitle Open file will appear. You will see a file called clab.cbp with a Code::Bocks icon next to it. Left click on the file and then left click on Open. You will see three window panels. The left panel is called the Management panel and it shows you a clab icon and two subfolders called Sources and Headers. The Sources folder contains all necessary source files for completing this course.
1.12 Building your target
Having covered the basics of our development tools, we can continue with the process of building our programs. The building process consists of several stages. To understand this process better you could consult:
http:en.wikipedia.orgwikiSoftwarebuild
Now focus on the Management tab and click on the symbol by the folder Sources. You will see a list of C programs in the src folder. Double click on the file graphics1.c. The IDE will open an editing window and show you the program, the first line of which is
please delete this line
Go ahead and delete this line. Click on the save file icon.
Now look for the green triangle like an arrow on Compiler toolbar in Code::Blocks. Near it you will see a dropdown menu. Click on this and select graphics1. This dropdown menu lists all the targets. This is how you select what program you want to compile and run.
Now you can try to build the program associated with the C source code file graphics1.c. Building means invoking the compiler which translates your C program in this case graphics1.c into the machine code program that runs on the processor chip inside the computer. To start the build process first locate the yellow gear button on the compiler toolbar and then click on it. Watch the output of the build log during the build process. In the build log we see that the build process first goes through compilation stage, then linking stage and finally reports the output size of the executable. The two blue lines report the status of the terminated process and time of execution followed by the number of errors and warnings which should be zero in this case.
Now using Windows Explorer navigate to clabbinDebug and you should see the file graph ics1.exe. The file is the product of the build process and its name is taken from the corresponding
12 Introduction to the C Programming Language Revision 5.1 option in the build targets tab in the projecttargets option window output filename setting. You could
run this program by double clicking the file. But dont do it just yet; we will run it through Code::Blocks.
1.13 Running the program
Focus again on the compiler toolbar and now execute the run command green triangular play but ton. The application should run and you are presented with a couple of windows. One is the black command run window like Command prompt, the other is a graphics window that the program opened. It will show a small red circle.
Make the command run window active by clicking on the top menu bar and then type return. The graphics window will disappear.
Press any key to close the command window when you finish 2
The third icon in the compiler toolbar runs the two steps above together in succession. All the commands found in the compiler toolbar can also be run through the build menu item of Code::Blocks.
1.14 Looking in more detail at a C Program
If you havent already done so close any program that is currently open i.e. close the editing window.
Double click on the icon for the source file lab1.c. The C language source code will appear in the editor window.
Select lab1 as the target in the Build target dropdown menu on the Code::Block menu bar.
The source code for this program is shown below. This is the same as the code in the lab1 project.
C Programming laboratory 1
The main function the program starts executing here
int mainvoid
Declare some variables for the calculations
int distancetotokyo, distancetoairport;
int speedofplane, speedofcar;
int timetofly, timetodrive, timetotokyo;
int averagespeed;
Set the values of some of the variables
Set distances in kilometres
distancetotokyo 9720;
distancetoairport 120;
Set speeds in kilometres per hour
speedofplane 1200;
speedofcar 100;
Calculate time taken to get to Tokyo
2If you dont want to close the command window by pressing a key every time you exit your application then you will need to change the settings.
A program to demonstrate simple mathematical operations
Revision 5.1 Introduction to the C Programming Language 13 timetofly distancetotokyo distancetoairport speedofplane;
timetodrive distancetoairport speedofcar;
timetotokyo timetofly timetodrive;
Calculate the average speed
averagespeed distancetotokyo timetotokyo;
return 0;
We will now go through this code, a line or two at a time. Make sure that you understand it before continuing.
The first important thing to notice is that everything between and is a comment. This means that it is ignored.
Syntax: Comments
…
Comments are used for adding text to a source file which will be ignored by the compiler. This is very useful for adding notes which will remind you about what a particular part of your program is supposed to do. In Code::Blocks when you type a comment the editor will understand and colour it grey. The different colour helps you see easily which parts of your program are comments are which are not.
It is good programming practice to comment your programs well. A good rule of thumb when writing comments is to write them for someone who understands C but doesnt understand how your program works.
The program begins with the line:
int mainvoid
ThisstatesthatalloftheCcodebetweenthetwobracesorcurlybrackets, … ,ispartofafunction called main. Every C program has a main function, which is the place where the program starts execut ing. At the moment, the main function is the only function in this program. Later on in the lab you will use, or call, some other functions that are often used in C. In laboratory 5 you will learn to create your own functions.
The next part of the program lists the variables we are going to use in this function:
int distancetotokyo, distancetoairport;
int speedofplane, speedofcar;
int timetofly, timetodrive, timetotokyo;
int averagespeed;
Variables are used in programs in much the same way that x, y and z for example are used in algebra, to represent values. The computer needs us to tell it what variables we will be using before we use them. To do that we need to tell it what the variable is called and what kind of information it will hold. This is called the variable type. In C terminology we declare the variable and its type.
14 Introduction to the C Programming Language Revision 5.1
Syntax: Variable Declarations
type name , name n ; e.g.
int anintegervariable;
double arealvariable;
int oneintvariable, anotherintvariable;
Variables are placeholders for values, just like in algebra. In C you must declare a variable before you can use it. To declare it you must give it a name and a type. The types you will use the most in C are:
int for integer numbers, both positive and negative such as 500, 2 and 20;
char for single characters, such as d and !;
double for decimal or real numbers, both positive and negative, such as 0.05, 3.141 and 2.718.
Variable names can be as short as a single letter or very long indeed. It helps to give variables descriptive names to help you remember what they are for. A variable name, or identifier, can contain any of the following characters:
upper and lower case letters, az, AZ; the digits 09;
the underscore character .
Variable names may not start with a digit. Variable names are case sensitive, that is, upper and lower case letters are treated as being different.
Some examples of valid variable names are:
distance to tokyo i
anotherCounter
Some examples of invalid variable names are
2me2you it starts with a number
dot.dot it contains an invalid character
Notice that there is a semicolon ; at the end of the line. Every C program is split into statements in a very similar way that English is split into sentences. Every sentence in English ends with a full stop or period. Every statement in C ends with a semicolon.
The next two lines of code are:
distancetotokyo 9720;
distancetoairport 120;
A statement of this type is called an assignment. It copies whatever is on the righthand side of the equals sign to whatever is on the lefthand side. In other words, the variable on the left is assigned the value on the right. The item on the lefthand side must be a variable. An assignment is very different to the
Revision 5.1 Introduction to the C Programming Language 15
way an equals sign is used in mathematics. An equals sign in maths declares a relationship between the left and the righthand sides e.g. x y z in maths tells you that x y must be equivalent to z. The equals sign in C copies information. The first line of code above copies the value 9720 into the variable distance to tokyo. You might like to think of the sign in C as meaning becomes equal to, so x 3; would be read as x becomes equal to 3 or even set x to 3.
This means you can write statements which make a lot of sense in C, but no sense in maths, such as:
someCounter someCounter 1;
Which means that the variable someCounter will be one greater in value after this line than it was before. Because you take the value of someCounter, add one to it and copy the result back into someCounter.
The next few lines carry out some mathematical operations. All the lines that do maths are also assign ments. They carry out a calculation and assign the result to a variable. For example the line:
timetodrive distancetoairport speedofcar;
takes whatever the value of the variable distance to airport is, it then divides is by whatever the value of the variable speed of car is and copies the result into the variable
time to drive.
Syntax: Mathematical Operators
The example source code lab1.c contains a few of the mathematical operators that C supports. The standard ones are:
addition;
subtraction;
multiplication; division.
When there are multiple operators on a line some basic rules are followed: operators are looked at by the C compiler from righttoleft and a special order is followed. This order is known as operator precedence and means that multiply and divide are considered more important than add and subtract. For example
642
gives a result of 8. This is the same as the way that they are used in mathematics. Quite often, when you want to clarify what you mean, you can use parentheses brackets, and , for this purpose. For example
6 4 2
gives a result of 5.
The last line of the main function, before the closing brace is: return 0;
16 Introduction to the C Programming Language Revision 5.1
This stops the computer from executing any more of the main function, and, because the main function was the first function to run, there is nothing to run afterwards. So the program ends. The value 0 is called a return value. We will see a little more about this later in this lab, and a lot more about it when you come to write your own functions other than main.
Exercise 1.1: Understanding lab1.c
Before we continue you should make sure that you understand what is happening in the C program source code.
What do you think the program is trying to do?
Repeat the calculations with a calculator. What results do you get? Write them down, as we will need them very shortly.
When you compile and run the program, what do you think it will appear to do? If you cant answer these questions, ask for help.
1.15 Compiler errors, warnings and debugging the lab1.c program
We are now going to use investigate how the compiler tells us about various things wrong with a pro gram we are working on.
Press the Build and run button. Look in the Logs others panel in the Build log tab as the compilation process executes.
Everything should compile and a command window will pop up displaying the output of our program.
When there are problems with the C source code, the compiler will generate errors and warnings. These will appear in the Build log tab.
errors are when the source code is not written in proper C language syntax and the compiler doesnt understand. The compiler will give an error message to try to help you to understand the problem;
warnings are when the source code is written in valid C but the compiler thinks you might have made a mistake. It may be that you have mistyped something or the flow of your program is logically wrong.
Only errors will stop the compiler and linker from producing an executable. Warnings will not stop it, but you should still pay a great deal of attention to them!
Now if you looked at the Build log when you built the program it will have given a warning. This is shown below. The text about the path to the folders has been removed. The first line appears in black and the warning appears in dark blue.
In function main:
15 warning: variable averagespeed set but not used
Wunusedbutsetvariable
Revision 5.1 Introduction to the C Programming Language 17
This warning is nothing to worry about. The compiler is just pointing out that although the integer vari able average speed has been declared and a calculation using it has been carried out see towards the end of the program, nothing is done with this i.e. we have not printed out the value or used it in a further caculation. Effectively, the compiler is reminding you about that, as you probably want to do something with the value. It also points out that it thinks the problem is at line 15 of the program, which is where average speed is declared.
Now, lets deliberately generate an error, just to see what happens when we try to build the program. Remove the ; symbol at the end of the line in the program which looks like:
distancetotokyo 9720;
So now it should look like:
distancetotokyo 9720
Now build the program. Now it will say in red:
21 error: expected ; before distancetoairport
It will also show a red square on the line 21 on the program listing.
Now correct the error, save the file and Build and run the program again.
You should have noticed from the program code that there are no statements telling the computer to display any information to the screen. So it doesnt. When you are writing a C program the computer will not do anything that you havent told it to do. Sometimes that is useful, other times, less so!
A debugger is built in to the IDE. We will be using two of its most important features:
stepping, which allows you to execute your program a line at a time, while the editor shows you which line will be executed next;
inspecting, which allows you to look inside variables to find out what their values are, whilst the program is running.
position the cursor over line 29 in lab1.c, which should be the line
timetofly distancetotokyo distancetoairport speedofplane;
Now right click the mouse and select Toggle breakpoint first option on menu. After you have done this a red circle will appear by the line number. A breakpoint is a point in Debug mode where the program will stop and wait for further instructions from the user. Now go to the Debug menu at the top of the IDE and select Start this can be done through a function key shortcut F8. The debugger will now run through the program and stop on the breakpoint. Once again return to the Debug menu and select Debugging windows Watches. A window will open in the IDE with two items in the window: Local variables and Function arguments. Each has a small plus sign on the left. Click on the plus sign next to Local variables. When you do this you will see a list of variables that are used in the program. The first four look like:
distancetotokyo 9720
distancetoairport 120
speedofplane 1200
speedofcar 100
18 Introduction to the C Programming Language Revision 5.1 These variables have all been given these values by the C program as it has executed all statements
before the breakpoint. After, the above variables it lists the other variables in your program:
timetofly 4200702
timetodrive 2293592
timetotokyo 4200608
averagespeed 2009288258
These have not received values from the program as the statements that define the values these vari ables take has not been reached yet. Consequently these variables have more or less random values. Dont worry if these uninitialized variables have different values to those above as they are processor dependent.
To begin stepping through your program starting at line 29, press F7, and you will see a small yel low triangle appear next to the line number. This indicates which line the debugger will execute next. Repeating this will advance the program execution another line. The debugger will skip lines that it cannot execute, such as comments and variable declarations.
As you step through the program you should be able to see the values change in the watch window. When you reach the last line of the program return 0; stop the debugger via the debug menu.
Exercise 1.2: Using the Debugger
Remove the breakpoint on line 29 and create a breakpoint on line 15. Now use the debugger to step through the program. Check the watch window after each time you step and check that you understand what has changed and why.
Do you understand what the program is doing?
How do the calculations compare with the results you obtained with a calculator? If the results are different, why are they different?
If you cant answer these questions, ask for help.
1.16 Displaying Text on the Screen
We are now going to add a statement to the program which calls a function to put some text on the screen. The function we are going to use is called printf. To be able to use the function the compiler needs to have some information about the function which is contained in a separate file, called a header file. You can tell the compiler to look in the header file that is needed for printf by putting the following line at the top of your program before the main function.
include stdio.h
This means include information from the header file called stdio.h. The header name stdio is short for Standard Input and Output and it contains readymade functions for getting information from the keyboard and to the screen, as well as to and from files. In this case it, will allow the compiler to understand the printf function we are about to use.
After the line:
timetotokyo timetofly timetodrive;
Type in a new line:
Revision 5.1 Introduction to the C Programming Language 19 printfIt takes d hours to get to Tokyon, timetotokyo;
Make sure you get the direction of the backslash correct and that you dont miss the semicolon off the end of the line. Be careful that you dont change the case of the letters that you type from the ones printed here. C always treats lowercase letters like a, b and c differently from uppercase letters like A, B and C.
Build the executable again. You shouldnt have any errors or warnings. If you do, ask for help.
Use the menu item Build Execute lab1.exe to execute the new program. You should see a window containing the following text.
It takes 9 hours to get to Tokyo
Press any key to continue
Syntax: Function Calls
variable name argument , argument n ;
To call a function you must first know its name, and whether or not it needs any information when you call it. Pieces of information that you give to a function when you call it are called arguments. Ar guments are enclosed in a set of parentheses brackets and are separated by commas. For example, the function call:
printfIt takes d hours to get to Tokyon, timetotokyo; calls the printf function and passes two arguments. The first argument is
It takes d hours to get to Tokyon
and the second argument is
timetotokyo
Some functions give, or return, a result after they have been called. We will meet some examples of these types of functions in later labs.
20 Introduction to the C Programming Language Revision 5.1
Function Reference: printf Displays text on the screen printfformat string , data item n ;
e.g.
printfHello, World!n;
printfDisplay the value of an int variable: dn, anint;
printfDisplay the value of a double variable: lfn, adouble;
The printf function displays text and data on the screen. It takes the following arguments:
format string is the text to be printed on the screen enclosed in double quotes … data item these are variables whose values will be printed on the screen
In order to specify where in the text the values of variables are to be printed, special characters are used in format string. These are known as place holders because they reserve space for these values to be printed. All printf place holders begin with a percent character . The most common place holders are:
d for integer int variables. You can remember this as d for decimal. lf long floating point used for real valued double variables.
c for single characters char.
The place holders are matched with the comma separated data item arguments in order. For ex ample:
printfResult 1 d, result 2 dn, 6, 7;
will display
Result 1 6, result 2 7
The printf function is defined in the header file stdio.h, therefore, to use printf you must
make sure that the line
include stdio.h
appears near the top of your source file. This allows the compiler to understand and find the printf function.
The printf format string can also contain special sequences of characters such as n which begins a new line and t which displays a tab character. The backslash functions as a special character causing the next character to be treated specially. This is called an escape sequence. If you want to specify a backslash in C you have to type the escape sequence for a backslash, which is two backslashes .
Revision 5.1 Introduction to the C Programming Language 21
Exercise 1.3: Using the double Variable Type
You should have noticed that because the program uses integer variable types it produces an answer of 9 hours, when the correct answer is 9.2 hours. To get the correct answer you should use the double variable type.
Change the variable declarations so that the type of all variables is now double rather than int.
Change the format specifier in the printf function call to be lf rather than d.Note thats a lowercase letter L and not a digit 1 in lf.
You should now be able to rebuild your program and execute it.
Exercise 1.4: Calculating the Proportion of Time Spent in the Air
Your program should now display the fact that it takes 9.2 hours to get to Tokyo. You are going to add some code of your own to display the percentage of the total time which is spent on the aeroplane. It should also display the percentage of time spent in the car obviously the sum of the two should be 100.
Your program should display something like:
x percent of time is spent in the aeroplane x percent of time is spent in the car
with the xs replaced by the results of the calculations you have added. Some hints:
you will need some more variables. Choose their names carefully;
you will need to add some calculations of your own. Remember that every statement in C ends with a semicolon;
you will need to add two printf lines to display the percentage results. Ask for help if you do not understand how to do this.
1.17 Graphics Option
There are two kinds of optional sections in the C Labscripts. One involves graphics and the other audio or midi related exercises. You are strongly encouraged to attempt both. However, if you are on a Music Technology related degree you might like to try the graphics exrecises after you have already completed the music options. On the other hand if you are not on a Music Technology degree you should try the graphics exercises first and then the music ones. The section for the music option begins after this one Section ??.
As an example of how to use C we are going to investigate graphical output. Although this is not strictly part of the C language, the principles are important for all C programming. Producing graphical output in Windows is quite complicated so this laboratory course uses a set of functions which are explicitly intended for creating graphics easily on Windows. This set of functions is an example of a software
22 Introduction to the C Programming Language Revision 5.1 library. The graphics library functions create a separate window to draw in.
Graphics are displayed in the graphics window by colouring the tiny dots that make up the display. These tiny dots are called pixels. Using the graphics functions you can control the colour of any pixel inside the graphics window. Each pixel in the window has a location which can be described using an x and ycoordinate, much like on a graph. The difference from most graphs is that the origin of the x and yaxes is in the top left of the window.
You will be able to choose the size of the graphics window, up to the size of the screen.
Revision 5.1 Introduction to the C Programming Language 23 1.17.1 A Simple Graphics Program
In Build target select graphics1 and also open the code listing graphics1.c.
The graphics1 program behaves quite simply at the moment. It displays the graphics window, which has a black background, and draws a red circle on it. When a key on the keyboard is pressed, the window closes. Try building and executing graphics1.
The source code for graphics1.c is shown below.
C Programming laboratory 1
This line allows the compiler to understand the
A program to demonstrate simple graphical operations
graphics functions
include graphicslib.h
The main function the program starts executing here
int mainvoid
Declare two variables for the x and y positions
int xposition, yposition;
Open a graphics window
Make it 640 pixels wide by 480 pixels high
initwindow640, 480;
Set up some coordinates
xposition 100;
yposition 340;
choose red pen colour
setcolorRED;
draw a circle at xposition, yposition
with radius 10 and line thickness 2
circlexposition, yposition, 10, 2;
move the contents of the screen buffer to the display
updatedisplay;
Wait for a key press
getch;
Close the graphics window
closegraph;
return 0;
We will go through this program a few lines at a time. Make sure you understand it before continuing. At the top of the source file, after the initial comment, is the line
include graphicslib.h
24 Introduction to the C Programming Language Revision 5.1
This allows the compiler to understand the graphics functions. This works in the same way as the include stdio.hlineyouneededtoputintoyourcodetoallowthecompilertounderstandthe printf function.
The first line of the main function declares two integer variables:
int xposition, yposition;
These variables are declared in exactly the same way as in the first example. The next line calls a graphics function to display the graphics window:
initwindow640, 480;
Calling the initwindow function in this way produces a window 640 pixels wide the xdirection and
480 pixels high the ydirection.
Function Reference: initwindow Creates a graphics window of a specified size
initwindowwidth, height; e.g.
initwindow640, 480;
The initwindow function creates the graphics window to allow you to begin drawing in it. The graphics window will be created with a drawing area of the specified dimensions, i.e. it will be width pixels wide and height pixels high.
When you have finished with the graphics window you should close it with the closegraph func tion.
initwindow is defined in graphics lib.h.
The next two lines set the coordinate variables to the point at which we are going to draw the circle:
xposition 100;
yposition 340;
This position will be the centre of the circle.
Before we do any drawing, we set the colour that we will be using to draw with:
setcolorRED;
Calling the setcolor function does not produce any output on the screen. It changes the colour that will be used for future graphics functions. It is the equivalent of picking up a pen of a specific colour.
Revision 5.1 Introduction to the C Programming Language 25
Function Reference: setcolor Sets the current drawing colour
setcolorcolour number;
The setcolor function determines the colour that is used for future graphics drawing operations. The colour is set using the colour number argument which is an integer from 0 to 15. You can just pass it a number but the graphics system defines some colour names to make it easier to use:
0 BLACK 1 BLUE 2 GREEN 3 CYAN 4 RED
5 MAGENTA
6 BROWN
7 LIGHTGRAY
8 DARKGRAY
9 LIGHTBLUE
10 LIGHTGREEN 11 LIGHTCYAN
12 LIGHTRED
13 LIGHTMAGENTA 14 YELLOW
15 WHITE
For example, to set the drawing colour to yellow you could either write
setcolor14;
or
setcolorYELLOW;
setcolor is defined in graphics lib.h.
The next line actually draws the circle:
circlexposition, yposition, 10, 2;
The circle has its centre at x position, y position and has a radius of 10 pixels. The fourth param
eter after 10 is 2. This determines the thickness of the pen used to draw the circle.
Function Reference: circle Draws an unfilled circle in the graphics window
circlexpos, ypos, radius, thickness;
The circle function draws an outlined circle in the graphics window in the current colour. The circle will have its centre point at the position specified by xpos and ypos which are coordinates from the topleft corner of the graphics window, in pixels. It will have a radius as specified by radius, in pixels. The thickness of the circle perimeter is specified by thickness.
For example
circle200, 300, 20, 5;
will draw a circle with its centre at 200, 300 with a radius of 20 pixels and line thickness of 5. circle is defined in graphics lib.h.
The next line is:
26 Introduction to the C Programming Language Revision 5.1 updatedisplay;
Before we explain the next line, it is important to realise that all graphics functions actually write to an internal graphics display, called a screen buffer. We need to call the function update display to move the contents of the screen buffer to the live display. This may seem a little tedious at first, but it allows us to do something that is very useful. We can create the appearance and possible movement of multiple graphics entities.
Function Reference: update display Moves the contents of the screen buffer to the screen
update display;
The update display makes the contents of the screen buffer live by moving it to the screen memory. It should be called after using graphics functions when you want the drawn elements to appear.
update display is defined in graphics lib.h.
The next line calls a function which waits for a key press:
getch;
This simply has the effect of leaving the graphics window on the screen while the computer waits for a key press. When the user presses a key, the program moves on, and closes the graphics window. Without this line the graphics window would disappear before you had a chance to see it. We will be seeing more of the getch function in later labs.
Function Reference: getch Waits for a key press from the keyboard character getch;
The getch function waits for a key press on the keyboard and then returns the value of the key that was pressed as an integer character code.
It is easy to use as a function that waits for a key press, when you dont care about which key the user has pressed. For example
getch;
If you want to find out what key was pressed then you can assign the result of the function call to a variable
int variable getch;
We will see more of this in later labs.
getch is defined in conio.h and also graphics lib.h.
After the user has pressed a key, the program will continue to the next line:
closegraph;
Revision 5.1 Introduction to the C Programming Language 27 which closes the graphics window.
Function Reference: closegraph Closes the graphics window closegraph;
The closegraph function closes the graphics window. It should be called before your program ends if you opened a graphics window.
closegraph is defined in graphics lib.h.
Exercise 1.5: A First Look at Graphics
Before we continue you should make sure that you understand what is happening in this graphics example.
Some things to investigate for yourself:
try changing the colour that is used to plot the circle;
try moving the position in which the circle is drawn by changing the coordinates; try changing the size of the circle.
After you have made a change remember to rebuild the program and execute it to see the results.
1.17.2 Some Simple Drawing
The next thing you will do is to draw a very simple stick person using a circle and four lines. Hopefully it will look a bit like this:
You have already seen the circle function. The only other function you need to know about to draw the stick person is the line function.
Function Reference: line Draws a line in the graphics window linestart x, start y, end x, end y, thickness;
e.g.
line100, 150, 200, 250, 2;
The line function draws a line in the graphics window using the current colour. The line is defined by its starting point and its ending point. The arguments start x and start y define the x and ycoordinates of the starting point respectively. The arguments end x and end y define the x and ycoordinates of the ending point respectively. The last argument defines the line thickness.
line is defined in graphics lib.h.
28 Introduction to the C Programming Language Revision 5.1
Exercise 1.6: Drawing the Stick Person
Change the program to place the circle in the right place for you to draw your stick person. Add four line function calls to draw the lines to make up the stick persons body, arms and legs. This may take a lot of experimentation!
It helps if you draw it out on paper first and try and work out what coordinates you will need. Remember that the origin of the x and yaxes is in the top left of the window.
Plot the lines using the x position and y position variables. For example:
linexposition, yposition 10, xposition, yposition 50, 2;
This defines the line with respect to the position of the centre of the stick mans head which is given by x position and y position. If you define all the drawing elements of the stick man in this way, you will be able to change the position of the stick man by just changing the values held by the variables x position and y position.
Ask for help if dont know how to complete this exercise.
Remember: Once you have created your executable program you can run it outside of the Code::Blocks IDE. To do this, locate the clab folder and within it, the bin folder. Inside that you will see there is a folder called Debug. Inside this you will see a file called graphics1.exe. If you double click this icon it will run graphics1 outside of the IDE.
1.18 Music Option
You should only begin this section if you have chosen to do the music option i.e. if you are a Music Technology student, or if you have chosen to do the graphics option but have already completed that section.
As an example of how to use C we are going to investigate how to get the computer to make sounds. Although this is not strictly part of the C language, the principles are important for all C programming.
We will be using the computers MIDI facilities to produce sound. MIDI stands for Musical Instrument Digital Interface and is a way of connecting electronic musical devices together such as keyboards, synthesisers and computers. Elsewhere in your Music Technology course you will learn about it in much greater musical and technical detail. For now, we will just be using it to get the computer to play sounds. Later on we will use another software librray called portaudio which will allow music files such as .wav to be read into a program and manipulated.
Producing MIDI sound output in Windows is quite complicated so this laboratory course uses a set of functions which are explicitly intended for creating sounds easily on Windows. This set of functions is an example of a software library.
1.18.1 A Simple Music Program
In Build target select music1 and also open the code listing music1.c.
The music1 program behaves quite simply at the moment. It plays a single note, a middle C, for a second and then stops. Try building and executing music1. Before you execute any midi program you must place headphones or speakers into the headphone socket of your computer. If you dont you will get a strange looking error message which looks like this:
Portmidi found host error. There is no driver installed on your system
The source code for music1.c is shown below.
Revision 5.1 Introduction to the C Programming Language 29
A program to demonstrate simple musical operations: C Programming laboratory 1
This line allows the compiler to understand the
midi functions
include amiolib.h
The main function the program starts executing here
int mainvoid
Declare integer variables for specifying a note
int pitch, channel, velocity;
initialize the midi functions
midistart;
Set the pitch variable to 60, which is middle C
pitch 60;
We will play the note on MIDI channel 1
channel 1;
The note will have a medium velocity volume
velocity 64;
Start playing a middle C at moderate volume
midinotepitch, channel, velocity;
Wait, for 1 second, so that we can hear the note playing
pause1000;
Turn the note off by setting its volume to 0
midinotepitch, channel, 0;
close down all midi functions
midiclose;
return 0;
We will go through this program a few lines at a time. Make sure you understand it before continuing. At the top of the source file, after the initial comment, is the line
include amiolib.h
This allows the compiler to understand the MIDI music functions. This works in the same way as the include stdio.hlineyouneededtoputintoyourcodetoallowthecompilertounderstandthe printf function.
The next few lines set the values of integer variables which will control the note that the computer plays:
pitch 60;
channel 1;
velocity 64;
30 Introduction to the C Programming Language Revision 5.1 We will see what these numbers mean in a moment when we look at the midi note function.
The next line is:
midistart;
This is essential and initializes the midi interface so that sounds can be played.
The next line starts the computer playing a sound it turns a note on:
midinotepitch, channel, velocity;
The midi note function is perhaps the most useful function you will use for creating sounds. It is used to play a note of a certain pitch on a certain channel. MIDI allows 16 different channels, each of which can be set up to sound like a different instrument. Each channel can have notes playing on it at the same time. You can therefore have up to 16 different instruments e.g. violin, piano, synth etc. each on its own MIDI channel. The channels are numbered 1 to 16. MIDI Channel 10 is often reserved for a drummap, and so it reacts differently to all other channels, by allowing individual MIDI pitches to activate individual drums. But more on this later.
The musical pitch is specified by a number. Each semitone each note on a pianolike keyboard has its own number. Middle C, for example, has the number 60. The C immediately above middle C has the number 61, the D above that has the number 62, and so on. There are 12 semitones in an octave, so the octave below middle C has the number 48 60 12 48, and the octave above has the number 72. MIDI can produce notes in a range a few octaves wider than a standard piano: the lowest note number is 0, the highest is 127.
The other thing you must specify when turning on a note is the velocity. This is equivalent to how hard or fast hence the term velocity the key on a piano or synthesiser would have been pressed to produce a note of this volume. Velocity is therefore a specification of the loudness or power in a note. It ranges from 127 the loudest down to 0 slient. In fact, MIDI uses a velocity of 0 to turn a note off. You will see this in a moment where we instruct the computer to turn the note off.
Function Reference: midi start Initializes the midi interface midi start;
midi start is defined in amio lib.h.
Revision 5.1 Introduction to the C Programming Language 31
Function Reference: midi note Starts or stops a MIDI note playing midi notepitch, channel, velocity;
The midi note function sends a signal to the computers MIDI device allowing you to turn notes on and off. It has three arguments:
pitch The pitch of the note as an integer value in the range 0 to 127. Middle C has the value 60.
channel The MIDI channel you wish to use to play the note as an integer number. There are 16 MIDI channels numbered 1 to 16, each one can be set up to use a different instrument and notes can be playing on all channels at once.
velocity The velocity related to volume of the note to be played as an integer value. This argument can range from 127 loudest to 0 silent. Setting the velocity of a note to zero is used to turn the note off.
So for example, to play middle C on channel 1 at moderate volume you could write:
midinote60, 1, 64;
which would turn the note on. To turn the note off you would write:
midinote60, 1, 0;
A note that is not turned off will continue to play forever, possibly even after your program has ended!
midi note is defined in amio lib.h.
If we turned the note off again straight away it would play for such a short time that you might not even hear it. To make sure you can hear it we make the computer wait, using the pause function:
pause1000;
You tell the pause function how long to wait for in milliseconds and it does not allow your program to continue until that time has elapsed. The pause therefore controls how long the note is played for: its duration. In this case the note will play for one second 1000ms 1 second.
Function Reference: pause Waits for a specified amount of time
pauseduration;
The pause function causes the computer to wait before continuing. The amount of time the com puter waits for is determined by the duration argument, which is a integer number, and specifies the amount of time the computer should wait for in one thousandths of a second milliseconds.
For example:
pause500;
will cause the computer to wait for half a second 500 milliseconds before continuing. pause is defined in amio lib.h.
32 Introduction to the C Programming Language Revision 5.1
After the program has waited for 1 second, the note is turned off:
midinotepitch, channel, 0;
Notice that the correct pitch and channel must be specified so that the computer knows which note to turn off.
After all the midi notes have stopped we need to reset the midi interface using the command:
midiclose;
Function Reference: midi close Closes the midi interface midi close;
midi close is defined in amio lib.h.
Exercise 1.7: Experimenting with MIDI
Experiment with changing the values relating to the note that is played in the music1 example. Try altering:
the pitch;
the velocity;
the duration the pause function argument.
After you have made a change remember to rebuild the program and execute it to see the results.
When you are happy with creating different notes and durations try to get the computer to play a set of notes, one after the other. Build up a set of notes to form a tune. You can use the Copy and Paste commands on the Edit menu in the IDE to copy sections of code multiple times. This should save you having to type the same sections again and again!
N.B. If you notice that your last note is being cut short it is probably because the midi closefunction is being called before your note has had a chance to fully play. If this is the case, add an extra pause of, say, 1 second just before the midi closefunction call, and see if this cures the problem.
If you dont know how to do this, ask for help.
1.18.2 Playing More than One Note at Once
If you turn two notes on, one after the other, they will both play at once. For example:
midinotepitch, channel, velocity;
midinotepitch 3, channel, velocity;
and after a pause, turn the same notes off:
midinotepitch, channel, 0;
midinotepitch 3, channel, 0;
Revision 5.1 Introduction to the C Programming Language 33 By choosing the correct notes you can create a chord. For example, you could turn on a major triad with
the following code.
Turn on the tonic
midinotepitch, channel, velocity;
Turn on the major third
midinotepitch 4, channel, velocity;
Turn on the perfect fifth
midinotepitch 7, channel, velocity;
You would need to turn all the notes off again afterwards.
Exercise 1.8: Creating Chords
Change your tune so that it ends on an appropriate major triad. Experiment with ending on other chords, can you produce:
a minor chord?
a dominant 7th?
a diminished chord?
a minor 7th added 9th chord?
Some of these may not be the most appropriate for your tune, but try them anyway!
If you are not sure of what musical intervals are required for the above chords discuss these amongst yourselves, or type forming chords into a search engine.
1.18.3 Changing the Instrument
You can change the MIDI instrument that is being used on a given channel using the program change function. For example:
programchange1, 57;
sets MIDI channel 1 to use instrument number 57, which is usually a trumpet. The exact correspondence between instrument numbers and instrument sounds or voices is dependent on the sound card being used.
34 Introduction to the C Programming Language Revision 5.1
Function Reference: program change Changes the current instrument on a MIDI channel
program changechannel, voice; e.g.
programchange1, 51;
The program change function changes the active instrument on the channel specified by channel. channel should be an integer number from 1 to 16 the same as used in the midi note function. The instrument is selected using the voice argument. This should be an integer number between 1 and 128. Each number corresponds to a different instrument. The instrument that a given number corresponds to is defined by the General MIDI specification, which most MIDI devices adhere to. Some common instruments and their voice numbers are:
1 Acoustic Grand Piano
43 Cello
49 String Ensemble 51 Synth Strings
57 Trumpet
58 Trombone
66 Alto Sax
67 Tenor Sax
74 Flute
Synth Drum
the internet for more information.
7 Harpsichord
10 Glockenspiel 13 Marimba
17 Drawbar Organ
27 Electric Jazz Guitar
28 Electric Clean Guitar
33 Acoustic Bass
41 Violin 119
Check MIDI documentation for example on program change is defined in amio lib.h.
Exercise 1.9: Changing the Program
Experiment with using program change to change the voice that is being used to play your tune.
Exercise 1.10: Creating both Melody and Chords
Use the program change function to set up two different voices on two different MIDI channels. Add some simple chords to your tune just a few will do which should play at the same time as the melody, but on a different channel.
If you dont know how to do this, ask for help.
Revision 5.1 Introduction to the C Programming Language 35 1.19 Summary
Now you have completed this lab you should know how to use the Code::Blocks IDE to build and run C programs. You will also have some understanding of the basic structure of a C program. You should also:
understand how to declare variables and choose their type;
be able to carry out some simple mathematics in C;
understand what a function call is and be able to call some simple functions such as printf.
If you chose the graphics option then you should understand the basic structure of a graphics program including how to display and close the graphics window. You should also be able to draw circles and lines in many colours.
If you chose the music option you should be able to instruct the computer to play notes of any valid pitch and on any instrument. You should have learned that, with MIDI, notes need turning on and off, and that the time between the two is the notes duration. You should also have learned how to play chords.
36 Introduction to the C Programming Language Revision 5.1
Laboratory 2
Conditional Statements: The if and
switch Statements 2.1 Overview
This laboratory will introduce you to the if and switch statements. Both allow your program to make decisions. You will learn how to form relational expressions which evaluate to be either true or false and allow if statements to work. You will find that switch statements are useful when there are lots of exact options.
This lab will also introduce you to two ways in which you can get input from the user of your program even if thats you!. The scanf function allows you to get a whole line of input from the user, and is useful for obtaining input made up of lots of key presses, like numbers. The getch function allows you to get a single key press from the user and is useful for more interactive input. You will use both of these functions a great deal more in later labs as well.
2.2 Getting Input from the User
We will begin by using the scanf function to obtain input from the user of your program. Change the target to lab2 and open it in the IDE.
The lab2 program will ask the user for an integer number. After the user has typed in a number and pressed the Enter key, the program tells the user what number they entered. Try building and executing the lab2 project.
The source code for lab2.c is shown below.
This line allows the compiler to understand both the
printf and scanf functions
include stdio.h
int mainvoid
Declare a variable to store an integer number
int numberentered;
Output some text to the user
printfEnter an integer number: ;
A program to demonstrate the use of the scanf function
C Programming laboratory 2
38 Introduction to the C Programming Language
Revision 5.1
Wait for the user to enter a number and hit enter
Store the number in the numberentered variable
scanfd, numberentered;
Display the number that the user entered
printfThe number you entered was dn, numberentered;
return 0;
The program uses the printf function that you met in the last laboratory to display a message to the user:
printfEnter an integer number: ;
It then uses the scanf function to get a single integer value from the user, and to put the information
into the number entered variable: scanfd, numberentered;
The first argument of the scanf function is at least one place holder enclosed in double quotes, exactly the same as they are used in the printf function. In a similar way to printf, for every place holder in the quotes there should be a variable listed as part of the function call. Usually you will only use one place holder and one variable with scanf.
You should notice that the variable has an ampersand, a character, before it. This is not a mistake! When you use scanf you should put an ampersand before each variable name. The exact reason for this is quite complicated and you will learn about later in the course. Until then you will have to remember that whenever you use the scanf function to get numbers or single characters from the user you must put an ampersand before the variable name.
Revision 5.1 Introduction to the C Programming Language 39
Function Reference: scanf Obtains a line of input from the user variable scanfformat string , data item n ;
e.g.
The scanf function obtains typed input from the user. It lets the user type in text and then waits for them to press Enter. It then takes the text that they have entered and attempts to match it to the place holders specified as part of the format string.
It takes the following arguments:
format string contains the place holders that scanf will try to match input to enclosed in
double quotes …
data item these are variables which will be set to the values recovered from the users
input
scanf uses the same place holder system as printf. As a reminder, the most useful place holders are:
d for integer int variables;
c for single characters char;
lf real valued double variables.
The place holders are matched with the comma separated data item variables in order.
The return value of scanf the value that is assigned to variable is the number of place holders
that were successfully matched. scanf is defined in stdio.h.
scanfd, anintvariable;
scanfc, acharvariable;
numberofmatches scanflf, adoublevariable;
Exercise 2.1: Changing the Variable Type
Alter the lab2 program so that it accepts real valued numbers from the user, not just integers. You will need to change the type of the number entered variable and the place holders in both the scanf and printf functions. Rebuild and execute the program to check that it works.
2.3 Making a Decision: Conditional Statements
We are now going to use a conditional statement to make a decision about which part of your program will execute depending on the number that the user enters. We will do this using an if statement.
40 Introduction to the C Programming Language Revision 5.1
Change your lab2 program to remove the second printf line the one that displays the value back to the user, and replace it with the following lines:
if numberentered 10
printfThat number is bigger than tenn;
Try building and executing the program. After you have entered the number, it should tell you whether the number is bigger than 10.
When you are satisfied that it works you may have to run it a few times, add another two lines after the if part to add an else condition, like this:
if numberentered 10
printfThat number is bigger than tenn;
else
printfThat number is smaller than ten or equal to tenn;
Build your program and execute it a few times, to test it with different numbers.
Exercise 2.2: Understanding Conditionals
Use the debugger to try stepping through the program you have just written with the if statement in it. Where does the flow of execution the yellow arrow go:
for numbers greater than ten; for numbers less than ten.
When the yellow arrow reaches a scanf statement it will wait until you enter a number before it will continue. To enter the number you must make sure that the window in which your program is actually executing it will have a black background is at the front.
An if statement makes a decision based on the part that is in brackets. The part in brackets is called a relational expression. It compares things using relational operators such as greater than, , and less than, to obtain an answer that is true or false. The words if and else are treated specially by C; it uses them to recognise that you want to do something conditionally. Words that are treated specially in this way are called keywords, because they are treated specially they cannot be used for variable names. You will meet many more keywords as part of this course.
Revision 5.1 Introduction to the C Programming Language 41
Syntax: Relational Operators and Expressions
!
Relational operators allow you to compare things such as the value of variables and numbers or characters. A simple relational expression compares two things and uses one relational operator:
item1 relational operator item2
The relational operator can be any one of the following:
less than
greater than
equal to
! not equal to
less than or equal to
greater than or equal to
The result of a relational expression is therefore true or false. We say the expression evaluates to true or false.
So, for example, lets construct a relational expression which tests the value of a variable called test against the number 5. If test has the value 6 then:
test 5 will evaluate to false
test 5 will evaluate to true
test 5 will evaluate to false test ! 5 will evaluate to true
If test has the value 5 then:
test 5 will evaluate to false
test 5 will evaluate to false
test 5 will evaluate to true test ! 5 will evaluate to false test 5 will evaluate to true test 5 will evaluate to true
It is very important to notice that the operator for testing whether two things are the same is not . This is the assignment operator, which we saw in the previous lab. The operator for testing if two things are the same is the double equals , this is different to the assignment operator. Dont get them confused. Sometimes the compiler wont pick the error up and your program will malfunction in peculiar ways!
42 Introduction to the C Programming Language Revision 5.1
Syntax: if statements
if relational expression statement1; else statement2;
The if statement allows you to execute a piece of your program conditionally. The if statement guards a single statement statement1 of a program and only executes it if the relational expression evaluates to true. Optionally, an if statement can be followed by an else section, which guards a second statement statement2. This second statement only exe cutes if the relational expression evaluates to false.
You have already seen how to add an else section to an if statement. You can produce a more com plicated and more useful structure by making the statement that the else part guards statement2 in the above syntax box another if statement. This allows you to connect if statements together, for example:
if numberentered 5
…
else if numberentered 5
…
else if numberentered 5
…
else …
You will need to understand how this works in order to be able to complete the next exercise. Ask if you need any help.
Exercise 2.3: Using Relational Operators
Alter the lab2 program so that after it accepts the number from the user it prints either
or
or
That number is less than or equal to zero
That number is greater than or equal to ten
That number is between one and nine
appropriately.
If you dont know how to answer this question ask one of the demonstrators for help.
Revision 5.1 Introduction to the C Programming Language 43 2.4 Grouping Statements into Compound Statements
Try adding a second printf statement to the final else condition of the program you have just written. The code should look something a bit like this:
if … …
else if …
…
else
printf…;
printfA printf statement I have just addedn;
What happens when you execute it?
You should find that the second printf statement is always executed. Compare the code with the syntax box on if statements. You should notice that if and else clauses a clause is a part of a statement only guard one statement. If you want the if statement to guard more than one statement you must group statements together into a compound statement. A compound statement replaces any statement like this:
statement;
including the semicolon with a set of statements, grouped together by braces curly brackets. Like this:
statement2;
You can replace any statement in C with a compound statement. This is useful for making an if state ment guard a set of statements. Returning to our example, it should be rewritten like this:
if … …
else if …
…
else
printf…;
printfA printf statement I have just addedn;
statement1;
Exercise 2.4: Adding Compound Statements
Add an extra printf statement to every branch of your if . . . else. You will need to use a com pound statement for each branch. Check that it works as you would expect when you execute it.
Compound statements are very useful for if statements. You will find them essential in the next lab when we look at repeating and iterating sets of statements grouped together into block statements.
44 Introduction to the C Programming Language Revision 5.1
Syntax: Compound Statements
…
A compound statement is a way of grouping statements together to replace a single statement with
many statements. Any statement like this:
statement;
can be replaced by lots of statements like this
This is useful for making the if or else clauses of an if statement guard multiple statements.
statement1; statement2; …
2.5 Making More Complex Decisions: Logical Operators
Student x wants to go to the bar which is only open after 7:00pm but she will only go if she has some money left. We could try and code this decision in C, it might look a bit like this:
if time 19:00 and bankbalance costofonedrink
gotobar;
finishcassignment;
else
finishcassignment;
Please note: this is not real C! This kind of more complicated decision is common in everyday life. To handle this kind of thing in programming code requires us to combine several decisions to form one complex decision.
The relational expressions we have looked at so far make a single decision on the basis of a comparison between two values which could be variables. Quite often we need to be able to combine comparisons together with an and or an or. These operations combine expressions which can already be evaluated to the logical values true or false, in C they are known as logical operators. In C, an and is represented by the symbol an ampersand twice and an or is represented by a vertical bar twice. There is an extra logical operator for not, which turns a true into a false or a false into a true. The not operator is an exclamation mark !. You may need to use parentheses brackets with the not operator to ensure that the operator is applied to the correct part of the expression.
Revision 5.1 Introduction to the C Programming Language 45
Syntax: Logical Operators
relational expression relational expression relational expression relational expression !relational expression
Logical operators allow relational expressions to be connected together to form larger relational expressions. There are three logical operators which form expressions which may be evaluated to true or false depending on the truth value of the expressions they are connecting.
and evaluates to true only if both the relational expressions it connects evaluate to true.
orevaluatestotrueifbotheitherorbothoftherelationalexpressionsitconnectsevaluate
to true.
not ! evaluates to true only if the expression it is modifying evaluates to false.
So, for example, if we have two variables: test1 which is 5 and test2 which is 21 then:
test1 10 test2 30 is false test1 10 test2 30 is true test1 10 test2 20 is true test1 10 test2 20 is true test1 1 test2 30 is false test1 1 test2 30 is false !test1 1 is true
!test1 1 !test2 30 is true
Make sure you understand these before you go on to the next exercise. If you need help, just ask.
Exercise 2.5: Logical Operators
From previous exercises you should have a program that takes a numeric input from the user and distinguishes between numbers that are less than or equal to zero, numbers that are greater than or equal to ten and numbers in between. In each case it should print a different response to the user from a number of printf statements.
Add to this program to allow the user to input two different numbers you should prompt them twice. Use printf statements to show that the program can distinguish between the conditions:
when either number is less than 0;
when both numbers are less than 0;
when the first number is greater than 10 and the other is not greater than ten.
The program should only need to display one of these messages you may need to structure your if . . . else statements carefully to get it to do this.
46 Introduction to the C Programming Language Revision 5.1 2.6 Dealing with Many Options
Sometimes you may need to make a decision on a single variable where there are lots of possible options. You could deal with this by stringing together lots and lots of if statements, but C provides a special statement to deal with this situation, called switch. The switch statement allows you to specify a number of cases, which are the options that you are interested in. There is also an special case for all other options, labelled default.
The lab2a project demonstrates the switch statement in a very simple way. Change the target to lab2a and open it in the IDE.
Now, build and execute it.
The source code for lab2a.c is shown below.
include stdio.h
int mainvoid
int numberentered;
Output some text to the user
printfEnter an integer number between 1 and 9: ;
Wait for the user to enter a number and hit enter
Store the number in the numberentered variable
scanfd, numberentered;
Display the number that the user entered
But display it as English text
printfThe number you entered was ;
This switch statement decides between lots of options
switch numberentered
case 1:
printfonen;
break;
case 2:
printftwon;
break;
case 3:
printfthreen;
break;
case 4:
printffourn;
break;
case 5:
printffiven;
break;
A program to demonstrate the use of the switch statement
C Programming laboratory 2
case 6:
Revision 5.1
Introduction to the C Programming Language 47
printfsixn;
break;
case 7:
printfsevenn;
break;
case 8:
printfeightn;
break;
case 9:
printfninen;
break;
default:
printfnot between one and ninen;
return 0;
Let us look at the switch statement in detail. It begins with the keyword switch followed by the name of the variable that we wish to switch on, in parentheses. Like this:
switch numberentered
We then describe a number of cases, which are different options for the value of the variable given in the switch part. All these cases are enclosed in a set of braces, like a compound statement. The switch statement looks for the first case clause that matches the value of the variable. When it finds it, it starts executing from that point onwards. Lets take the example where the variable number entered has the value 4. The switch looks down its list of case clauses until it finds the one that say case 4:, it then starts executing at that line, so the next thing it executes is the line:
printffourn;
The next line says
break;
which tells it to stop executing the code inside the switch statement, and to continue after the closing brace . You should also notice that there is a special case clause called default. This gets executed if none of the other case statements before it match. Because the switch statement attempts to match case clauses in order, the default clause should always go last.
48 Introduction to the C Programming Language Revision 5.1
Syntax: switch statements
switchvariable case clause n default clause
The switch statement allows you to make a choice between a number of options. Each option is a different value of the variable specified at the start of the statement. Each possible value of interest is described using a case clause. A case clause has the following syntax:
case value: …
A switch statement finds the first case that matches and continues to execute from that point onwards. It will even continue into the next case. To stop it executing at the end of the code for each case it is common to include a break statement. The break statement stops any more of the switch statement from executing. A case clause with a break statement looks like this:
case value: …
break;
A default clause is like a case clause except that it matches anything. This is commonly used at the end after all the case clauses to match anything that hasnt already been matched. Because the default clause goes last, it does not need a break statement.
Exercise 2.6: Flow of Execution in switch Statements
Try using the debugger to step through the switch statement in the lab2a example. Watch where the flow of execution goes. What do you think will happen if you remove some of the break state ments? When you have finished stepping through, remove some of the break statements, rebuild the project and try stepping through it again. Does it do what you expected?
If you do not understand the programs behaviour ask one of the demonstrators.
2.7 Getting a Single Character from the User
The programs in this laboratory have used the scanf function to get input from the user. As you have seen, the scanf function collects input and allows the program to continue only after the user has pressed enter. Sometimes you want to make a program that is more interactive than this. In this section we will use the getch function to collect a single key press from the user.
The getch function waits for the user to press a single key and then returns the value of the key that the user pressed back to the program as a character. The getch function is described in conio.h, so to use it you must add the line
include conio.h
to the top of your source file.
You would use getch in the following way:
int keyentered;
Revision 5.1 Introduction to the C Programming Language 49
keyentered getch;
getch will wait for a key press and then the assignment will copy the value of the key as a character into the key entered variable. So, if you use the bit of code above, you have the value of the key press in a variable. Now you need to know how use the value.
You can describe the value of a character in C by enclosing the single character in single quotation marks. Like this:
if keyentered r
printfYou pressed the R keyn;
Function Reference: getch Obtains a single key press from the user character getch;
The getch function waits for a key press on the keyboard and then returns the value of the key that was pressed as an integer character code.
To find out what key was pressed then you should assign the result of the function call to an integer variable one of type int
int variable getch;
There are some special cases which relate to keys on your keyboard which are not straightforward letters. The best example is the arrow keys. In these cases when you call getch and the user presses an arrow key it will return zero. You will then need to call getch a second time. This time getch will not wait for a key press. It will return immediately with the value of an arrow key. In case a user presses a noncharacter key, getch should always be properly used as follows:
int variable getch; if int variable 0
int variable getch;
You should see from this code that getch is called twice if the value from the first getch was zero. In this case the value of the key can be tested to see if it matches one of many useful values, including the arrow key values which are shown below
Key Value
75 72 77 80 Enter 13
In some cases, the getch function may return the number 224, instead of zero, to indicate that an extended key has been pressed. It is usually good practice to check to see if a call to getch returns either zero or 224.
getch is defined in conio.h and also graphics lib.h.
50 Introduction to the C Programming Language Revision 5.1
Exercise 2.7: Using getch and switch
Adapt the lab2a program to use getch instead of scanf. The program should prompt the user for a single letter which is the first letter of a month. The program should then display the months that begin with that letter. You should use a switch statement for this. The program should not care whether you use upper or lower case, for example, pressing either F or f should result in the program displaying February.
Hint: You could use multiple case clauses to handle the upper and lower case letters. For example:
case f:
case F:
…
break;
If you do not understand how to do this, ask one of the demonstrators for help.
2.8 Graphics Option
We are going to alter the graphics program you were working on in the last laboratory to incorporate some of the new techniques you have just learned.
Close any project you have open at the moment and change the target to graphics1. Open graph ics1.c for editing.
Your code from last lab should draw a stick person on the screen. You are going to add to this code so that the user can decide the position of the stick person and the colour that it is drawn in.
Exercise 2.8: Adding User Control of Position to the Stick Person
When your program starts the user should be able to type in a number which specifies the horizontal location of the stick person on the screen. The user should be able to choose any location in the left half of the screen. You should use an if statement to check that the number is sensible, i.e. the user should not be able to specify a location that results in any part of the stick person being cut off by the lefthand edge of the window. The user should also not be able to specify a location that is in the righthand half of the window. If the user does specify an invalid location, you should display an error message and not show the graphics window with the stick person in it. The process of ensuring that input is suitable for your program is known as input validation.
For this exercise to work you will have to make sure that your stick person is not too big. You might like to draw in a line representing ground level below the stick persons feet.
You should now have a working program that allows the user to control the horizontal position of the stick person, within bounds which you have specified.
Revision 5.1 Introduction to the C Programming Language 51
Exercise 2.9: Adding User Control of Colour of the Stick Person
The next step is to allow the user to choose the colour of the stick person. You should do this by showing the user a menu a list of possible colours and allow them to choose the colour by pressing a single letter usually the one that corresponds to the first letter of the colour, e.g. R for red. This should choice should be caseinsensitive, i.e. r and R should be treated the same. You will probably want to use a switch statement for this. You should use the default clause to watch for invalid input from the user. If the user presses an invalid key you should display an error message and not show the graphics window with the stick person in it.
The circle which makes up the head of the stick person is currently empty. We can use an alternative to the graphics function filled circle to draw a filled circle with colour.
Function Reference: filled circle Draws a filled circle in the graphics win dow
filled circlexpos, ypos, radius, fillcolour;
The circle function draws a filled circle in the graphics window in the colour specified by fillcolour. The circle will have its centre point at the position specified by xpos and ypos which are coordinates from the topleft corner of the graphics window, in pixels. It will have a radius as specified by radius.
For example
filledcircle200, 300, 20, BLUE;
will draw a blue filled circle with its centre at 200, 300 with a radius of 20 pixels. filled circle is defined in graphics lib.h.
At this point it is worth mentioning a few more useful graphics functions.
Function Reference: ellipse Draws an ellipse in the graphics window
ellipsexpos, ypos, xradius, yradius, thickness;
The ellipse function draws an outlined ellipse in the graphics window in the current colour. The ellipse will have its centre point at the position specified by xpos and ypos which are coor dinates from the topleft corner of the graphics window, in pixels. It will have a radii as specified by xradius and yradius, in pixels. The sum of the radii is a constant and equal to the legth of the ellipses major axis. The thickness of the ellipse perimeter is specified by thickness.
For example
ellipse200, 300, 20, 10, 5;
will draw an ellipse with its centre at 200, 300 with an xradius of 20 pixels, a yradius of 10 and line thickness of 5.
ellipse is defined in graphics lib.h.
52 Introduction to the C Programming Language Revision 5.1 You can also draw a filled ellipse with the function
Function Reference: filled ellipse Draws a filled ellipse in the graphics window
filled ellipsexpos, ypos, xradius, yradius, fillcolour;
The filled ellipse function draws a filled ellipse in the graphics window in the colour specified by fillcolour. The ellipse will have its centre point at the position specified by xpos and ypos which are coordinates from the topleft corner of the graphics window, in pixels. It will have a radii as specified by xradius and xradius.
For example
filledellipse200, 300, 10, 20, BLUE;
will draw a blue filled ellipse with its centre at 200, 300 with an xradius of 10 pixels and a yradius of 20 pixels.
filled ellipse is defined in graphics lib.h.
Exercise 2.10: Using filled circle and filled ellipse
Add to your program to ensure the stick persons head is filled with the same colour as the colour used to draw the body.
Another useful graphics functions provided in graphics lib.h is the arc drawing function defined below.
Function Reference: arc Draws a circular arc in the graphics window
arcxpos, ypos, radius, angle start, angle end, thickness;
The arc function draws an arc of a circle of radius radius in the graphics window in the current pen colour and with a line thickness specified by thickness. The arc is drawn clockwise starting at angle in degrees specified by angle start and ending at angle angle end. The angles may be negative and are realnumbers as opposed to integers. An angle zero is equivalent to the horizontal axis. Note that the end angle is relative to the first i.e. it draws an arc by adding the end angle to the first.
For example
arc200, 340, 10, 90, 270, 2;
will draw a circular arc with its centre at 200, 340 with a radius of 10 pixels. It will begin at 90 degrees above the horizontal and draw clockwise until the final angle is 180 90270.
Revision 5.1 Introduction to the C Programming Language 53 2.9 Music Option
We are going to alter the MIDI program you were working on in the last laboratory to incorporate some of the new techniques you have just learned. Close any project you have open at the moment and change the target to music1. Open music1.c in the editor.
Your code from last lab should play a melody with some chords on a separate channel and a different instrument. You are going to add to this program to allow the user to choose the instruments for the melody and backing chords. You will also allow them to choose the key that the piece will be played in.
Exercise 2.11: Adding User Control of Instruments
When your program starts the user should be able to type in a number which specifies the instrument that will be used to play the melody. This should be a number from the General MIDI specification i.e. a number from 1 to 128. You should use an if statement to check that the number is in this range. If the user does specify an invalid instrument number, you should display an error message and not play the tune. The process of ensuring that input is suitable for your program is known as input validation.
The program should do the same for the instrument which plays the chords, i.e. the user should be able to choose an instrument for both before the piece is played.
You should now have a working program that allows the user to control the instruments that are used for both the melody and the chords, within bounds which you have specified.
For the next step you will need to make sure that all of the notes in the tune are specified as an offset from a variable whose value specifies the key. For example:
int key;
The key of this piece is C. All notes are specified
with reference to middle C
midistart;
key 60;
Turn a note on
midinotekey 3, 1, 64;
pause1000;
Turn the note off
midinotekey 3, 1, 0;
midiclose;
Ask a demonstrator for help if you do not understand how to do this.
54 Introduction to the C Programming Language Revision 5.1
Exercise 2.12: Adding User Control of Key
The next step is to allow the user to choose the key in which the piece is played. You should do this by showing the user a menu a list of possible keys. Next to each choice you should indicate which keyboard key the user will need to press in order to select the musical key for the piece.
You may like to choose keys on the keyboard whose layout most closely resembles a standard piano style keyboard.
This choice should be caseinsensitive, i.e. r and R should be treated the same. You will probably want to use a switch statement for this. You should use the default clause to watch for invalid input from the user. If the user presses an invalid key you should display an error message and not play the tune.
2.10 Summary
Now that you have completed this lab you should have the ability to write conditional statements in C. You should have learnt about, and be able to use:
if statements;
switch statements.
You should be able to form relational expressions, including quite complex containing with logical op erators.
You should understand switch statements and the way in which the flow of execution passes through them, including the reason for break statements.
You should also be able to obtain input from the user of your program. You should know how to use: scanf to get a complete line of input from the user at one time until the user presses Enter;
getch to obtain a single key press.
In the music and graphics options you should have used these functions to provide various options to the user of your program. You should have used conditional statements to process the options and to make sure that none of the input is invalid.
Laboratory 3
Repetition and Iteration do, while
and for 3.1 Overview
This laboratory will introduce you to three ways of repeating parts of your program:
the while loop repeats a part of your program whilst and providing a condition is true;
the do…while loop also repeats a part of your program whilst a condition is true, but it will always execute that part of your program at least once;
the for loop is a convenient way to repeat a part of your program with a built in counter.
You should learn how to use these repetition structures, and which is the most appropriate for a given
situation.
The graphics and music options allow you to use these new structures for carrying out repetitive tasks that would be difficult without loop structures.
3.2 Repeating Statements Many Times
It is often necessary to repeat parts of your program many times. Sometimes you will know exactly how many times this will happen, and other times you will not. In C, structures that repeat many statements are often referred to as repetition structures, loop structures or just loops.
The most basic way to repeat a single statement lots of times is to use a while loop. A while loop executes a single statement over and over again as long as a relational expression just like the ones you used in if statements is true. while loops look like this:
while relational expression statement;
Just like with if statements you will often want to put lots of statements inside a while. To do this you should use a compound statement in place of the single statement underneath the while clause. This is what has been done in the lab3 example. Open the clab project, change the target to lab3, and open the source code lab3.c. Now try building and executing it.
The source code for lab3.c is shown below.
56 Introduction to the C Programming Language
Revision 5.1
include stdio.h
int mainvoid
Declare a variable to store an integer number
int numberentered;
Output some text to the user
printfEnter an integer number: ;
Wait for the user to enter a number and hit enter
Store the number in the numberentered variable
scanfd, numberentered;
Display all the numbers from the one entered
up to and including the number 10
while numberentered 10
printfdn, numberentered;
numberentered numberentered 1;
return 0;
You should find that this program asks you for a number and then displays all the numbers from the one you entered up to, and including, the number ten. If you enter a number greater than ten it doesnt display anything.
You will notice that in the example the while clause has a compound statement underneath, rather than a single statement. This allows us to repeat more than one statement.
Try stepping through the example program. Do you see how the execution point jumps backwards inside the compound statement underneath the while clause?
Make sure you understand how the example works before continuing. If you have any problems ask for help.
A program to demonstrate the use of the while statement
C Programming laboratory 3
Syntax: The while Loop
while relational expression statement;
The while structure allows you to repeat a single statement many times. The while statement will execute for as long as the relational expression is true. If you want to repeat or loop many statements, rather than just one, statement including the semicolon should be replaced by a compound statement just as with if to give:
while relational expression
…
Revision 5.1 Introduction to the C Programming Language 57
Exercise 3.1: Using a while Loop
Alter the lab3 program to display a sequence of numbers which starts with the number that the user entered, but which doubles with every number it displays. It should stop when it reaches or exceeds the square of the number the user entered.
Hint: you may need to introduce another integer variable.
Sometimes you know that you want to execute the statements inside a loop at least once. We can do this with a while loop by using a do clause. The do clause goes at the beginning of the loop and tells C that we are starting a loop, but that we dont want it to check the condition until the end. It works like this:
do
while relational expression;
A couple of really important things to note:
the loop will execute while the relational expression is true, not until it is true, this is a very easy mistake to make;
there is a semicolon at the end of the while clause in a do…while loop.
You will probably find that do…while loops are more useful than plain ordinary while loops, be cause you usually want a part of your program to execute at least once.
…
Syntax: The do…while Structure
do statement; while relational expression;
The do…while loop is very similar to a while loop see above, except that the condition that is checked to determine whether the loop should continue relational expression is checked at the bottom of the loop rather than the top. This means that the statement inside the loop will always execute at least once. As in the case of the while loop, it is common to replace statement and its semicolon with a compound statement.
Exercise 3.2: Using do…while for Validation
In the last laboratory you used if statements for user input validation i.e. checking that user input was valid. If the user entered an invalid number your program simply ended. It would be better if it told the user that the number was invalid.
Edit the code you have produced in the first exercise of this lab to prevent the user typing in a number greater than 100 or less than 1. If the user enters an invalid number the program should tell them why the number they entered was not accepted. It should then ask them for a number again. It should repeat the process of asking for a number until the user gives a valid input.
You should find that a do…while loop is very useful for this purpose.
58 Introduction to the C Programming Language Revision 5.1 3.3 Repeating Statements and Counting
There are many occasions when it is useful to have a loop which is controlled by a variable which counts the number of loops or iterations. The for loop exists in C for this purpose. The code below is from the project lab3a. Change the target to lab3a and open lab3a.c in the editor. You will probbaly notice that lab3a is nearly identical to lab3 except that it uses a for loop instead of a while loop. It also declares an extra variable, count, to use as a counter in the for loop.
Try compiling and stepping through lab3a.
include stdio.h
int mainvoid
Declare a variable to store an integer number
int numberentered;
Declare a counter variable
int count;
Output some text to the user
printfEnter an integer number: ;
Wait for the user to enter a number and hit enter
Store the number in the numberentered variable
scanfd, numberentered;
Display all the numbers from the one entered
up to and including the number 10
for count numberentered; count 10; count
printfdn, count;
return 0;
At the beginning of a for loop, after the keyword for, is a set of parentheses with three statements inside. You can understand how these statements work by noticing that any for loop can be written as a while loop. In general, the for loop:
for statement1; statement2; statement3 statement to loop;
can be written as an equivalent while loop like this
statement1;
while statement2
statement to loop;
statement3;
A program to demonstrate the use of the for statement
C Programming laboratory 3
Revision 5.1 Introduction to the C Programming Language 59 To help this make sense, lets look at the example in lab3a. The for loop is:
for count number entered; count 10; count printfdn, count;
We can translate this directly to a while loop. It then becomes:
count number entered; while count 10
printfdn, count;
count;
which is very similar to the kinds of while loops that you have already seen and created for yourself, except for the line
count;
This line uses an operator you have not seen before called the postincrement operator. This is one of a number of shorthand operators in C. The shorthand operators just make it easier to type and describe commonly used operations. The postincrement operator:
variable;
is equivalent to:
variable variable 1;
i.e. the postincrement operator simply adds one to a variable. There is another way of writing the add one to a variable operation: the preincrement operator. The preincrement operator is used like this:
variable;
When used on its own like this there is no difference between the pre and postincrement operators. The difference between the two increment operators only becomes clear when you try and use an incre ment operator at the same time as doing something else.
60 Introduction to the C Programming Language Revision 5.1
Exercise 3.3: Understanding Pre and PostIncrement Operators
Temporarily add the following two lines of code to the end of the lab3a source code
count 5;
printfcount dn, count;
Rebuild the project and try stepping through the code. What value is displayed on the screen? What is the value of count after the printf line has executed?
Replace the postincrement operator with a preincrement operator so that the lines read
count 5;
printfcount dn, count;
How is that different? You can remove these lines of code from the lab3a project when you have finished investigating them.
The increment operators are often useful for writing more compact C code. They are most often used in for loops, but can be used in many other places. You should take great care when using shorthand operators as sometimes they make the purpose of code a lot less clear when it is read.
Exercise 3.4: A Simple for Loop
Edit lab3a to create a program which always counts up from zero, up to the number that the user entered. You should only need to make very small changes to the lab3a code. If you do not understand how to do this, ask one of the demonstrators for help.
Revision 5.1 Introduction to the C Programming Language 61
Syntax: Shorthand Operators
C specifies a set of shorthand operators that allow you to write more compact C code. They are often especially useful in loops.
The most useful of these operators in loops are the pre and postincrement and decrement operators:
variable; variable; variable; variable;
The increment operator, , is equivalent to adding one to a variable. The decrement operator, , is equivalent to subtracting one from a variable. The value of a postincremented expression is the value of the variable before it is incremented. The value of a preincremented expression is the value of the variable after it is incremented. The same applies to the decrement operator.
Other shorthand operators are more straight forward
variable1 variable2 is equivalent to
variable1 variable1 variable2
variable1 variable2 is equivalent to
variable1 variable1 variable2
variable1 variable2 is equivalent to
variable1 variable1 variable2
variable1 variable2 is equivalent to
variable1 variable1 variable2 So, for example
count 5;
is directly equivalent to
count count 5;
Exercise 3.5: Using a for Loop: A More Advanced Problem
Alter the lab3a source code so that, after the user has entered a number, the program responds by displaying the factorial x! of the number that the user entered. You should find that a for loop is the best way to do this. Make sure your code still works if the user enters a number less than 1.
Hint: A factorial is the product of an integer and all positive, integers below it. e.g. 5! 5 4 3 21 120
If you dont understand how to do this ask for help.
62 Introduction to the C Programming Language Revision 5.1 3.4 Deciding What Kind of Loop to Use
There are no hard and fast rules as to what kind of loop you should use in a given situation. Here are some guidelines to help you to make a decision when designing and coding your own programs. You should refer back to this list in later labs, whenever you are not sure what type of loop to use.
In general, the for loop tends to be the neatest and easiest to read loop when you have some kind of counter variable. Even if the counter is not simply counting up it could be counting down, or in steps of 2 etc. The for loop is also an obvious choice when you know, in advance, how many times the loop should be executed.
If your code does not neatly fit into a for loop, you probably want a while loop. If the condition at the top of the while loop is not met the first time, the loop will not execute at all. Quite often this behaviour is exactly what you want.
Youshouldusedo…whileloopwhenyouthinkawhileloopisappropriateandyouarecertain that you always want the loop to execute at least once.
3.5 Graphics Option
We are going to add to your graphics1 program to allow your stick person to throw an object. The graphical display will show the path of the object. It should look something like this
First we will have a brief look at the mathematics we need to describe the path of an object. Once we have the maths we will write some C to carry out the required calculations and plot the results.
We will begin by assuming that there is no air resistance. The initial velocity of the object as it comes out of the stick persons hand can be resolved into horizontal and vertical velocities. These act along the x and yaxes respectively. The only force acting in our simple world is that of gravity. Therefore, there are no forces acting in the xdirection and the horizontal velocity will remain constant. There is one force in the ydirection: gravity. The position in graphics coordinates of our object is:
where
Px Px0 Vxt
Py Py0 Vyt gt22
3.1 3.2
Px, Py is the current position of the object;
Px0, Py0 was the initial position of the object;
Vx was the velocity with which the object was thrown, in the xdirection in ms1; Vy was the velocity with which the object was thrown, in the ydirection in ms1; g is the gravitational pull 9.81ms2;
t is the time in seconds.
For simplicity we will treat each pixel in the graphics window to be a metre wide, just for the purpose of these equations. The exact scale relationship between the graphics window and reality is not important.
We must now think about how these equations should be translated into a C program. The best way to get a good graphical output is to find the height of the projectile in graphics ycoordinates for every xposition. For example, the following code would work
time posx initialposx velx;
posy initialposy vely time gravity time time2;
Revision 5.1 Introduction to the C Programming Language 63
You should be able to see that the first line works out what the current time must be since the throw, using the current xposition. This line is a simple rearrangement of equation ??. Make sure that you un derstand this rearrangement before continuing. The second line is simply equation ??. To keep accuracy in all of these calculations we must declare some of the variables as being of double type i.e. they may contain realvalued numbers.
We will be drawing the path of the object in the graphics window. Rather than try and draw a curved line, we will construct a curve out of lots of very small straight lines. There are two useful graphics functions which we are going to use for drawing the path of the object. The first allows us to give the graphics system a current location. The function call
moveto100, 300;
does not draw anything in the graphics window. It simply tells the graphics system that we wish to set the location 100, 300 to be our current location. We can then use the lineto function. The function call
lineto200, 350, 3;
draws a line in the graphics window from wherever the current location is to the coordinates specified, in this case the coordinates 200, 350. The line thickness used is given by the third parameter. It then sets the current location to be 200, 350 ready for us to use lineto all over again.
Function Reference: moveto Sets the current graphics location movetox position, y position
e.g.
moveto100, 200;
The graphics system keeps track of a current position, which will be used by functions like lineto. The moveto function allows you to set this current position. When you call the moveto the current position is set to the value x position, y position in graphics window coordinates. Both of these values should be integers.
moveto is defined in graphics lib.h.
64 Introduction to the C Programming Language Revision 5.1
Function Reference: lineto Draws a line from the current location to the specified location
linetox position, y position, thickness e.g.
lineto150, 250, 5;
The graphics system keeps track of a current position, which can be set by the moveto function. The lineto function draws a line of a specified thickness in the graphics window from the coordinates specified by the current position to the coordinates x position, y position. These values must be integers. Once the lineto function has drawn the line it sets the current position to be the end of the line it has drawn i.e. to coordinates x position, y position. The next time you call lineto it will draw from this point.
lineto is defined in graphics lib.h.
If you use the C code we have just looked at to calculate the yposition of the object for a given xposition, we can use the lineto function for joining these points together with graphical lines. In a moment you are going to do this, but first a couple of hints.
You should use a loop to work through all the xcoordinates that you need to. Before the loop you should use moveto to set the current location, you can then use lineto inside the loop to draw all the lines that will make up the path of the object. A suitable do…while loop would look something like this
movetoinitialposx, initialposy;
do
while posx ??;
You will notice that part of the while condition from this loop is missing where the ??? is. You will have to think about this for yourself. You should also be aware that moveto and lineto functions are expecting integer numbers of type int as arguments. If your variables are of type double they have to be converted by putting intbefore the variables that are arguments to these functions. The conversion between double and int types is built in to C and is called a type cast. You can see a type cast being carried out in the assignment statement for pos y.
time posx initialposx velx;
posy intinitialposy vely time gravity time time2;
linetoposx, posy;
posx;
Revision 5.1 Introduction to the C Programming Language 65
Exercise 3.6: Drawing the Projectile Path
Using the information and hints you have been given, add to your graphics1 project to draw the path of an object thrown from the stick persons hand. The object path must not go underground. If you use the standard value for gravity 9.81ms2 you might find that an initial velocity of 60ms1 is suitable for both x and ydirections. The code you produce should work whatever horizontal location the user chooses for the stick person. You should ask the user for the initial velocity of the object. The same initial velocity should be used for both vertical and horizontal components.
Hint: If you really get stuck, have a look at the source code graphics2.c . It should help you. If you still do not understand how to do this, ask one of the demonstrators for help.
Exercise 3.7: Allowing the Stick Person to Move
Use a getch function call to wait for the user to press the Enter key before drawing the path of the object. This should happen after the stick person has appeared in the graphics window you may need to look back at the script for laboratory ?? to find the key value for Enter.
Remove the option at the beginning of the program for the user to choose the horizontal location of the stick person. Let the user move the stick person before they hit Enter using the left and right arrow keys. To make the stick person appear to move you should either draw over the top of the stick person with another stick person made up of black lines, or more simply draw a filled rectangle see below that covers over the stick man. This will erase the stick person from the screen. You can then redraw the stick person in a new position using coloured lines.
Here is the function that will draw filled rectangles:
Function Reference: filled rectangle Draws a filled rectangle in the graphics window
filled rectanglexupperleft, yupperleft, xlowerright, ylowerright,fillcolour;
The filled rectangle function draws a rectangle in the colour specified by fillcolour. The rectangle will have its upper left and lower left points at the position specified by xupperleft, yupperleft, xlowerright, ylowerright respectively. For example
filledrectangle10, 10, 40, 60, LIGHTCYAN;
will draw a filled rectangle in a light cyan colour with its upper left coordinates 10, 10 and lower right coordinates 40, 60.
filled rectangle is defined in graphics lib.h.
For reference there is also an unfilled rectangle drawing function defined below:
66 Introduction to the C Programming Language Revision 5.1
Function Reference: rectangle Draws an outlined rectangle in the graphics window
rectanglexupperleft, yupperleft, xlowerright, ylowerright,thickness;
The rectangle function draws a rectangle in the default colour set by the setcolor function in the graphics window with perimeter line thickness specified by thickness. The rectangle will have its upper left and lower left points at the position specified by xupperleft, yupperleft, xlowerright, ylowerright respectively. For example
rectangle10, 10, 40, 60, 5;
will draw an outlined rectangle with its upper left coordinates 10, 10 and lower right coordinates 40, 60 using a pen thickness of 5 pixels.
rectangle is defined in graphics lib.h.
Exercise 3.8: Giving the User Three Goes
The program you have now should allow the user to choose the initial velocity of the object. It should then display the stick person and allow them to use the arrow keys to move the stick person. The program then waits for the user to press Enter before it plots the path of the projectile. After the object has been thrown the program waits for a key press and then exits. You should alter this process so that after this last key press the program allows the user to have another go, providing they have not already had three goes. You should close the graphics window and reopen it for each go.
Hint: You will have to put almost all of the code you already have inside another for loop to get this to work.
3.6 Music Option 3.6.1 Simple Scales
Repetition is very important in music. We are going to use loops to generate simple scales and use them to attempt to construct music in a minimalist style, similar to that used by composers such as Steve Reich, Terry Riley and Philip Glass. The program music2 plays one octave of a chromatic scale starting on middleC. Change the target to music2 and open the source code music2.c in the editor.
Revision 5.1 Introduction to the C Programming Language 67 The source code for music2.c is shown below.
A program to demonstrate a simple chromatic scale
C Programming laboratory 3
include midilib.h
int mainvoid
Declare integer variables for specifying a note
int pitch, channel, velocity, offset;
Set the pitch variable to 60, which is middle C
pitch 60;
We will play the note on MIDI channel 1
channel 1;
The note will have a medium velocity volume
velocity 64;
initialize the midi functions
midistart;
Play an octaves worth of chromatic scale
for offset 0; offset 12; offset
Start playing a note
midinotepitch offset, channel, velocity;
Wait, so that we can hear the note playing
pause400;
Turn the note off
midinotepitch offset, channel, 0;
close down all midi functions
midiclose;
return 0;
Try compiling and running the program. Does it sound how you expected it to sound? Make sure you understand the for loop before continuing.
Exercise 3.9: Adding to the Chromatic Example
Add to the music2 code to make it complete two octaves of ascending chromatic scale before descending back down chromatically to the starting note.
68 Introduction to the C Programming Language Revision 5.1 3.6.2 Whole Tone Scales
A whole tone scale ascends in steps of whole tones, in MIDI note numbers this is increments of two. Composers like Debussy used whole tone scales to create a smooth, dreamy effect, which is often used in films to denote misty or underwater scenes.
Exercise 3.10: Playing a Whole Tone Scale
Alter the code you have just created to play two octaves of ascending then descending whole tone scale.
Exercise 3.11: Using Whole Tone Scales
By altering the code you have just created, produce a program which plays:
four notes of a whole tone scale ascending, four times; followed by
five notes of the same whole tone scale, ascending from the same starting note four times; followed by
sixnotesofthesamewholetonescaleinasimilarmanneraspreviously,fourtimes;followed by
seven notes of the same whole tone scale, four times.
Finally the last whole tone scale should be played in descending order to complete the piece.
You will need to put one for loop inside another to get this to work. Putting one programming structure inside another is called nesting.
If you do not understand how to do this, ask one of the demonstrators for help.
3.6.3 Adding to Your Whole Tone Scale Piece
You can hear the patterns in this piece but it probably doesnt sound very musical. One reason for this is that there is no properly defined rhythmic structure; there is no sense of where the barlines might be.
Exercise 3.12: Making the Piece Sound More Musical
Without destroying your nested for loop structure, alter your code so that each ascending scale takes the same amount of time, no matter how many notes are going to be played. You will need to calculate the note durations inside the loop.
What other changes can you make to try and make the piece more musical? Can you make the second and fourth scale in each set quieter than the first and the third without changing the for loop structure?
Revision 5.1 Introduction to the C Programming Language 69
Exercise 3.13: Adding DroneTones for Depth
The next step is to add some depth to your piece by allowing one or more dronetones to play in the background. You might like to change the tone that is used during the piece. You could do this once or even at the beginning of each set of scales.
You might choose to play the tones on a different channel and instrument to the scales.
3.6.4 Playing Until Told to Stop
The kbhit function allows you to find out whether the user has pressed a key on the keyboard. You use it like this
int variable kbhit;
If the int variable has the value 0 after this function call then no key has been pressed. You can use the kbhit function to repeat a part of your program until a key is pressed. For example the following do…while loop will execute the statements inside it until a key is pressed.
do
while kbhit 0;
It is very important to note that because the kbhit function is called at the end of every loop to check if
a key has been pressed, this loop will always execute a whole number of times.
…
Function Reference: kbhit Checks to see if a key has been pressed int variable kbhit;
The kbhit function tells you whether a key has been pressed. It will return the value 1 if a key has been pressed, or the value 0 if no key has been pressed. This value will be assigned to the int variable if it is present. The kbhit function does not wait for a key press. You can retrieve a number identifying what key was pressed using the getch if kbhit returned 1.
kbhit is defined in conio.h
To use kbhit you should make sure that the line include conio.h
is at the top of your source file.
70 Introduction to the C Programming Language Revision 5.1
Exercise 3.14: Repeating Until a Key Is Pressed
Alter your program to play the four sets of ascending whole tone scales repeatedly until the user presses a key. When the key is pressed the program should finish its current group of four sets of scales and then finish with the descending scale. You might like to add to the code which executes after the key is pressed to give the piece more of a finale.
3.7 Summary
Now that you have completed this lab you should have the ability to use three kinds of repetition structure:
while loops;
do…while loops; for loops.
You should also be able to decide which of these types of loop is appropriate in a given situation.
If you completed the graphics option you should have made some major changes to your graphics program which allow your stick person to throw an object. The path of the object should appear in the graphics window. The user should be able to move the stick person left and right using the arrow keys and should have three goes at throwing an object.
If you completed the music option you should have investigated how to use loops to generate scales. You should have put together a piece built on repetition of simple whole tone scales with drone tones in the background. You should also have learned how to detect when the user has pressed a key and used this to allow the user to choose when your program should stop.
Laboratory 4 Functions
4.1 Overview
This laboratory will give you the capability to create your own functions, and help you better under stand how existing functions are defined and called. You will learn about:
how to define functions of your own;
how to specify parameters so that you can pass values to your own functions;
how to allow your functions to return a value back to the place where they were called from; how and, most importantly, why you should use functions to split up your programs.
You will also be introduced to the fflush function, which you will use to make sure that scanf handles user input better.
Some standard C mathematical functions are introduced, which you might find useful in your own programs.
In the graphics and music options you will make use of functions to make your programs more readable and more powerful. In the graphics option you will add the capability for the user to choose the launch angle for the object. In the music option you will be introduced to the random number program which you will use to try and create a program which improvises.
4.2 Creating New Functions
In most of the example programs you have seen and created so far, you have used functions a great deal. Most of the time you have used called existing functions such as printf and getch. However, every program you have written has contained exactly one function of your own: main. In this lab you will see how to write other functions, which you can call in exactly the same way as printf, getch and others.
Open the clab project and make sure the target is lab4 project and open lab4.c in the editor. This project will introduce two new concepts:
creating new functions of your own, and calling them;
using the fflush function to handle bad input from the user when using the scanf function.
The source code of lab4.c is:
72 Introduction to the C Programming Language
Revision 5.1
include stdio.h
displaywelcome function displays a welcome message
The displaywelcome function takes no parameters and
does not return anything.
void displaywelcomevoid
printfWelcome to the squaring numbers programnn;
square function squares an integer number
The square function takes a single integer
parameter. It returns an integer which is the square
of the value of the parameter it was given.
int squareint value
int squaredvalue;
squaredvalue value value;
return squaredvalue;
The main function the program starts executing here
The main function takes no parameters and returns an
integer.
A program to demonstrate function creation
C Programming laboratory 4
Revision 5.1 Introduction to the C Programming Language 73
int mainvoid
int numplaceholdersmatched;
int numberentered, squarednumber;
Call the displaywelcome function
This will display a welcome message
displaywelcome;
Obtain a number from the user
printfPlease enter an integer number: ;
Loop for as long as the user gives us values
that arent integers
do
Call scanf and use the return value to find out
how many placeholders were matched
numplaceholdersmatched scanfd, numberentered;
The integer placeholder was not matched
if numplaceholdersmatched 1
Clear out whatever the user typed
fflushstdin;
Tell the user to try again, loop will go again
printfThat was not an integer. Please try again: ;
while numplaceholdersmatched 1;
Square the number using the square function
squarednumber squarenumberentered;
Display the result
printfd squared is dn, numberentered, squarednumber;
return 0;
All the programs you have seen so far have started with the main function. This program is no different, its just that there are two other functions included in the source code before the main function. These two functions are called display welcome and square.
The first thing that the main function does is to call the display welcome function, which it does with this line:
displaywelcome;
You will notice that no arguments are specified as part of this function call there is nothing between the parentheses.
The next part of the main function obtains an integer from the user using the scanf function. It is more complicated than the way you have used scanf before because it checks to see whether the user actually entered a valid integer.
When the user types in a response the scanf checks what they typed against the placeholder, it could either be
74 Introduction to the C Programming Language Revision 5.1 a valid integer, in which case the scanf function has a return value of 1;
something else, in which case the scanf function has a return value of zero;
This return is the number of placeholders that were matched with the text the user entered. The return
value is assigned to the variable called num placeholders matched.
But what happens if the user doesnt type in a valid integer? To answer this question we must look at
the way scanf works.
When you type in characters on the keyboard they get stored in a special variable in the stdio library.
This variable is called an input buffer.
When you call scanf the first time the input buffer is empty, because you havent typed anything yet. Because the buffer is empty, scanf waits for you to type in characters and press Enter.
When you have pressed enter it checks to see what is in the input buffer. It then tries to interpret the characters in the input buffer, in away that matches the placeholder you specified. So for example. Say you called scanf and you wanted an integer, so you specified a placeholder of d.
If the characters in the input buffer match the type that is required by the placeholder then it takes them out of the input buffer.
The scanf call will then have a return value of 1, because it matched one placeholder.
If, on the other hand, the text does not match the placeholder, scanf leaves the characters in the input
buffer.
This is a problem! If we call scanf again, the first thing it will do is to check the input buffer. It will find some text there already so it will not wait for the user to type in more text.
To get the next call to scanf to work properly, we have to clear out, or flush the input buffer. We do that by calling the function fflush, like this:
fflushstdin;
This tells the stdio library to clear out flush whatever it has in its input buffer. The name stdin is the name of input buffer which receives input from the keyboard. stdin is short for standard input and the variable is defined in stdio.h. There are other buffers that are used in this way. In general these buffer variables are called streams.
Revision 5.1 Introduction to the C Programming Language 75
Function Reference: fflush Flushes a stream fflushstream
e.g.
fflushstdin;
Clears a buffer identified by stream that is being used for input or output. The most common usage of fflush is to make sure that the input buffer is emptied after a scanf call which had unmatched placeholders. In this case the return value of scanf would be tested to determine how many placeholders were matched. If scanf did not manage to match all of its placeholders than there will still be characters left in the input buffer. In this situation fflush should be called to remove unmatched input from the buffer.
There are three predefined streams which may be used with fflush:
stdin the standard input stream, usually the keyboard;
stdout the standard output stream, usually the screen;
stderr the standard output stream especially for error messages this is also usually the screen.
fflush, stdin, stdout and stderr are defined in stdio.h
The next line in the main function after the end of the while loop is another function call: result squaren;
This line calls the square function passing it the value of the argument n. The square function has a return value which is equal to the square of the value of its argument, in this case the return value is assigned to the result variable.
The code before the main function defines the display welcome and squared functions. The follow ing code defines the display welcome function:
void displaywelcomevoid
printfWelcome to the squaring numbers programnn;
A C function is made up of two parts:
the first line is the function head and identifies the function. We will study this part in more detail in the next section.
the function body which is a set of statements enclosed in braces, in exactly the same way as a compound statement.
The following code defines the square function:
int squareint value
int squaredvalue;
squaredvalue value value;
76 Introduction to the C Programming Language Revision 5.1 return squaredvalue;
Exercise 4.1: Investigating Functions
Step through the lab4 program in the debugger. Make sure you use the step into shift F7 key
feature to move the execution point into the functions when they are called.
What happens to the variables defined in main when the execution point is inside the body of
display welcome?
What about when the execution point is inside the body of squared?
What variables are available when the execution point is inside these functions?
If you do not understand how to step into the display welcome and square functions, ask one of the demonstrators.
You should find that any variables defined in the body of the main function are not available in other functions. When the point of execution is in the square function, there is one variable available squared value. Variables defined inside the body of a function are known as local variables because they are local to the body of the function. The section of the program in which a variable is valid i.e. the function body that contains it is known as the variables scope.
Exercise 4.2: scanf Input Validation
The code which surrounds the scanf function the code inside the while loop validates the user input to make sure it is of the correct type. Try running the lab4 program and typing in text instead of a number. What happens?
Try stepping through the program in the debugger and give the program the same input. Make sure you understand how the program works before continuing. If you need any help, ask one of the demonstrators.
4.3 Anatomy of a Function
We are now going to look at how a function head is constructed so that you can define functions of your own. There were two functions defined in lab4: display welcome and square. The function head for display welcome looked like this:
void displaywelcomevoid
void is a type, like int and double, except that its main use is in function declarations. In this context
void means nothing. You can see from this line that function heads are made up of three parts:
type of return value function name parameter list
We do not need the display welcome to return a value, so we specify its return type as void. We do not need any extra information for the function to work i.e. when the function is called there is no need to specify any arguments. So we put void in the parentheses after the function name.
When the main function called the display welcome function, it did it like this:
Revision 5.1 Introduction to the C Programming Language 77 displaywelcome;
You can see from this line that there was no return value to assign to variable, and no arguments were specified. This matches the function head for display welcome.
The square function is a bit different. The function head looked like this:
int squareint value
This function head declares the square function to return a value of type int and to require it to be called with one argument of type int. When the argument reaches the function it is given a name: value. It is then called a parameter. Parameters are very like variables, they have a type and a name. You can declare many parameters for a function in a list separated by commas. Each parameter in the list must have its own type. Parameters also have the same scope as a local variable declared in that function. You can only use the parameter as a variable inside the function body.
When a function is called there must be an argument for each parameter in the function head. The values of the arguments specified in a function call are copied into the parameters before the execution point enters the function body. The values are copied in order i.e. each argument is matched with a parameter, in order.
When the square function was called, it looked like this: squarednumber squarenumberentered;
Before the execution point represented by the yellow arrow in the debugger moves into the square function, the value of the number entered variable is copied into the value parameter specified in the square function head.
When the square function has finished everything it needs to do it uses the return statement, speci fying a value to return. The type of this value must match the return type specified in the function head. square uses the return statement to return the value of an integer variable like this:
return squaredvalue;
The value of the squared value variable is returned to main and assigned to the squared number
variable.
When a function defines a return type, like in the case of the square function or the getch function, this does not mean that you must assign the result to a variable. You dont have to. For example:
key getch;
calls the getch function, which waits for a key press, and when the function returns it assigns the result
the code for the key that was pressed to the key variable. You could also call getch like this: getch;
In this case, the getch function is still called, and it still returns a value, but the compiler throws that value away because you have not assigned it to a variable. In this case the getch function will still wait for a key press and return the value of key that was pressed. However, that value will be discarded because no assignment was specified.
78 Introduction to the C Programming Language Revision 5.1
Syntax: Function Definitions
return type function name parameter list or void
…
A function definition declares the name of a function function name and associates with it a return type which may be void and a parameter list which may also be specified as void. Specifying the return type as void indicates that the function will not be returning a value. Spec ifying void in place of the parameter list indicates that the function should not be called with any arguments.
A parameter list has the following syntax: type name, type namen
For example:
int param1, double param2
int param1, int param2, int param3
Each parameter has a name and a type. Note that even if the types of subsequent parameters are the same they must still be specified explicitly.
Exercise 4.3: Investigating Function Types
Alter lab4.c to use doubles instead of integer values. You will need to think about:
the square function head;
the variables in main;
the placeholders used by the scanf and printf functions; the message displayed to the user.
Compile and run your program to check that it works. Make sure that it works with noninteger values and that it still handles invalid text input correctly.
Revision 5.1 Introduction to the C Programming Language 79
Exercise 4.4: Transferring Code into a Function
You are now going to move the input code the while loop with all of its contents into a separate function. You should call the function get double.
Make sure you can answer the following questions before you start typing:
What should the return type of the function be? How many parameters does the function need? How do you want to be able to call the function?
You should end up with a program with four functions including main. The main function should be quite short. In general, it is good programming practice to try and keep your main function short as it makes your program more readable. Build and execute your program and test it several times to make sure that it works.
If you do not understand how to do this, ask one of the demonstrators.
4.4 Functions: Why Bother?
Why did you move the input handling code into a separate function in exercise ??? One answer is that it made a very important part of your program, the main function, more readable. Readability is something that you as a programmer should be very worried about. As a general rule, programs are read about 10 times more often than they are written. When you come to write bigger programs, you will need to be able to glance back over code that you have written previously and still understand how it works.
If a program is being designed and written by more than one person, as is usually the case in industry, the problem becomes even greater. One software engineers code may be read by many others who need to understand what it does easily and quickly. Software may also be used or updated by people other than those who wrote it. This is especially common in industry and can be a real problem.
So, making code more readable is one good reason for functions. However, perhaps the most important reason for functions is that once youve turned a piece of code into a function you can use it as a building block. Just as you have been doing with printf, for example. Functions do two things which make them powerful building blocks:
they hide all the complicated workings of the program and present a simple interface in the form of a function call. You do not have to know how a function works in order to be able to use it. In software engineering, this is called encapsulation.
they allow you to use parts of your program many times without having to retype the same bits of code. Logically enough, this is called code reuse.
If you choose the names of you functions wisely then what they do should be fairly clear just from looking at a function call. This will make your programs easier for you to write and debug. Carefully crafted functions have the potential to be used more than once in a program, which saves you effort. Or you could copy and paste a function out of one program and into another if you think it will be useful.
As an example, the get double function you have just written is very useful. It gets a double value from a user and does some input validation. There are likely to be many times in the following labs, and in the assignments, when you need to get a value in this way. You might find it useful to reuse the function by copying it and pasting it into a different program. You can only do this so easily because it is a separate function.
80 Introduction to the C Programming Language Revision 5.1 4.5 Positioning Functions in a File
In the example program you have just modified, the functions display welcome, square and get double were defined before the main function.
When a compiler is turning your source code into machine code, it reads it in order. When it reaches a function call it will try and associate it with a function that it already knows something about. If it doesnt know anything about the function yet it has two options:
make some assumptions about the information it doesnt know and continue assuming that the assumptions are correct;
throw its hands up in the air and stop.
In most cases compilers choose the first of these options even though the second would cause fewer problems. If the compiler subsequently finds some actual information about the function it usually discovers that the information it assumed was wrong, which causes another problem.
The only information the compiler needs to know about a function to allow you to call it is:
what arguments the function takes and what their types should be; what the return type of the function is.
These two pieces of information are both contained in the function head.
C provides a way to declare just the head of a function so that you can use it before you define the body of the function. This allows you to put the function definition the combination of the head and the body below the place where it is called in the source code. Declaring just the head of a function on its own is called a prototype. It should be exactly the same as the head of the function, but with a semicolon at the end. It should be placed outside of any other function.
For example, a prototype for the square function would look like this:
int squareint value;
Note the semicolon on the end of the line. Because the compiler only needs to know the types of param eters in the parameter list their names dont really matter at this stage you can miss the names out, like this:
int squareint;
A prototype like this would usually be placed somewhere near the top of the file, just after any include lines.
Exercise 4.5: Changing the Order of Functions in a File
Move the get double function so that it is defined underneath main. You could use Edit Cut and Edit Paste for this. Try building the project. What errorswarnings do you get? Why do you think there is a problem with putting functions in this order?
Revision 5.1 Introduction to the C Programming Language 81
Exercise 4.6: Using Prototypes to Change the Order of Your Functions
Declare prototypes for all of your functions, except main. Move the order of functions in your file so that main is above the other functions. You might like to try and put the functions in some kind of logical order.
If you dont understand how to do this, or if you are still getting errors or warnings when you try to build your code, ask for help.
In the same way that a prototype is all the compiler needs to know about a function, a prototype is also all the programmer needs to know about a function. From this point on the laboratory scripts will use prototypes to define functions in function reference boxes.
Function Reference: Change to Function Boxes
From this point on, functions will be described using their prototype like this:
int getchvoid;
Rather than using the syntaxtype method used up to this point, which has looked like this:
character getch;
4.6 The Maths Function Library
So far, on this course, you have been introduced to a number of different functions that are part of the C standard library. This have been functions defined in stdio.h and conio.h. You are now going to use some mathematical functions, defined in math.h.
You have already written your own function for squaring numbers. math.h defines a square root func tion called sqrt. It also defines trigonometric functions sin, cos, tan, inverse trigonometric func tions asin, acos, atan and many more. You will find full documentation for all of the available mathematical functions in a book on C, or on the internet. Some suggestions for reading are given in Appendix ??, you will also have been given some suggestions for reading in the lectures. This section introduces some useful maths functions that you may need during the rest of the course.
Function Reference: sqrt Calculates the square root of a number double sqrtdouble;
The square root function takes one argument, a value of type double, and returns another double value which is equal to the square root of the argument.
sqrt is defined in math.h
82 Introduction to the C Programming Language Revision 5.1
Function Reference: pow Raises one number to the power of another number double powdouble x, double y;
The pow function raises the first argument to the power of the second argument and returns the result i.e. xy. For example:
result pow2, 3;
would assign the value 8 to the variable result. pow is defined in math.h
Function Reference: sin,cos,tan Trigonometric functions
double sindouble;
double cosdouble;
double tandouble;
The sin, cos and tan functions take a single argument of type double, which is treated as an angle in radians 2 radians 360. Each function returns a double value:
sin returns the sine of the angle;
cos returns the cosine of the angle; tan returns the tangent of the angle.
sin, cos and tan are defined in math.h
Function Reference: asin,acos,atan Inverse Trigonometric functions
double asindouble;
double acosdouble;
double atandouble;
The asin, acos and atan functions take a single argument of type double. In the case of asin and acos this value should be in the range 1 to 1. The return value of each of these functions is an angle in radians 2 radians 360 represented as a value of type double.
asinx returns sin1x which will be in the range 2 to 2; acosx returns cos1x which will be in the range 2 to 2; asinx returns tan1x which will be in the range to ;
asin, acos and atan are defined in math.h
Revision 5.1 Introduction to the C Programming Language 83
Exercise 4.7: Calculating the Length of a Triangles Hypotenuse
Alter the lab4 program to prompt the user for two values. You should call your get double function twice to do this. Treat these two numbers as the lengths of two sides the opposite and adjacent sides of a rightangled triangle. Use the square and sqrt functions to calculate the length of the hypotenuse using the Pythagorean Theorem.
Remember to include the math.h header file.
4.7 Graphics Option
4.7.1 Creating More Manageable Code
Open the graphics1 program you have been working on in previous laboratories. Your graphics program should operate in the following way:
The user is asked for an initial velocity, which they type in.
The stick person appears on the screen and the user gets the opportunity to move the stick person left and right using the arrow keys.
When the user presses Enter the stick person throws an object which is drawn on the screen.
The user then has another two goes at this.
Your program is now getting quite large. To make it more convenient you should now split in into multiple functions.
Exercise 4.8: Splitting Your Program into Functions
Define suitable functions for:
drawing the stick person at any location on the screen. This function should have two param eters which specify the x and ycoordinate at which the stick person will be drawn. It should also take a parameter which specifies the colour in which the stick person should be drawn.
drawing the projectile path. This function should have two parameters which specify the start ing point for the projectile in screen coordinates.
Place these functions under the main function in your source file. You will need to define a prototype for each function.
If you do not know how to do this, ask for help.
4.7.2 Allowing Control of the Launch Angle
Currently the stick person always throws the object at 45 because the horizontal and vertical velocities are equal. You are now going to change the program so that the user can choose the launch angle of the object between 0 and 90. The velocity that the user specifies should be treated as the initial velocity of the object. This velocity needs to be resolved into horizontal and vertical components. These components can be calculated by treating the problem as a rightangled triangle:
84 Introduction to the C Programming Language Revision 5.1 The x and ycomponents can therefore be calculated using the sine and cosine of the launch angle, :
vx v cos 4.1 vy v sin 4.2
Exercise 4.9: Allowing the User to Choose the Launch Angle
Alter your program to allow the user to type in the launch angle, as well as the initial velocity, before the graphics window appears. The user should be able to specify an angle between 0 and 90, but not outside that range. Use the sin and cos functions from the maths library to resolve the velocity into horizontal and vertical components.
Remember that the maths library functions expect the angle to be in radians. You will need to convert the angle from degrees into radians.
4.7.3 Making Your Program More Visually Appealing
This section introduces three new graphics functions that you might find useful:
the cleardevice function clears any drawing you have done from the graphics window, just as if you had reopened the window;
the setbkcolor function which sets the current background colour;
the outtextxy function allows you to put text in the graphics window.
Function Reference: cleardevice Clears the contents of the graphics win dow
void cleardevicevoid;
The cleardevice function clears the graphics window of any contents. It fills the screen with the current background colour previously set using setbkcolor, and sets the current location which is used for things like lineto to 0,0.
cleardevice is defined in graphics lib.h.
Function Reference: setbkcolor Sets the background colour
void setbkcolorint colour;
The setbkcolor function sets the current background colour. It takes one argument which is the integer number which identifies the colour. You can use the same colour names as for setcolor, which are listed in the function box on page ??.
setbkcolor is defined in graphics lib.h.
Revision 5.1 Introduction to the C Programming Language 85
Function Reference: initfont Initializes the font for the outtextxy function void initfontvoid;
The initfont function sets up the font type used by outtextxy. It has no arguments. It uses the font defined in
datafixedfont.tga
. This font definition and others are in the data folder that is inside the clab folder. initfont is defined in graphics lib.h.
Function Reference: outtextxy Draws text in the graphics window
void outtextxyint x, int y, text;
The outtextxy function places the text in graphics window at the location specified by x and y. text should be enclosed in double quotes, in the same way as with printf. Unlike printf however, you cant use placeholders with outtextxy. The text is drawn in the current colour.
For example:
initfont;
outtextxy100, 250, Press Enter to Continue;
would display the text Press Enter to Continue starting at location 100, 250.
Important: You will notice that the prototype given above for the outtextxy function does not have a type for the third argument text. This is because we have not yet studied how to specify the type for variables containing text. We will cover this in the next laboratory.
outtextxy is defined in graphics lib.h.
Exercise 4.10: Using the New Graphics Functions
Now is your opportunity to use the new graphics functions cleardevice, setbkcolor and outtextxy together with initfont to add to your graphics program. You could:
use cleardevice to clear the graphics window in between each of the users throws instead of opening and closing the window;
use outtextxy to display helpful text for the user;
change the background colour to something other than black for the scene using
setbkcolor and cleardevice.
Add as much to your program as you can, using functions appropriately.
86 Introduction to the C Programming Language Revision 5.1 4.8 Music Option
Open your music2 program that have been working on in previous laboratories. Your program should play a simple piece constructed of whole tone scales with appropriate drone tones and dynamics. The piece should play until the user presses a key. By now your code will be getting quite large so the first thing we will do is to split it into functions to make the program more readable and to allow code reuse.
Exercise 4.11: Splitting Your Program into Functions
Define a function that produces a number of whole tone scales. The function should have parameters for:
the number of scales to play;
the pitch of the starting note in the scale; the number of notes in each scale;
the velocity to use for the scales.
You can add other parameters if you want. Place this function under the main function in your source file. You will need to define a prototype for the function.
Currently your program repeats the same sequence of scales until the user presses a key. We can make a music program more interesting by using randomness to try to create a program which improvises. C contains standard functions for producing random numbers, but they are not easy to use. The music library contains a much simpler random number function called random number.
Function Reference: random number Generates a random number
int random numberint lower range, int upper range;
The random number function returns a random number which could be anywhere in the range lower range to upper range, including the values lower range and upper range. For exam ple:
pitch randomnumber60, 71;
will assign a value to pitch that could be 60, 71 or any integer value inbetween. random number is defined in amio lib.h.
Exercise 4.12: Improvising with Whole Tone Scales
Using the function you have just written which plays whole tone scales, try to use the random number function to make your program improvise pieces of music based on whole tone scales. Drone tones and dynamics should also be improvised. How can you make it sound reason ably musical?
All the improvisation your program does at the moment is based on whole tone scales. Whole tone
Revision 5.1 Introduction to the C Programming Language 87
scales have an interesting effect, but their use can become quite constraining. You now have the chance to add to your program to make it insert passages of freer improvised melody inbetween sections of whole tone scales. This will all be based on random numbers.
Here are some things to think about:
you might like to control the lengths of the free and whole tone scales sections to enforce some kind of structure with recognisable phrasing;
you could use a random number to decide whether you are about to improvise a phrase based on whole tone scales, or completely random notes;
you should use random numbers to allow the program to make choices about pitch and note length for example, but you might want to place certain constraints on what it can do to make sure the results still sound musical.
you will have to be careful with the improvisation between the whole tone scale phrases to ensure that the piece does not become too disjointed.
Exercise 4.13: Adding to Your Improvisation Program
Create a separate function which chooses a note at random and plays it. You might like to call it random note. You should use this function to create the free phrases. You will need to think about what parameters the function needs so that you can control the random notes it produces. You might like to control and have parameters for:
the range in which the pitch can lie;
the velocity of the note;
the length of the note;
whether there is a rest before the note.
Improvising in this way is hard, but see how musical you can get it to sound. You might find that it is easier to produce a convincing piece if the tempo is kept fairly slow e.g. adagio.
4.9 Summary
In this laboratory you should have learned why functions are useful and how to create functions of your own. You should understand how to specify parameters and return values, and how to declare function prototypes so that you can choose the order in which functions are declared.
Function prototypes will be used in all function boxes from now on.
You should understand how to use the fflush function to control the way scanf works and to ensure that user input is validated correctly. In the second part of the lab you were introduced to some more mathematical functions which you might find useful.
In the graphics option you had to put your knowledge of functions into practice, and you improved your program to allow the user to choose the launch angle for the projectile. In the music option you were introduced to the random number function which you used to try to produce a program which improvises, and found out how hard it is to get it to sound musical!
88 Introduction to the C Programming Language Revision 5.1
Laboratory 5
Arrays and Strings
5.1 Overview
This laboratory introduces you to arrays which are a way to create a variable that has the capacity to store many values. Each of the values in the array can be accessed by using an index.
You will learn how to create and use arrays, and how to make sure that they are initialised with specific values when your program starts. You will also learn about multidimensional arrays which can be used to store data in a similar way to tables.
You have already been using text enclosed in quotation marks …. In this laboratory you will be learn more about these text or character strings, which are actually a special form of array. You will learn how to create and manipulate them.
In the graphics option you will make use of arrays to make your graphics program more like a computer game. In the music option you will find that arrays are very useful for defining musical relationships, like the pitch relationships between notes in a scale.
5.2 Introducing Arrays
The variables you have been working with so far are a bit like scalar values in maths. This laboratory is about arrays which are more like mathematical vectors.
Each variable you declare defines a space in the computers memory in which you can store one value of the correct type. We often show this as a diagram like this:
The variable declaration on the left is equivalent to the diagram on the right. In the diagram, the box represents the space in the computers memory in which the value of the variable is stored. In this case you can see that the box contains the value 20 to indicate that the variable is assigned the value 20. The text to the right of the box my integer identifies the name of the variable: it provides a name for that space in the computers memory.
Every variable you declare has a space in memory, and the name of that variable identifies the memory space. An array allows you to reserve more than one memory space for a single variable. All the memory spaces you reserve will have the same type for example int. When you use the variable you have to specify which one of the spaces you wish to access. Diagrammatically, an array looks like this:
This shows that one variable name identifies multiple spaces in the computers memory. These spaces are more properly called elements. To identify which element we are talking about we reference it by number. In C elements are numbered from zero. This element number is called a subscript or an index.
90 Introduction to the C Programming Language Revision 5.1 A subscript is placed after the variable name, in square brackets, like this: my array3. We can show
the way that subscripts work on a diagram:
Obviously the subscript must be an integer; it wouldnt make sense to ask for element number 2.3859. You declare an array by specifying how many elements you want in that array. For example:
int myarray4;
declares a new array variable called my array. Each element in the array contains an integer value. The array has four elements in it. Note that the last element is called my array3. Try to remember that when you are declaring an array, the number in the square brackets is the number of elements, not the subscript of the last element. The subscript of the last element will be the size of the array minus one.
Syntax: Array Declarations
type namesize , more variable delcarations n ; e.g.
int anintegerarray10;
double arealarray6;
int anintvariable, anintarray22;
Arrays are variables which have space for more than one value. The number of values that the array has space for is specified as a number in square brackets size.
When the array variable is used, an integer must be included specifying the index of the element which is being referenced. This index is called a subscript. Subscripts are numbered starting from zero. For example:
anintegerarray6
is the integer value which occupies the 7th element in the the array called an integer array.
5.3 Working with Arrays
You are now going to try using arrays in a program. The lab5 program uses arrays to collect informa tion. The program asks the user for the heights of up to ten people and then displays the mean height, calculated from the data that were entered. The heights that the user enters are stored in an array. It would be very difficult to produce a program like this without using arrays.
Open clab project and set the target to lab5. Try building and executing the program. Run it a few times to make sure you are familiar with what it does. The source code for lab5 is shown below.
include stdio.h
Function prototypes
A program to demonstrate arrays
C Programming laboratory 5
Revision 5.1 Introduction to the C Programming Language 91 void welcomemessagevoid;
double meandouble values, int numvalues;
Program starts here
int mainvoid
Declare an array which can store up to 10 doubles
double datavalues10;
Keep track of the number of items we have here
int numdatavalues;
Some other useful variables
int currdatavalue, done;
double meanheight;
Set initial conditions
numdatavalues 0;
done 0;
Display message to user
welcomemessage;
Loop to get all data values, stop when we have 10 values
Or when the user enters a zero height
for currdatavalue 0;
currdatavalue 10 done 0;
currdatavalue
Get the data into the array
printfPlease enter the height for person d or 0 if done: ,
currdatavalue 1;
scanflf, datavaluescurrdatavalue;
If the data was nonzero we have another height
If not, we are done
if datavaluescurrdatavalue ! 0
numdatavalues;
else
done 1;
Calculate the mean height
meanheight meandatavalues, numdatavalues;
Display it
printfnThe mean height is lfn, meanheight;
return 0;
Displays welcome message
void welcomemessagevoid
printfMean Height Calculatorn;
92 Introduction to the C Programming Language Revision 5.1
printfEnter the height of each person when promptedn;
printfEnter 0 when you are done. You can enter up to 10 valuesnn;
Calculates the mean of a set of values
double meandouble values, int numvalues
double mean;
int currentvalue;
Initialise the mean to zero
mean 0;
Calculate the sum of all of the values
for currentvalue 0; currentvalue numvalues; currentvalue
mean valuescurrentvalue;
Divide by the number of values, if there are any
if numvalues 0
mean numvalues;
return mean;
The program uses the main function to collect information from the user. It defines two other functions: the welcome message function displays useful text to the user when the program starts; the mean function calculates the mean of the values that the user has entered.
The program will accept up to 10 data values, so it declares an array of 10 double elements, like this: double datavalues10;
The program allows the user to enter less than ten values if they want, so we need to keep track of how many values they have entered. This is done using another variable:
int numdatavalues;
After the welcome message has been displayed the program enters a for loop. This loop counts through the elements in the data values array. Each time the loop runs each iteration the user is asked for a height. The scanf function call places the result into the correct element in the array:
scanflf, datavaluescurrdatavalue;
This scanf call is just like the ones you have seen in previous labs, except that instead of a scalar variable this call puts the result into an element of the array. The element it puts the result in is decided by the value of the curr data value variable. The value of the curr data value variable is set by the for loop. The for loop will stop when it gets to the tenth element in the array data values9. It will also stop if the done variable is assigned a value other than zero. This is controlled by the condition part of the for loop.
To calculate the mean, the array is passed to another function, called mean. Note how the parameter which receives the array is declared. The prototype for the mean function looks like this:
double meandouble values, int numvalues;
Revision 5.1 Introduction to the C Programming Language 93
The array is declared with empty square brackets because we dont need to limit this function to only working with arrays of a certain size. In this case, the function just needs to know how many values out of the array to use. Even if the program always used the whole array, we would still need to pass the size of the array as a parameter to the function. There is no way to determine the size of an array in C. You must store it in a variable somewhere, or you must fix it at the time when you write the program.
Exercise 5.1: Understanding the Array Program
Make sure you understand how the lab5 program works. Try stepping through some or all of it if you are unsure. If you only want to step through some of it perhaps you only want to step through the mean function then use a breakpoint to interrupt the program when it reaches the part you are interested in.
If you do not understand anything about the program, ask one of the demonstrators for help.
When you are sure that you understand how the program works, change the source code to allow the program to accept up to 15 values, rather than 10. Rebuild the program and test it to make sure that your changes have worked.
94 Introduction to the C Programming Language Revision 5.1
Exercise 5.2: Add a Standard Deviation Function
The standard deviation of a sample of values measures how spread out the values are and may be calculated using the following formula:
Where:
is the standard deviation;
xi represents the ith data value;
x is the mean of all of the data values; N is the number of data values.
1 N
N
x2i x 2
5.1
i1
The equation may also be written as the difference between the mean of the squared data values and square of the mean:
2 2
xx 5.2
Add a function to lab5 called standard deviation which takes the array of data values and the number of data values as arguments. It should return the standard deviation. You should add lines to the main function to call your new function and display the standard deviation on the screen.
Hints:
Use equation ?? to calculate the standard deviation.
Create a second array of the same maximum size as the data values array i.e. 15 elements.
You should copy the original data items into this new array, but square them.
Use the mean function to calculate the two means.
You might want to look back at the last laboratory to remind yourself about the pow and sqrt functions.
You will need to include math.h.
5.4 Initialising Arrays and MultiDimensional Arrays
Sometimes you will want to make sure there are specific values in elements of an array before you do anything with it. Imagine a situation where you want to know the number of days in a month. If you have the number of the month from 0 to 11 in a variable called month, you could use an array to find out the number of days the month has:
int daysinmonth12;
…
printfThe number of days in January d, daysinmonth0;
For this to work you would need to make sure the array days in month was set up with the right values. We could do that like this:
int daysinmonth12;
Revision 5.1
Introduction to the C Programming Language 95
daysinmonth0 31;
daysinmonth1 28;
daysinmonth2 31;
daysinmonth3 30;
daysinmonth4 31;
daysinmonth5 30;
daysinmonth6 31;
daysinmonth7 31;
daysinmonth8 30;
daysinmonth9 31;
daysinmonth10 30;
daysinmonth11 31;
But this is a pain. Fortunately, C provides us with a way to initialise the value of an array when we declare it. Like this:
int daysinmonth12 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31; The values on the righthand side of the assignment operator , in the curly brackets, are known as
initialisers. There must not be more initialisers that elements in the array.
The next program you will write will use initialisers to set numbers in an array. The difference from the arrays we have just been looking at, is that this next program will need a multidimensional array. The arrays you have seen so far have a single dimension; they work like a table with a single column. The subscript is like the row number, telling the program where to look in the table. A two dimensional array has two subscripts; it works like a table with multiple columns. The two subscripts act as the row and column numbers, selecting a single cell in the table. Three and more dimensions are also possible.
A two dimensional array is declared in C like this:
int datatable53;
You could think of the data table array as being a table with 5 rows and 3 columns. You would access
the data table array like this:
printfThe first element in the table is d, datatable00;
Notice that you need to specify both subscripts.
Initialising a two dimensional array is like treating each row as a onedimensional array, and then col lecting all of the rows together. Look at this example:
int datatable53 1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6,
5, 6, 7 ;
If we treat the first subscript as the column index, and the second as the row index, data table is equivalent to the following table of values:
Change the target to lab5a and open lab5a.c in the editor. lab5a is intended to be a program which informs the user of the distance between a small selection of major world cities. However, at the moment the program isnt finished. The best way for the program to work out the distance between cities is to look it up in a table i.e. a twodimensional array. You will need to create and initialise a suitable array to get the program to work. You should initialise it with data from the table below. The distances are in miles.
1
2
3
2
3
4
3
4
5
4
5
6
5
6
7
96 Introduction to the C Programming Language Revision 5.1
Cape Town
Hong Kong
London
New York
Rio de Janeiro
Tokyo
Cape Town
0
7,375
6,012
7,764
3,773
9,156
Hong Kong
7,375
0
5,982
8,054
11,021
1,794
London
6,012
5,982
0
3,458
5,766
5,940
New York
7,764
8,054
3,458
0
4,817
6,740
Rio de Janeiro
3,773
11,021
5,766
4,817
0
11,533
Tokyo
9,156
1,794
5,940
6,740
11,533
0
Exercise 5.3: Using an Initialised TwoDimensional Array
Add a two dimensional array to the lab5a program and initialise it with the data shown in the table. You can then use the indices that the user enters to look up the correct distance.
Some things to look out for:
Remember that array subscripts are indexed from zero.
Using a subscript that is beyond the range of the array can cause big problems. Validate the data that the user enters to make sure it is valid.
If you dont understand how to do this, ask for help.
5.5 Strings: A Special Kind of Array
You have already used pieces of text many times in your C programs. They have usually been in printf statements and have been enclosed in double quotation marks like this. A piece of text like this is called a string because it is treated by the programming language as a string of characters. The name string is just an abbreviation.
In C, strings are treated as arrays of type char. Each element in the array holds a single character. For example, we could declare an array to hold strings like this:
char somestring8;
Initialising a character array like this is quite easy, for example:
char somestring8 Hello ;
When a character array is initialised like this each letter is stored in an element of the character array some string. Like this:
You will notice that the element immediately after the last character in the string some string5 in this case contains a the character 0 thats a backslash character and a zero character, not the letter o. This is an escape sequence just like the special sequence for a new line n. 0 is the escape sequence for the null character. It is used to signal the end of the string. A string that ends in a null character is said to be null terminated. All strings in C are null terminated. When you initialise a string the null termination is added to the array for you automatically. Because the null termination takes up an extra character, you must make sure that any character array you declare has one more space in it than the maximum number of characters that you want it to hold. For example, if you wanted to declare an array for holding strings of up to 20 characters, you should declare it as:
char anotherstring21;
Revision 5.1 Introduction to the C Programming Language 97 to make sure that there is room for the null termination character.
You can use the null termination to find the end of a string in an array. For example, you could check the first element in the array to detect whether a string is empty i.e. it has no characters, like this: . You would check for the null termination like this:
if anotherstring0 0
The string is empty
else
The string is not empty
The example program lab5b contains an example of how to do some basic string handling. Change the target to lab5b and open lab5b.c in the editor. Try building and executing the program. What does it do?
The source code for lab5b.c is shown below.
C Programming laboratory 5
include stdio.h
Program starts here
int mainvoid
Declare a character array to store the string in
char stringdata20;
Ask the user for a string
printfEnter a word: ;
scanf19s, stringdata;
Show them the string
printfThe word you entered is: sn, stringdata;
Tell them what the first character was
printfThe first character of the word is cn, stringdata0;
return 0;
You should see that the program is quite simple; it uses a scanf statement to read in the string. It then displays the string using printf and then displays just the first character using another printf statement.
The scanf and printf statements use a placeholder that you havent seen before for handling strings: s. For example, the printf statement uses the s placeholder to substitute the characters out of the string variable and into the string which is going to be displayed.
You will notice that the scanf statement also uses a s placeholder, to read in a string. However, in the case of scanf a number appears between the percentage sign and the s character. The number is the maximum number of characters to read into the string. It ensures that the program does not try and put too many characters into the array.
A program to demonstrate strings
98 Introduction to the C Programming Language Revision 5.1
When using an array with scanf you do not need to use the ampersand character before the variable name. The reason for this is a little complicated and you will study it in more detail in laboratory ??.
Function Reference: s Using the s placeholder with scanf and printf scanflength s, string variable;
printfs, string variable;
The s placeholder allows scanf and printf to handle strings. When using scanf it is good programming practice to make sure the length of the string that can be read is limited using a number length between the percentage sign and the s character. This number should be one less than the length of the array to allow room for the null termination character.
As the argument which matches the s placeholder is an array. It does not need to be preceded by an ampersand.
Exercise 5.4: Understanding Character Arrays
Test the lab5b program with different input. You should find that scanf prevents you from being able to enter nothing at all. It also only ever uses the first word that you enter.
Why is the scanf placeholder 19s? Why is it not 20s?
What happens if you enter a word longer than 19 characters?
What happens if you change the placeholder to have a number less than 19?
Exercise 5.5: Handling Null Terminated Strings
Add to lab5b to create a function with the prototype:
int stringlengthchar string;
The function should count the number of characters in the string. It should stop counting when it reaches the null character. It should be able to handle situations where there are no characters in the string i.e. the first character is the null character. Call your new string length function from within the mainfunction so that you can display the length of the word that the user enters.
If you dont understand how to do this, ask for help.
Revision 5.1 Introduction to the C Programming Language 99
Exercise 5.6: Character Array Handling
Add to lab5b to add some code into the main function which copies the characters from the string data array into another array, but in reverse order. You will need to use the length of the string which you determined in your string length function to do this. Display the reversed string using printf. You must make sure that the new string you create the reversed copy has a null termination character in the right place.
If you dont understand how to do this, ask for help.
5.6 Forming Strings Using sprintf
Sometimes you want to form a more complicated string which will be stored in a character array, rather than displayed on the screen. The sprintf function works exactly like printf except that, rather than displaying the string it makes onto the screen, in places the result into a character array which you specify. For example, look at the following code snippet:
char numberstring10;
int aninteger;
aninteger 20;
sprintfnumberstring, d, aninteger;
You can see that the sprintf function call looks very like a printf function call, except that there is a new first argument. The first argument to sprintf is the string variable that results will be placed into. After the sprintf statement executes, the string number string contains the characters 2, 0 and 0
100 Introduction to the C Programming Language Revision 5.1
Function Reference: sprintf Forming strings using printflike placehold ers
int sprintfchar string variable, char format string, …;
e.g.
The sprintf function works like the printf function except that, instead of outputting its results onto the screen, it places them into the character array string variable. It is called in exactly the same way as printf but with an extra first argument string variable.
sprintf takes at least two arguments but, like printf, it can take more, depending on how many variables you want to include.
string variable is the character array which will receive the output of the sprintf func tion as a string;
format string is a string containing placeholders, just like with printf;
after the first two arguments where the … is you should include variables whose values
will be substituted for the placeholders in the format string. The placeholders you will use most often are:
d for integer int variables; lf double variables;
c for single characters char; s for strings char.
These are the same as for printf.
The return value of sprintf is an integer, which specifies how many characters were written into
the string variable array not including the null termination. The sprintf function is defined in stdio.h
sprintfnumberstring, d, intvariable;
sprintfanswerstring, The answer is d, integeranswer;
numchars sprintfdisplaystring, lf, doublevariable;
Revision 5.1 Introduction to the C Programming Language 101
Exercise 5.7: Using sprintf
Add to the main function in lab5b to prompt the user for an integer number. Use the sprintf function to create a string version of the integer in a character array you could reuse one of the arrays you already have, if it is big enough.
Determine the length of the string it produces in two ways: use your string length function;
use the return value from the sprintf function call.
Display both answers and make sure that they are the same!
If you dont understand how to do this, ask one of the demonstrators for help.
There is a library that is part of the C standard library which contains a number of functions especially designed for handling strings. All the functions are defined in string.h. If you want to find out more about these functions you should look in a book on C, or consult documentation on the internet.
5.7 Graphics Option
Change the target to graphics1 program and open graphics1.c in the editor. You will be adding even more functionality to your program now. By the end of this session it should reach the stage where you can play it as a simple game.
Your graphics program is beginning to get quite sophisticated. The user now has control over the hor izontal position of the stick person, and the launch angle of the projectile. You are now going to add a target for them to throw the object at. The target should be at ground level and have numbers on it identifying the score associated with a particular area. It could look something a bit like this:
How many areas there are, and what the scores are for each area is entirely up to you.
The best way to produce the target is using a loop. Each iteration of the loop should produce one of the small vertical lines which separate the scores. You could store the associated scores in array a bit like this:
int scores5 10, 20, 30, 20, 10;
The code that you write to produce the target should have a structure a bit like this:
int line;
char label3;
for line 0; line 5; line
Calculate position of line based on the value
of the line variable
Draw the line in the right place
Calculate position of label based on the value
of the line variable
Create a string with the label in it
102 Introduction to the C Programming Language sprintflabel, d, scoresline;
Use outtextxy to display the text
outtextxyx, y, label;
Draw the last line here
Revision 5.1
This is obviously just a skeleton, you will need to fill in the missing sections with code of your own.
Exercise 5.8: Drawing a Target
Create a function called draw target which uses code based on the skeleton to draw a suitable target on the far righthand side of the graphics window. Feel free to decide:
how many areas your target will have;
what scores the different areas will have;
how big the different areas of the target will be.
Exercise 5.9: Giving the User a Score
Now the user has a target to throw the object towards, the computer should reward them with a score that corresponds with the position in which the projectile path ends.
Your program calculates the vertical position of the projectile at each horizontal location. It should stop when the vertical location is not above ground level. The horizontal position at which the projectile is no longer above ground level will determine the score.
When the projectile reaches ground level or below your program should assign the corresponding horizontal position to a variable. You can then use that variable which will be an xcoordinate to calculate where on the target the object fell. You should then be able to use the values in the scores array to give the user a score for their throw.
5.8 Music Option
The improvisation program you have been working on has been limited to producing whole tone scales or random notes. It has been difficult to produce other scales as the differences in pitch between notes in say, a major scale, are not easily calculated mathematically. As an example, lets look at a simple C major scale. If the scale starts on middle C the first note of the scale has a pitch value of 60. To get the other notes in the scale we could add small pitch values onto this starting value, like this:
If we chose a major scale in a different key then the pitch offsets would still be the same. But the pitch offsets are not related in any obvious mathematical way.
A way to approach this problem is to store these pitch offsets in an array. For example, you could define a major scale like this:
int majorscale8 0, 2, 4, 5, 7, 9, 11, 12;
Revision 5.1 Introduction to the C Programming Language 103 A loop like the following one would play a major scale:
int scalenote;
int key;
key 60;
for scalenote 0; scalenote 8; scalenote
midinotekey majorscalescalenote, 1, 64;
pause500;
midinotekey majorscalescalenote, 1, 0;
Arrays like these are very powerful for representing musical relationships such as scales and chords.
Exercise 5.10: Making Your Improvisation Use NonWhole Tone Scales
Begin by opening your music2 program remember to change the target to music2. Add a function which uses as array to play a single ascending octave of a major scale. Try using it in place of the function which produced whole tone scales.
Now is your opportunity to innovate! Try and improve your improvisation program focussing on using scales other than whole tone scales.
Try some different scales, other than a major scale.
Try choosing which scale will be played at random.
How about representing chords using an array? Can you get your program to improvise a chord line to accompany a melody built out of scales?
Can you use the value of an array to predefine some pause values? This would allow you to predefine certain rhythms. Try playing these rhythms on MIDI channel 10 this is the drum channel.
5.9 Summary
Now that you have finished this laboratory you should understand what arrays are and how they can be used. You should be able to declare both single and multidimensional arrays and initialise them with data.
You should know that strings are character arrays and that all strings in C are null terminated; so they end with the null character 0. You should be able to manipulate strings and create them using the scanf and sprintf functions.
In the graphics option you added to your program to make it much more like a computer game. It should now have a target towards which the user throws the object. The user should then be given a score for their throw.
In the music option you should have found that arrays are very useful for defining sections of music by representing numerical relationships. You should understand how to use an array to represent a scale. You may also have explored how to use arrays for chords and rhythms.
104 Introduction to the C Programming Language Revision 5.1
Laboratory 6
Structures and Defining New Types
6.1 Overview
In laboratory ?? you saw how arrays could be used to collect information together in a useful way. This lab introduces structures, which are another way of collecting information together. In an array, all the entries must be of the same type. The information stored in a structure may be of many different types. Structures allow you to write more compact programs and make them much easier to design and understand.
This laboratory will also introduce you to the typedef statement, which allows you to define your own types like int, double etc.. This is most useful when used in combination with structures.
The graphics and music options each show you one way in which structures can be put to good use.
6.2 Introducing Structures
Imagine that we want to write a program to store details about students attending a course at a univer sity. Let us say that we want to be able to store the following pieces of information about the student:
their family name or surname;
their given name or first name; the year in which they were born; the code of the course they are on.
Before computers were used to store this kind of information it would be common to put each of these details on a card. The card could then be filed with other cards which have the details of other students.
A card is useful because it keeps the various pieces of information about the student all in one place.
In C we have used arrays to keep pieces of information together, like distances or positions or notes in a musical scale. In an array, all the items must have the same type. This can be very limiting. The details we want to store about each student are not naturally all the same type:
the family and given names are character strings; the year in which they were born is an integer;
the course code is a three digit integer.
106 Introduction to the C Programming Language Revision 5.1
There are two strings and two integers. It would be possible to store the two integers as strings, but this would require conversions to store and retrieve the information. This would be inefficient and error prone.
C structures allow us to collect information together in a very similar way to the cards mentioned above. We can declare a structure using the struct keyword. This is normally done in two stages:
Firstlyyouusethestructkeywordtodefineatemplateforthestructure.Thisisabitlikecreating a card which has headings, but has not been filled in yet. The template is given a name so that you can refer to it.
Once you have declared the template, you can now use it. To do this, you specify the name of the template when declaring a variable in place of a type name like int or double.
We will look at each of these stages in turn.
To define the template you first specify the struct keyword followed by a tag which is the name of the template you are defining. Following this, in a set of curly braces, you define one or more variables which are part of the structure. These are called member variables. A structure template definition for the details we want to store about a student is shown below.
Remember that this does not actually declare a variable yet. All we have done is decided on a template, a layout for the card which we are going to fill in.
Now that we have a template, we can use it. We declare a variable called student which is a structure of the template student type:
To use the student variable you must specify which one of the member variable you wish to access. For example, to set the year of birth to 1986, you would write:
student.yearofbirth 1986;
The dot says that the variable before it is a structure, and the variable afterwards specifies which part of the structure we want to access.
Revision 5.1 Introduction to the C Programming Language 107
Syntax: Structures
struct name
member variable declarations
;
A structure is a way of grouping variables together where the variables may have different types. Structures also create more readable code because, unlike arrays, each item of data in the structure has a name, rather than just a number.
A structure definition specifies a new structure type called name which has member variables spec ified by the member variable declarations. For example, the following code defines a new structure type called Point with two member variables, x and y.
struct Point
int x;
int y; ;
This structure definition can also be written:
struct Point
int x, y; ;
Themember variable declarationsfollowexactlythesamesyntaxasordinaryvariabledec larations.
Tousethepointstructure,avariableshouldbedeclaredusingtypestruct point: struct Point somepoint;
The x and y parts of this variable can now be accessed using the dot . operator. For example: somepoint.x 50;
Open the lab6.c program in the editor and change the target to lab6. This program is a very simple demonstration of how to use structures.
Exercise 6.1: Using Simple Structures
Try building and executing the lab6 program. Once you have run it, and tried entering some details, have a look at the source code. Make sure you understand what is happening and how it is being achieved.
Add a member variable to the structure for favourite colour. Add functionality to the program to allow the user to enter a favourite colour. The program should also display the students favourite colour when the other details are displayed.
108 Introduction to the C Programming Language Revision 5.1 6.3 Defining New Types with typedef
The typedef keyword allows you to define new types, just like int and double. The new types you define must be based on existing ones. For example:
typedef int Distance;
declares a new type called Distance which is identical to int. typedef statements are usually placed in the global scope of the program i.e. not inside any functions or in a header file so that the type may be used by lots of different functions. The new type may be used in a variable declaration like this:
Distance distancetotokyo;
If at some point in the future you wanted to make all the variables of type Distance more precise, you
could change the typedef statement to define Distance as a double rather than an int:
typedef double Distance;
In this way typedef statements can help make your program more readable by making your types more flexible, and your type names more descriptive. By creating a type called Distance you have quite a good idea about what variables of that type are going to store.
typedef statements are especially useful when dealing with structures, which is why they are being introduced in this lab. When we defined a structure for holding student details it was done likes this:
struct studenttype
char familyname40;
char givenname40;
int yearofbirth;
int coursecode;
;
This effectively defines a new type, but to use this type we have to use the struct keyword as well.
You saw this in the lab6 program:
struct studenttype student;
We can make this shorter, and therefore easier to read and type!, by using a typedef.
First, lets change the structure definition to rename the structure type name:
struct longstudenttype
char familyname40;
char givenname40;
int yearofbirth;
int coursecode;
;
The prefix long has been added because we are going to create a type name which can be used as shorthand, and this is the long version. We can now define a new type as shorthand for struct long student type:
typedef struct longstudenttype studenttype;
This new type is easier to use than the old one, because we can omit the struct keyword when creating variables. So:
Revision 5.1 Introduction to the C Programming Language 109 studenttype student;
declares a new variable called student of type student type.
When using type definitions with structures it is usual to combine the struct definition and the
typedef all in one statement. Like this:
typedef struct longstudenttype
char familyname40;
char givenname40;
int yearofbirth;
int coursecode;
studenttype;
Thisdefinesastructurestruct longstudenttypeandcreatesashorthandforitcalledstudenttype,
all in one line.
Note that when using typedef with structures you dont need to have an internal structure name
like struct long student type since the structure has a name due to the use of typedef.
typedef struct
char familyname40;
char givenname40;
int yearofbirth;
int coursecode;
studenttype;
As with other type definitions, the best place to write this code is in the global scope.
Syntax: Type Definitions
typedef old type name new type name;
A typedef statement defines a new name for an existing type. The new name is an exact replace ment for the old name, it can be used interchangeably with the old name i.e. it is a synonym. The old type name is still valid.
For example:
typedef double Length;
Defines a new type called Length which is equivalent to the double type.
Exercise 6.2: Using typedef with Structures
Change the lab6 program to use a typedef for the structure type so that the keyword struct
does not need to be used when declaring variables.
Ensure that the type definition is in the global scope of your program i.e. outside of any function.
110 Introduction to the C Programming Language Revision 5.1
Exercise 6.3: Using Your New Type Name
Create a function which displays all of the details about a student. Each piece of information should be shown on a separate line. Alter the program to use the function to display the contents of the structure in place of the final printf statement.
The function might have a prototype like this:
void displaystudentstudenttype student;
6.4 Using Arrays of Structures
At the beginning of this lab the analogy was drawn between a structure and a card with details written on it. Usually there are many cards, all of the same type, kept together in a filing cabinet of some kind. So far we have only used one card. In this section we will use multiple cards by creating an array of structures.
An array of structures is easy to create by using the type that your have defined. An array of five student records would be declared like this:
studenttype students5;
You can now access individual structures in the array by specifying their index. For example:
students2.yearofbirth 1986;
Exercise 6.4: Using an Array of Structures
Edit the lab6 program so that the user is first asked how many students they wish to enter details for. This could be a number anywhere between 1 and 10. If the user enters 0 the program should end. Ask the user for the details of as many students as they specified. The student details should be stored in structures in an array.
When the user has entered all of the details the program should display all of the information stored in the array. This should be achieved by calling your display student function repeatedly, in a loop.
If you do not know how to attempt this, ask for help.
6.5 Graphics Option
A structure can be used to store information about a graphical object such as a line, or a shape. Vector graphics editing programs manipulate information about graphical objects in this way. In this lab you will store the information for a set of lines in a structure.
A line can be fully defined by:
its start coordinate x, y;
its end coordinate x, y;
its colour an integer value.
Revision 5.1 Introduction to the C Programming Language 111 This information could be stored in a structure like the following:
typedef struct
int startx, starty;
int endx, endy;
int colour;
Line;
The program graphics3 contains the skeleton for the program you are about to write. Change the target to graphics3 and open the source code graphics3.c in the editor.
Exercise 6.5: Using Structures for Graphics
Write a program which prompts the user for the coordinates and colours of a number of lines. You might like the user to be able to state how many lines they want to use, although you will probably have to impose a maximum limit.
When the user has finished entering the information, draw the lines on the graphics window and wait for a key press.
You might like to add a feature to allow the user to edit the details of the lines that they have already entered so that they may correct mistakes.
A 2D coordinate is always made up of both x and y portions. It would make sense to define a structure to hold coordinates, or points, in a 2D space.
typedef struct
int x, y;
point;
Exercise 6.6: Nesting Structures
Add the type definition for point type to your program. Change the definition of line type so that the start and end location of the lines are specified as points. You will end up with a structure inside a structure.
Exercise 6.7: Implementing Simple Vector Graphics Capability
How do you think you could use one type of structure to define a range of shapes like lines, squares, circles, triangles etc.? What things do they have in common? What special items of information might you need for some of them? How could you make a single drawing function draw all of the shapes? Can you include fill information?
Try implementing a few of your ideas. You will need to change your structure type definition, the user input code and the drawing routine.
112 Introduction to the C Programming Language Revision 5.1 6.6 Music Option
In this laboratory you will use structures to create a simple sequencer. The sequencer will allow the user to input the details of various notes and then play them back, in order.
Each note can be characterised by four pieces of information:
pitch;
channel;
velocity;
duration in milliseconds.
This information could be stored in a structure like the following:
typedef struct
int pitch;
int channel;
int velocity;
int duration;
note;
The program music3 contains the skeleton for the program you are about to write. Set the target to music3 and open the source code.
Exercise 6.8: Using Structures for Music
Write a program which prompts the user for the details required to play a number of notes pitch, channel velocity, duration. You might like the user to be able to state how many notes they want to use, although you will probably have to impose a maximum limit.
When the user has finished entering the information, play the notes back to the user.
You might like to add a feature to allow the user to edit the details of the notes that they have already entered so that they may correct mistakes.
Exercise 6.9: Operating on the Sequence
Alter your program so that the user may choose to play back the note sequence they have just recorded in a number of different ways:
transposed up or down;
in reverse order;
the instruments that isare being used.
Revision 5.1 Introduction to the C Programming Language 113
Exercise 6.10: A More Advanced Sequencer
The sequencer you have created is limited to playing only one note at once. Have a think about how you might lift this restriction. How would this change the information that you store in a structure? How would the playback function have to be changed? Could you incorporate changes in instrument into the sequence?
Try implementing a few of your ideas.
6.7 Audio Programming Part 1
So far in the course you have been taught about all the fundamental and some advanced concepts in C Programming. In particular you have been taught about variables and arithmetic expressions, control flow like conditional statements and iteration loops, functions and program structure, arrays and structures. These concepts cover almost all of the C language. At this point you are well equipped to continue with audio programming and implement programs that can generate and process audio in some way. If you do not feel comfortable with the C language concepts mentioned above please revise those concepts before proceeding with this section of the lab. You should have a decent understanding of the basic topics in order to better comprehend the material that follows.
This laboratory session covers the fundamentals of audio programming. The learning outcomes of this session are the following:
Understand the concepts of signals and digital audio signals in particular.
Understand, at high level, how continuoustime audio signals are discretised so that they can be manipulated using a digital system.
Become aware of PulseCodeModulation for converting continuoustime signals to discrete time.
Get familiar with the sampling rate and bitdepth of digital audio signals and understand the way these two parameters affect the quality of the signal and its size.
Differentiate between interleaved and noninterleaved digital audio signals.
Use the amio lib library to read a digital audio file into memory e.g. .wav file, access basic information about the file and finally write a digital audio file from memory to disk i.e. save a file to disk.
6.7.1 Signals
The concept of signals arises in many areas of science and technology including communications, elec tronic circuit design, seismology, biomedical engineering, acoustics, image processing and speech pro cessing, just to name a few. Generally speaking, a signal conveys information about the variation behaviour of a physical quantity phenomenon. Mathematically, signals are functions of one or more independent variables. For example the variations in time of the voltage and current in an electrical circuit are types of signals. In this case voltage and current are the physical quantities and time is the independent variable e.g. vt and it . In medicine, the electrocardiogram and the electroencephalo gram are examples of signals and again the measured quantities electrical activity of the heart and electrical activity of the scalp respectively are functions of time. Sound speech, music or audio in gen eral is also a signal where the physical quantity is acoustic pressure which varies in time. A picture is another type of signal. In this case the physical quantity is brightness which varies along two spa tial variables, so a monochromatic picture is a function of two independent variables the coordinates x and y, so the signal is fx,y. In a similar fashion we have a video signal which is a function of three independent variables x,y coordinates and time t, i.e. f x, y, t .
We can categorise signals based on the number of the independent variables they are functions of. A signal with one independent variable is a onedimensional signal e.g. voltage, current, speech, with
114 Introduction to the C Programming Language Revision 5.1
Figure 6.1: A simplified view of the Analog to Digital AD and Digital to Analog DA conversion process of audio signals.
two independent variables a twodimensional signal e.g photograph so on so forth. Audio program ming deals with sound signals, so in this course we are only interested in onedimensional 1D signals and the independent variable will be time denoted by t.
Signals can also be categorised based on the nature of the independent variable. That is signals where the independent variable is continuous are called continuoustime signals and are defined for a contin uum of values. When the independent variable is discrete then the signals are called discretetime and are defined only for a discrete set of values. A discrete signal can be discrete by nature e.g demographic data, rainfall data over a period of time, stock market indices etc. but can also arise from the sampling of continuous signals. For example sound is inherently a continuoustime signal but in order to pro cess it using a digital computer it has to be converted into a discretetime signal first. This conversion occurs by a process known as sampling, so a discretetime sound signal represents successive samples of the underlying continuoustime sound signal. In this part of the course we will see how to generate, modifyprocess and save on disk such discretetime audio signals.
6.7.2 Digital Audio Signals
Audio signals are signals pertaining to sound be it speech, music or any other audible sound. Sound as a physical phenomenon is simply fluctuations of pressure transmitted through a medium. The medium is usually air but sound travels through other materials as well, like water for example. Sound does need a medium to transmit though, so in outer space where there is vacuum sound cannot be transmitted. When the medium is air sound is produced by fluctuations in acoustic pressure. It is clear that sound is a continuoustime signal. It is also a onedimensional signal since these fluctuations in acoustic pressure are a function of time only.
Analog to Digital AD and Digital to Analog DA Conversion
In order to process audio signals in the digital domain i.e. using digital electronics, a computer etc. sound has to be captured, digitised and stored somewhere usually on a computer hard drive. Sound is captured by a microphone that converts acoustic pressure into an electrical signal. The microphone is a transducer, i.e. a device that converts a signal from one form of energy to another. In our case this is mechanical energy to electrical energy. At this stage the produced electrical signal i.e. the output of the microphone is still a continuoustime signal. This electrical signal is digitised by a process known as Analogue to Digital Conversion ADC. An Analogue to Digital Converter which is the device that performs analogue to digital conversion comprises many steps but two of the most important are sam pling and quantisation. The process of sampling, as mentioned in the previous subsection, produces the discretetime representation of a continuoustime signal; i.e. after sampling we end up with a se quence of samples that represent values of the continuoustime signal at points equally spaced in time. Sampling acts on the independent variable of the signal and produces a discretetime signal. Quantisa tion on the other hand is the process that discretises the dependant variable. In the case of sound that is the electrical signal that corresponds to acoustic pressure. This process is depicted in figure ??.
In figure ?? we can see that sound emanating from the source is captured by a microphone. The cap tured signal is then sent into an analog to digital convertor where sampling and quantisation of the continuous electrical signal output of the microphone convert it into a digital signal which can in turn be either stored into nonvolatile memory hard disks, optical disks, flash memory etc or placed into volatile memory e.g RAM where it can be further processed. At this stage we have a digital repre sentation of the analog audio signal. In many cases though we want to get back to the original analog counterpart. This is the inverse process of ADC, known as Digital to Analog Conversion DAC. The output of the DAC can be further processed using analog signal processing with analog electronics and finally reproduced over loudspeakers.
Revision 5.1 Introduction to the C Programming Language 115
Figure 6.2: Demonstration of sampling a simple sinusoid at different rates. At high sample rates the digital signal is a better representation since we have more information more samples of the original signal.
Linear PulseCode Modulation LPCM or PCM
Sampling at uniform intervals and quantising a signal are parts of a method called Linear PulseCode Modulation LPCM which is the most common way to represent a continuousanalog signal in the digital domain. WAV and AIFF audio formats are two examples that contain PCM data. The following is true for PCM audio data.
Sampling Rate BitDepth
It should be clear by now that sampling and quantisation affect the size and quality of the captured digitised audio signal. We have two parameters to control the processes of sampling and quantisation namely the sampling rate or sampling frequency or Fs and the bitdepth resolution of the signal. The sampling rate is typically given in units of kiloHertz kHz or Hertz Hz. Hertz is an SI unit and is defined as cycles per second, which in our case means how fast at what rate we sample the continuous time signal. Another way to look at the sample rate is as how many samples there are in one second of audio data. That is when we see a sample rate of 44100 Hz this means that one second of audio contains 44100 samples. A directly related quantity is the sampling period Ts which is defined mathematically as:
Ts 1 6.1 Fs
When quantising the signal, what we effectively want to do is to map the infinite continuous amplitude values of the analog signal into a finite discrete set of values where the number of possible values de pends on the bitdepth value. The error produced by quantisation is called the quantisation error and depends on bitdepth. Bitdepth is given in units of bits per sample and is the number of bits used to represent each sample of the audio signal. A common value is 16 bits e.g CDDA which means that there are 216 65536 possible values to represent the amplitude of each sample. In digital audio processing though we usually use 32bits to represent each sample which gives us 232 4294967296 possible values. Bitdepth directly affects the resolution of each sample, therefore sometimes it is also refereed to as bitresolution. A high bitrate generally produces better quality audio since it decreases the quantisation error, improves the signaltonoise ratio SNR of the reconstructed signal and provides a larger dynamic range having said that there are techniques like dithering and oversampling that mitigate some of these characteristics without changing the bitdepth. This will apply to audio that is already recorded using high bit rates or for audio that is generated with such values. For a thorough explanation of ADC, sampling and quantisation you can read 13.
Figures ?? until ?? depict the effects of sampling and quantisation on a continuoustime signal. The plots in figure ?? show the effect of sampling a simple sinusoid at different speeds. To be in accord with conventional notation we will denote the independent variable of an analogcontinuous signal as t and will always enclose it in parenthesis brackets such as xt and for digital signals the we denote the independent variable as n and will always enclose it in square brackets such as xn. We can relate continuous time with discrete time using:
tn Ts whichleadstoxtxn Ts 6.2 wheretR,tandnZ,nwithTs asdefinedinequation ??
Figures ?? until ?? depict the effect of quantising the amplitude of a continuous signal using different bitdepths 2 bits, 3 bits and 5 bits. NOTE that the continuous signal blue in all plots is ofcourse digital since all plots were produced from a computer generated script but for our purposes let us assume that the blue signal in all subsequent plots is continuous.
116 Introduction to the C Programming Language Revision 5.1
Figure 6.3: 2bit quantisation. Each audio sample can take a value out of only four possible values.
Figure 6.4: 3bit quantisation gives eight values to choose from. We can see that the quantisation error decreased.
Audio Channels
An audio file on disk can comprise one monochannel, two twochannel stereo or more channels multichannel. This has nothing to do with the dimensionality of the underlying signals. That is a monochannel audio file comprises one 1D signal, a twochannel audio file comprises two 1D signals, so on so forth. One question that comes to mind is how audio samples are grouped inside an audio file that might have a multichannel format. For Linear PulseCode Modulated signals LPCM as ex plained in previous sections we can have a noninterleaved or an interleaved configuration. In the noninterleaved case the samples of each channel are grouped separately meaning that samples belong ing to each channel are stored in separate contiguous memory locations. In the interleaved configuration the samples of each channel are interleaved, meaning that the audio samples of each channel alternate in a single stream. These two configurations are depicted in figure ??. In both configurations the signal comprises a number of frames, where each frame comprises M channel audio samples. In case of a monochannel file M1 so a frame comprises one sample. In a stereo case, M2 so each frame comprises two samples left channel sample followed by right channel sample so on so forth.
Interleaved audio data is a very common configuration and we are going to use it throughout the ex ercises. In amio lib.h library, the function that is responsible for loading audio data into memory produces an interleaved buffer of audio data and we should take that into consideration especially when processing multichannel audio files.
6.7.3 Audio MIDI InputOutput Library amio lib
amio lib is a library specifically build for this course. It comprises three third party libraries, namely libsndfile, portaudio and portmidi. libsndfile provides functions that deal with reading writing audio files from to disk. portaudio provides realtime audio capabilities and portmidi provides MIDI functionality. We chose these libraries for all audio and MIDI needs of the course for three main reasons:
1. They are written in pure C and are well suited for this course.
2. They are crossplatform libraries meaning that you can write your code once and compile the same code in multiple architectures like for example Windows, Apple OS and Linux.
3. Theyarefreesoftwarewhichmeansthatwecanusethemforeducationalpurposeswithouthaving to pay any license fee.
amio lib combines the power and functionality of all aforementioned libraries providing a single, expandable, simple and easy to learn Application Programming Interface API suitable for beginners in the areas of audio and MIDI processing. Of course amio lib does not provide the full functionality of libsndfile, portaudio and portmidi but definitely enough for this course. All examples and exercises in the next section use amio lib. To get the amio lib functionality in your programs all you have to do is add include amio lib.h at the top of your implementation file.
The program audio01 contains code which loads a wav file into memory, displays some basic infor mation about the file and saves the file unaltered on disk. Set the target to audio01 and open the source code.
Figure 6.5: With five bits we get 32 possible values to choose from and the quantisation error decreased dramatically compared with the 2bit quantiser. In the top plot we can also see how the digital signal red begins to look similar to the original blue.
Revision 5.1 Introduction to the C Programming Language 117
Figure 6.6: Figure a depicts how LPCM stereo audio data is stored in a noninterleaved way. Left channel samples are grouped separately from right channel samples. Figure b depicts LPCM stereo audio data interleaved. The audio stream consists of frames, where each frame comprises M channels samples for stereo, M2 thus each frame consists of 2 samples.
Exercise 6.11: Reading an audio file into memory and writing it back to disk
This example takes you through the processes of reading an audio file into memory and writing it back to disk, unaltered but with a different name and on a different physical file, something like a rename program would do. This example introduces the two functions that allow us to perform such operations namely, wavread and wavwrite the naming of the functions was taken by the similar functions found in MATLAB software package.
Open file audio01.c into CodeBlocks or Xcode and read through it. There are plenty of comments that explain what each step does. First we create two SIGNAL structures to hold information about the input and output audio files sampling rate, bitdepth, format, number of channels, number of frames and of course the actual data. Then we use the wavread function to read the file into memory. wavread actually performs a series of steps in the background; first of all it opens the audio file we requested, then it loads its data into memory and finally it closes the file. This way the original file remains unaltered, as it should be. We should not be concerned about these steps because wavread takes care of everything.
Your exercise is to read thgrough the code in audio01.c carefully and make sure you understand what is does. If in doubt ask one of the demonstrators.
A few words on error handling
A this point note what wavread returns. The return value is an integer which represents an error code. When creating Application Programming Interfaces, especially in C, it is a usual design pattern for the functions to return an error code, especially functions that perform critical andor complicated opera tions. As programmers we should always check for errors returned by functions and act accordingly. This is what the following lines of code do:
errwavreadkInputSignalLocation, input;checkErrerr,kSndFileSystem,Failed to read audio file into memory; amio lib uses three different libraries in the background each of which has its own error reporting system portaudio and portmidi error reporting mecha nisms are very similar.
checkErr is an utility function which provides a single error reporting interface. For more information on that and other functions read the comments included in amio lib.h.
After reading the file into memory the program proceeds by displaying information about the file using another utility function displaySndInfo.
After displaying the info to the user the program uses yet another utility function, Fill SIGNAL which prepares the output SIGNAL structure. By preparing we mean that the fields of the SIGNAL structure are populated with values. This function is a helper function and you could also populate the fields of the SIGNAL structure in the usual way of accessing each field of the structure and assigning a value to it. Having a SIGNAL structure ready for output the only thing that is left is to actually assign the audio data to write to disk and this is achieved with the following line:
output.datainput.data;
Recall that input and output are both SIGNAL structures and each has a data field which is a pointer to a memory location where the actual sample data reside. In this case we merely copy the pointer of the input data to the pointer of the output data so that output.data pointer points to input.data.
Finally the program uses the wavwrite function to write the output SIGNAL into a file on disk. It should be clear that in this example the creation of an output SIGNAL was not necessary; we could have
118 Introduction to the C Programming Language Revision 5.1 simply passed SIGNAL input to the wavread function. Make sure you understand the logic behind this
statement and the program in general. If you have any questions please ask one of the demonstrators.
6.8 Summary
This lab has introduced you to structures, a powerful way of collecting together information. An array collects information, but a structure is often useful because:
the different parts of it members may have different types;
the members are named, rather than simply referred to by index.
The middle part of the lab introduced type definitions, and showed a way in which they are commonly used when defining structures.
You should also have used a collection of structures in an array, both in a simple example for storing student details and in the graphics and music options. The graphics option used an array of structures to deal with graphical objects such as lines in a similar way to vector graphics editing programs. The music option used an array of structures as the basis for a simple sequencer.
Laboratory 7
Pointers and Passing Parameters by Reference
7.1 Overview
This laboratory begins by investigating how parameters are normally passed to functions. When a function is called, the value of an argument is copied into a parameter which acts like a variable inside the function. This is called passing by value.
You will then be introduced to a special kind of variable called pointers which, rather than store a value of their own, reference another variable. A pointer allows the program to find, and modify, another variable. In the next part of this lab you will use pointers when calling functions to allow them to modify the variables that have been passed as arguments. This is called passing by reference.
In the final part of the lab you will use pointers with structures to improve the way in which your programs from lab ?? are written.
7.2 More About Function Parameter Passing
This laboratory will introduce you to a useful and very powerful technique for working with variables. Before you can go on to this, we will take some time to look at the way in which variables work when functions are called. We will use very simple pieces of C code to understand important concepts.
The source code below is from the lab7 project. Change the target to lab7 and open lab7.c in the editor. Dont execute the program yet.
120 Introduction to the C Programming Language
Revision 5.1
void changeint i
printfThe number is now dn, i;
i 20;
printfThe number is now dn, i;
int mainvoid
int j;
j 5;
printfThe number is dn, j;
changej;
printfThe number is now dn, j;
return 0;
You will see that there are two functions in this program. The main function and another function called change.
Exercise 7.1: Investigating Function Parameters
Before you try running the program look at it carefully. Decide exactly what you think it will do. What will it display on the screen?
Try running the program. Does it do what you thought it would? Do you understand why it operates in the way it does?
You should remember some important facts about functions from lab ??:
parameters the part in parentheses after the function name are just like variables;
all variables and parameters that are declared in a function are only accessible inside that func tion;
when a function is called, it is common to specify some arguments in brackets after the function name;
the values of these arguments are copied into the function parameter variables.
These points mean that if a parameter is changed inside a function the value of the variable that was
used as an argument is not affected.
To emphasize this point, lets look at how the simple program lab7 works. To begin with, a value is
assigned to the variable j. This is shown below:
When the function is called, the variable j is specified as an argument. Its value is copied into the
change functions parameter i see the diagram below.
In the change function, the value 20 is assigned to the parameter i. Notice that the value of the variable
j, which only exists inside main, is not affected.
When the change function returns the program flow to the main function, the value of j has not changed.
Revision 5.1 Introduction to the C Programming Language 121 This system of copying the value of an argument into the parameter is called passing by value. It is the
normal way in which C functions work. It has a very good side and a less good side:
the good side is that functions are not able to affect the code that calls them. This stops them from damaging other parts of your program and ensures encapsulation this was mentioned in laboratory ??.
the less good side is that the only way to return a value is by using the return statement. This limits a function to only returning one value. Sometimes you might want to write code in which a function returns more than one value.
The next part of the lab introduces pointers which, amongst other things, allow us to get round this limitation.
7.3 Introducing Pointers
When you store a number in a variable, the program represents that number as binary and places in the computers memory. In some diagrams in this lab script this process has been shown by depicting the memory location as a box containing the number. Like this:
This diagram appeared in lab ??. You can think of the computers memory being entirely made up of boxes like this one. Some of these boxes are used for your programs variables, others are used for your programs code and more are used by other programs.
Every box or location in the computers memory is numbered. The number for a location identifies it uniquely and is called an address. You can refer to any location in the computers memory by specifying its address. Since addresses are just numbers it can be difficult to keep track of them so program ming languages give us a way of representing location addresses with names. A variable name like my integer is just an easier way of talking about a location in the computers memory.
The address in this diagram is made up. It is difficult to know what address your variables will have before your program loads. Because C gives a name to each variable, you dont need to know the address.
C provides a way to use one variable to refer to the contents of another variable. This kind of vari able is called a reference, because instead of holding a value of its own it references another memory location, which holds a value. In C, references are more commonly called pointers. The two names are interchangeable, we will most often use the name pointer in this lab script.
The diagram below shows a pointer variable called ref my integer which references the variable my integer. The reference is shown with an arrow.
Notice that the contents of the memory location associated with the pointer variable ref my integer is 0x12345678. This is the address of the memory location associated with the my integer variable.
Pointers in C are declared like this:
int refmyinteger;
This line declares a new variable called ref my integer which is a pointer, or a reference, to an int.
The symbol can be placed immediately after the int like this: int refmyinteger;
122 Introduction to the C Programming Language Revision 5.1
These two statements are identical. It is a matter of stylistic taste whether you append the data type i.e. int with an asterisk or prepend the variable itself. Notice that we have specified what this point will reference: an integer type int. This pointer cannot be used to reference a double or a char or anything else. This helps to prevent some simple programming mistakes.
The star is one of two C operators which are used when working with pointers, the other is the ampersand . You can think of these operators as travelling along the arrow which goes from a pointer to the memory location it is pointing to.
To make this clearer, lets look at an example piece of code:
This piece of code is in the project lab7a. Open it in the IDE and change the target to lab7a.
We will now investigate this program a line at a time.
The first two lines of the program declare the integer variable my integer and the pointer variable ref my integer which is specified as referencing integers. The program has not assigned values to these variables yet.
The next line uses the operator to set up a pointer from the integer variable my integer. The oper ator is called the reference operator because it allows us to create a reference from a variable. A reference pointer to the variable my integer is created and assigned to the pointer variable ref my integer.
The next line assigns the value 20 to the variable my integer and then uses a call to the printf function to display its value.
The next line uses the ref my integer pointer variable with the operator. The operator is called the dereference operator and tells the program that we are not talking about the pointer variable, ref my integer, by what ever it references, in this case the my integer variable.
The assignment copies the value 5 into the location that is referenced by the pointer ref my integer, which changes the my integer variable. The value that is displayed on the screen is therefore 5.
Exercise 7.2: Investigating Pointers
Build and execute the program lab7a. Look at the source code and have a go at trying to under stand how the program works. Dont worry if you dont understand, the next part of the lab will explain this program.
Exercise 7.3: More Pointer Investigation
Try stepping through the lab7a program. Watch the variables change in the watch window.
Make sure that you understand what is happening before you continue. If necessary, ask one of the demonstrators to explain it to you.
You can see that the reference and dereference operators do opposite things.
The reference operator creates a reference a pointer from a variable. It take simply takes the
address of the memory location the variable is using to store its information in.
The dereference operator uses a reference to find the original variable. It uses the address stored in the pointer variable to find the memory location containing the information.
Revision 5.1 Introduction to the C Programming Language 123
Syntax: Pointer Reference and Dereference Operators
The reference operator operates on a variable to create a reference. It does this by obtaining the address of the memory location which is being used to store the information for that variable. For example:
somevariable
is directly equivalent to the address of the variable some variable.
The dereference operator carries out the opposite operation to the reference operator: it takes an address in the form of a pointer and follows it to find the location that it refers to. So, if:
somepointer somevariable;
some pointer is directly equivalent to some variable i.e. the lines
somepointer 20;
somevariable 20;
do the same thing.
The dereference operator is used when declaring pointer variables, as in:
type name; For example, the line:
int somepointer;
Declares a new variable called some pointer which is a pointer to a variable of type int
You might have noticed that a pointer variable is declared using the dereference operator like this:
int refmyinteger;
This is saying I would like to declare a variable with a type such that if you were to dereference it, you would get an int. If you dereference the ref my integer variable, you get an integer.
7.4 Using Pointers to Pass Parameters by Reference
The reason we started looking at pointers was to change the way parameters are passed into functions. The next thing you will do is to change the simple program lab7 you met at the beginning of this lab so that the change function can alter the value of the argument variable in the main function.
This can be done by changing what we pass into the change function. Instead of passing the value of the variable j from the main function, we could pass a reference to j using the reference operator . The change function should then be adjusted to accept and use a pointer to an integer instead of an integer.
This technique of passing a pointer rather than a value to a function is called passing by reference.
124 Introduction to the C Programming Language Revision 5.1
Exercise 7.4: Changing the lab7 Program to Pass by Reference
Change the lab7 program to pass the parameter into the change function by reference, rather than by value. You will have to change:
The way in which the function is called. You will have to use the reference operator to create pointer.
The parameter declaration part of the change function head. At the moment the change function accepts a single integer parameter. You should change this so that it accepts a pointer to an integer instead.
The assignment statement inside the change function to use the dereference operator. By using the dereference operator you will affect the value of the j variable in the main function.
Try building and executing your program. You should find that the change function is now able to affect the value of j.
You may have noticed that you have been using the reference operator since laboratory ?? in scanf lines like this:
scanfd, myinteger;
This means that you are passing the scanf function a pointer to the my integer variable, which allows
it to change the value. This is another example of passing by reference.
Exercise 7.5: Using scanf with a Pointer
Alter the change function so that it asks the user what value they wish to set the variable to. It
should then set the value of the location that i references using a scanf function call.
Be Careful! Remember that the variable your are using i is a pointer. Do you need to use the reference operator when calling scanf? If you dont understand this, ask one of the demonstrators to explain it to you before continuing.
Exercise 7.6: Passing Multiple Values by Reference
Because a pointer is just another parameter, a function can accept a number of pointers as parame ters, as well as other values. There are no limitations on this.
Change the lab7 program so that the change function accepts two or more! pointers as parame ters, and sets the values of them using scanf function calls.
7.5 Using Pointers with Structures
One of the most powerful ways to use pointers is in combination with structures, like those you met in lab ??. By passing a pointer to a function by reference it allows that function to change any of the members of that structure.
Suppose we have a student type structure type just like the ones you looked at in lab ??:
Revision 5.1
Introduction to the C Programming Language 125
typedef struct
char familyname40;
char givenname40;
int yearofbirth;
int coursecode;
studenttype;
We could declare a function to accept one parameter, which was a pointer to a structure of this type:
void changestudentstudenttype student;
So that parameter student is a pointer to a structure of type student type.
So how would the change student function set the values in the structure? It cant do it like this: student.yearofbirth 1986;
because student is a pointer to structure not a structure. We need to use the dereference operator to follow the reference to find the actual student type structure. It has to be done like this:
student.yearofbirth 1986;
This dereferences the pointer student to find the structure, then uses the dot operator . to access the member variable year of birth. The brackets are necessary because otherwise the . takes prece dence over the and C thinks that the star refers to both the parts before and after the ..
Writing student.member is very cumbersome and difficult to read. To alleviate this problem, C includes a special operator for accessing the members of a structure to which you have a pointer. It looks like this: . It is a combination of a minus sign, , and a greater than sign, , and is meant to look like an arrow. The line:
studentyearofbirth 1986;
is exactly equivalent to:
student.yearofbirth 1986;
The first notation is easier to read and is almost always used in place of the second.
Syntax: Pointer to Structure Member Access Operator
The is used for accessing the member variables of a structure to which you have a pointer. As in:
struct pointermember; For example:
mystructsomevalue
Accesses the member variable some value from the structure which is referenced by the pointer
variable my struct. This is directly equivalent to: mystruct.somevalue
126 Introduction to the C Programming Language Revision 5.1
Exercise 7.7: Using Pointers with Structures
Open the program that you were working on in lab ?? as part of your option. This will be graphics3 if you are were working on the graphics option, or music3 if you were working on the music option.
Both these programs have a loop in the main function which accepts values from the user to put into a structure in the array. Create a separate function which accepts a pointer to a structure. It should be this function which prompts the user for values and places them in the structure.
The function prototype for those doing the graphics option might look something like this:
void getlinevaluesline newline;
For those doing the music option it might look something like this:
void getnotevaluesnote newnote;
You will have to use the reference operator when you call the function, and the operator.
Exercise 7.8: Improving Program Efficiency Using Pointers
When you pass a structure by value all of the member variables are copied into the parameter. This can make your programs inefficient, both in terms of their speed, and the amount of memory they use.
Change the draw line graphics option or the play note music option function so that the structure is passed by reference rather than by value.
7.6 Summary
Now that you have finished this laboratory you should know that the usual way in which functions are called involves a copy of the values of the arguments into the function parameters and is called passing by value.
You should understand what a pointer is and be able to use the reference and dereference opera tors to work with pointers. The technique of using pointers as parameters to functions is called passing by reference, you should know how to write and call functions which use this technique.
In the final part of the lab you used pointers with structures. You should have met the operator which is designed for working with structures. You should also have altered one of the programs you created in lab ?? so that it passed structures by reference.
Laboratory 8
Arrays and Strings Revisited and Allocating Memory
8.1 Overview
In lab ?? you were introduced to pointers. This lab begins by examining arrays, showing that there is a strong relationship between arrays and pointers. An array is essentially a pointer to a block of memory locations which the C compiler has set aside. Array and pointer notation can therefore be used interchangeably.
A pointer on its own is not very useful, as it has no memory to refer to. This lab introduces the malloc function which you can use to allocate blocks of memory whilst your program is running. Any memory you allocate with malloc must be deallocated before your program ends using the free function. C provides an operator called sizeof which helps you determine how much memory is required by different variable types.
Finally the lab looks at allocating memory for structures, and arrays of structures. You will alter the graphics or music program you have been working on to use the memory allocation functions malloc and free.
8.2 More About Arrays
Lab ?? introduced you to arrays. You may remember diagrams of arrays with boxes representing the
elements of the array. Like this:
The boxes in array diagrams like this one represent memory locations in just the same as the boxes in the diagrams representing pointervariable relationships in lab ??. These diagrams simply the way in which arrays work. An array actually has two parts to it:
A block of memory locations in which the information for each element is stored;
The array variable is actually a pointer which references the first memory location in the block.
An array that is declared as:
int myarray4;
Can be drawn diagrammatically as:
128 Introduction to the C Programming Language Revision 5.1
The variable name my array is actually a pointer, this is shown on the lefthand side of the diagram. This pointer references the first location of a block of four integersized memory locations. The block of memory locations is shown on the righthand side of the diagram.
When you use the square brackets after an array name it is very similar to using the dereference operator . In fact, writing:
myarray0 5;
is exactly the same as writing:
myarray 5;
Accessing any element other than the first element in an array requires placing a nonzero number in the square brackets. The pointer equivalent to this is to add a number to the pointer. Like this:
myarray3 20;
Which is exactly the same as writing:
myarray3 20;
Using mathematical operations, such as addition, on pointers is called pointer arithmetic and must be used carefully. Pointer arithmetic changes what the pointer is referencing. There is nothing in C to stop you changing a pointer so that it does not reference a valid memory location. This mistake, often called a floating pointer, is very difficult to spot and generally causes your program to crash completely.
In general the array notation, using the square bracketed subscript, is much clearer and easier to read than pointer arithmetic. Use pointer arithmetic very carefully, try and avoid it if possible, there are usually clearer ways to write the same thing.
The fact that arrays are just pointers with some memory attached is often reflected in functions which accept arrays as parameters. In lab ?? you used a mean function to calculate the mean of an array of values. The prototype for this function was:
double meandouble values, int numvalues;
This prototype could equally have been written using pointer notation, as:
double meandouble values, int numvalues;
The two prototypes are effectively identical. The body of the mean function used the square bracket
notation for accessing the values parameter as an array. Like this:
mean valuescurrentvalue;
Even with the function prototype that declares the values parameter as a pointer, this line does not need to be changed. Just as an array variable is actually a pointer, it is perfectly legitimate to treat a pointer as an array.
If you look at other peoples code, including standard C functions, you will find that the pointer notation for array parameters to functions is very common.
Exercise 8.1: Investigating Arrays as Pointers
When you pass an array to a function, you are passing a pointer. You can think of arrays as always being passed by reference. The program lab8 contains a skeleton for a program which might use an array. Open lab8.c in the editor and change the target to lab8.
Based on the very simple programs you used in laboratory ??, create a program which demonstrates that arrays are effectively always passed by reference. You can make the program as simple or complicated as you like.
Revision 5.1 Introduction to the C Programming Language 129 8.3 More About Strings
In lab ?? you saw that character strings are also arrays: arrays of type char. Each element is a character and the last element in the string is always the null character, 0. Since string variables are arrays, they are also pointers. You will often find that functions that operate on strings expect a parameter of typechar i.e.acharacterpointer.Forexample,theprototypeforthestandardCfunctionstrlenis as follows:
int strlenchar str;
The strlen function calculates the length the string it was passed by finding the nulltermination char
acter. You wrote a function to do this in lab ??.
You can assign strings to pointers that are specified in your program, like this:
char message;
message Its a long way to Tokyon;
You could then display the message using a printf statement, like this:
printfmessage;
You can access individual characters of the message using the array subscript square brackets, for ex ample:
message5
would be equivalent to the character a. However, you can not change the string by writing to it. The string is prespecified so it may be in memory which you are not allowed to write to. For example, you should not do the following:
message5 1;
If you want to be able to change the message, you must put its contents into an array, like this:
char message Its a long way to Tokyon;
This will allocate writeable memory especially for the message and copy the message into it. You can now change its contents.
130 Introduction to the C Programming Language Revision 5.1
Exercise 8.2: Investigating Strings as Pointers
Open the lab5b program. This program does some operations on a word that you enter. It should count the length of the word and then reverse the characters in the word and display it. Currently, the reversal operation takes place in the main function.
create a function called reverse string, which reverses the string that you give it;
for both the reverse string function and the string length function change the proto
types so that the string parameters are declared as pointers, rather than arrays. So, your prototypes should be:
int stringlengthchar string;
and:
You should find that declaring these parameters as pointers rather than arrays makes no difference to the operation of your program. However, when handling strings it is far more common to use the pointer notation than the array notation.
void reversestringchar string;
8.4 Allocating Memory
In the last two sections you found that an array is a pointer to a block of memory locations. The block of memory is allocated by the C compiler when your program is running. The C compiler then sets up the array pointer so that you can use it. There are a number of circumstances under which you might not want the C compiler to allocate the memory for you. You might want to do it yourself. The most common of these reasons are:
You dont know how big an array you need until the program is running. When you specify an array size, it must be fixed when you write the program. If you allocate the memory yourself you can control how big an array is whilst the program is running, perhaps in response to user input.
The amount of memory that can be set aside by the compiler for an array is limited. Sometimes you may wish to allocate a large block of memory to use as an array, for example to manipulate a bitmap image or a sound sample. Allocating memory whilst the program is running is more flexible, and the blocks of memory which can be allocated are bigger.
When the compiler allocates array memory for you, you must have specified the size when you wrote the program. This size is fixed, so this is called static memory allocation. Allocating memory whilst the program is running is more flexible. This is called dynamic memory allocation because the amount of memory that is allocated can be changed every time the program is run.
The standard C library provides a number of functions for working with memory. The normal way to allocate a block of memory is to use the malloc function which is an abbreviation for memory allocation. When you are finished with the block of memory, your program must hand it back, using the free function.
To demonstrate the use of malloc and free we will look at a very simple program snippet. The bit of code we will look at simply allocates some memory, we imagine that it uses it, and then the memory is freed. When the memory is allocated we will use the pointer my array to reference it. When the program starts the pointer does not yet have a meaningful value.
The call to malloc allocates a block of memory of a specified size. The code snippet has the word size where you would specify the size of the block of memory you require. We will look at how to specify
Revision 5.1 Introduction to the C Programming Language 131 memory sizes in a moment. Imagine that we specified that we wanted room for four integers.
The diagram shows that we have allocated a block of memory, and that the pointer my array references it. Notice that the block of memory has no variable name. It is not a variable; the only way we have to access this memory is using the my array pointer.
When we have finished using the memory we must tell the system that we no longer need it. This allows the memory to be reused. If we did not do this the system would use up memory every time we ran the program. Allocating memory and forgetting to free it is called a memory leak.
Notice that when you free a block of memory, the pointer that you used to access the memory in this case my array does not change. However, the memory that this pointer references no longer belongs to the program. You must not attempt to access memory you have freed.
A call to the malloc function may not always succeed. You are asking the system for a block of memory. If it does not have enough memory to give you the malloc function will fail. If it does, the malloc function returns the special pointer value NULL. If a pointer is NULL it indicates that the pointer is invalid. If you try to use a NULL pointer your program will crash. It is good practice to always check to see if malloc returned a NULL or a valid pointer.
You have just seen how the malloc and free functions are used to allocate and free up blocks of memory. A call to the malloc function takes one argument: the size of the block you wish to allocate. C has a special operator called sizeof to help you calculate how much memory different things take up. The sizeof operator looks like a function call but is in fact built in to the C language. To use sizeof you specify the type name for a variable in brackets after the keyword sizeof. For example, if you want to know the size of an integer, you would write:
sizeofint
The size of four integers would be:
sizeofint 4
Therefore, to allocate space for four integers using malloc you would write: myarray mallocsizeofint 4;
The code snippet we have been looking at is in the lab8a program. Open lab8a.c in the editor and change make sure the target is lab8a.
Exercise 8.3: Investigating Memory Allocation
Have a look through the source code for the lab8a program. Do you understand what it is doing? Once you have tried executing it, try stepping through it and watching the variables. If you cannot understand what is happening, ask one of the demonstrators to explain it to you.
132 Introduction to the C Programming Language Revision 5.1
Function Reference: malloc Memory Allocation pointer mallocsize;
e.g.
somepointer mallocsizeofint;
realarray mallocsizeofdouble 20;
string mallocsizeofchar 256;
The malloc function allocates a block of memory of the requested size and returns a pointer to the memory. Once the memory is not longer required, it must be deallocated using the free function.
Should the malloc function be unable to grant the request for memory, for example if there is insufficient remaining free memory on the system, the function will return the NULL pointer.
The malloc function is defined in stdlib.h
Syntax: The sizeof Operator sizeoftype
The sizeof operator calculates the amount of memory a type requires for storage. For example, the following:
sizeofint
calculates how much size is required by one integer variable. sizeof evaluates to a number, so it
may be combined with mathematic operations such as multiplication. For example:
1024 sizeofchar
The most common use for the sizeof operator is when using the malloc memory allocation func tion.
Revision 5.1 Introduction to the C Programming Language 133
Function Reference: free Memory Deallocation freepointer;
The free function deallocates memory that was previously allocated using the malloc function. The free function takes one argument: a pointer to the block of memory to be deallocated.
The free function should always be used to deallocate memory as soon as it is no longer required.
You should never attempt to free a block of memory twice, or to free statically allocated mem ory such as arrays.
Once a block of memory referenced by a pointer is deallocated, the pointer should not be used again, unless it is assigned a new value.
The free function is defined in stdlib.h
Exercise 8.4: Arrays and Memory Allocation
The lab5 program allowed the user to enter data which the program placed in an array. Two sta tistical operations are then carried out: mean and standard deviation. At the moment, the memory in the array is statically allocated. The number of data items the user can entered is therefore fixed when the program is compiled.
Change the lab5 program so that the user is asked how many data items they wish to enter at the beginning. You should then use malloc to dynamically allocate the data array. You can put a maximum limit of the number that the user enters if you want.
Remember to free the memory before the program ends.
Exercise 8.5: Strings and Memory Allocation
In a similar way to Exercise ??, change the lab5b program so that the user can decide how long a word they wish to be able to enter. You will need to be careful in how the scanf function call is constructed.
8.5 Dynamic Memory Allocation for Structures
Dynamically allocating memory for structures is very similar to allocating memory for arrays. The structure name is used with the sizeof operator to calculate the size of the block of memory required. For example, to allocate a block of memory for one student type structure you would call malloc in the following way:
student mallocsizeofstudenttype;
Allocating memory for an array of structures is similar. For example:
studentarray mallocsizeofstudenttype 20;
134 Introduction to the C Programming Language Revision 5.1
As you can see, this follows the same pattern as allocating memory for standard C types such as int and double.
Exercise 8.6: Structures and Memory Allocation
If you have been following the graphics option, open the graphics3 program; if you have been following the music option, open the music3 program remember to change the targets appropri ately. These projects currently use a statically allocated array of structures. Alter the program so that the array memory is dynamically allocated and freed.
Exercise 8.7: Reallocating Memory
If the user of your graphics2music3 program wanted to a a linenote whilst the program was running, how would you accommodate this it would require more memory to be allocated. If the user removed a linenote could you free memory up? Have a go at implementing this into your program.
If the user is addingremoving linesnotes continuously allocating and freeing memory can make your program slow. How could you make this process more efficient?
8.6 Audio Programming Part 2
Having learned about pointers and memory allocation you are now ready to continue with more ad vanced audio programming concepts such as audio effects and realtime audio processing. The fol lowing example code and exercises will take you through the creation of skeleton code that you can eventually use in your assignment.
8.6.1 Applying gain changes
This example demonstrates how to apply gain changes into an audio file. The program reads a file into memory, halves the amplitude of all samples and outputs the new data into a new file on disk. The code is exactly the same as that of example audio01.c apart from the memory allocation step and the processing step. In the previous example we didnt have to modify the signal in any way so no extra memory was needed. In this example though we want to modify our initial signal so we have to allocate some memory to hold the processed signal. The following line in file audio02.c does exactly this:
output.data float malloc sizeoffloat input.frames input.channels;
The above line uses malloc to allocate a block of memory of size:
sizeoffloat input.framesinput.channels.
The malloc function return a pointer to that block of memory which we store in the data field of the output SIGNAL structure. The processing step iterates through each sample of the input data, applies a gain change and stores the result in the output data. After this simple processing the new file is written to disk using wavwrite.
The program audio02 contains code that shows you how to change the amplitude of an audio file. Set the target to audio02 and open the source code.
Revision 5.1 Introduction to the C Programming Language 135
Exercise 8.8: Applying gain changes add error checking
Modify the program audio02.c so that it includes error checking as shown in audio01.c example.
Exercise 8.9: Applying gain changes inspect original and processed audio files
Run the program and compare, inspect and listen the original and the processed audio file using an audio editor e.g Audacity.
Exercise 8.10: Applying gain changes write processing function
Write a function that carries out the same processing found in as STEP4 in audio02.c. The function should have at least two input arguments the input and output SIGNAL structures. What other parameter could be useful for this processing? Finally replace the code in STEP 4 PROCESSING with your function and make sure your program works as expected.
8.6.2 Reversing a signal
This example demonstrates how to reverse a signal. The only thing that is different from previous exam ples is the processing step. Open audio03.c and inspect the code. Do you understand the processing part? If not ask a demonstrator for help. Run the program and compare, inspect and listen the original and the processed audio file using an audio editor e.g Audacity.
Exercise 8.11: Reversing a signal add error checking
Modify audio03.c so that it includes error checking.
Exercise 8.12: Reversing a signal write a processing function
Write a function that carries out the same processing found in as STEP4 PROCESSING in audio03.c and make sure your program works as expected.
8.6.3 Delay effect
This program demonstrates how to implement a simple delay effect. In particular this is a feedforward delay which creates a single echo there is no feedback parameter. Open file audio04.c and inspect the code. You should notice that we have declared a couple of extra parameters namely M and g. M is the amount of delay we require in samples and g is gain parameter the feedforward parameter also known as the feedforward coefficient. The most interesting part of this code is the processing block
136 Introduction to the C Programming Language Revision 5.1 that implements the delay. The actual mathematical equation that we use is the following:
yn xn g xn M 8.1 where yn is the output signal, xn the input signal, M Z the amount of delay we require in samples
and g R the feedforward coefficient gain factor.
The role of the feedforward coefficient is clear; when g 0 the second term in equation ?? becomes zero so what we end up is yn xn meaning that there is no delay at all. When g 0 the second term of ?? starts to contribute to the output. Note the term xn M for a moment. This term is actually the signal xn delayed by M samples. This is depicted in figure ??.
And as a sanity check we can also use table ?? to confirm this for M2: Table 8.1: A signal delayed by 2 samples.
n01234567 xn 0.8 0.5 0.2 0.7 0.4 0 0 0 nM 2 1 0 1 2 3 4 5
xnM 0 0 0.8 0.5 0.2 0.7 0.4
We can clearly see the signal xn M being delayed! Now if carefully look back into equation ?? we can see what it actually does: the output signal is equal to the input signal plus a delayed and attenuated version of the input signal.
Exercise 8.13: Delay effect add error checking
Modify the audio04.c so that it includes error checking.
Exercise 8.14: Delay effect convert samples to ms
The delay parameter M in this example is given in samples. Find the equation which converts this value into milliseconds or seconds. Assume a known sampling rate you will usually get this by the file information from within the SIGNAL structure or if you generate sound from code you can specify your own system sampling rate; a good value is 44100 Hz .
Exercise 8.15: Delay effect write processing function
Write a function which implements the delay effect explained in this example. Then replace the code in STEP 4 PROCCESSING in audio04.c with your own function and make sure your program works as expected.
Figure 8.1: A signal xn blue and a delayed version red
Revision 5.1 Introduction to the C Programming Language 137 8.6.4 Tremolo effect
This example applies a tremolo effect to a signal. Tremolo can be created by simply modulating an incoming signal with a low frequency oscillator LFO. For our LFO we will use a sine wave. The mathematical formula of a sine wave is the following:
lfot sin2 f t 8.2 where f is the frequency of the oscillation in Hz and the phase of the wave in radians. Using equation
?? into equation ?? we get:
t n Ts n Fs
8.3
8.4
Finally substituting equation ?? into equation ?? we get the discrete version of the sine wave: lfonsin2 f n
Fs
We know that the output of the sin function ranges from 1 to 1. For the tremolo effect to work we want the LFO to range from 0 to 1 so we have to do some scaling. The following line produces the required scaled output:
lfon0.5sin2 f n1 8.5 Fs
Equation ?? is actually implemented in the code of this example without the phase parameter. After creating an array that contains the values of our LFO the only thing left to do is to multiply the LFO signal with the amplitude of the input signal and save the result into a new file on disk.
Open file audio05.c and inspect the code. Make sure you understand the lines of code that generate the LFO signal. If not please ask a demonstrator to explain.
Exercise 8.16: Tremolo effect add error checking
Modify the program audio05.c so that it includes error checking.
Exercise 8.17: Tremolo effect write processing function
Write a function that implements an LFO, that is a function that given a rate value in Hz and an amplitude value, produces a LFO signal as the one expressed in equation 3.5. You could also add a phase parameter.
8.6.5 Real time audio processing. Generating a sine wave.
This example generates a sine wave and plays it through the speakers for a few seconds. There is no user interaction adding user interaction is an exercise but the example goes through the fundamental concepts of realtime audio processing. The theory and design pattern that follows, although simplified, is true for many audio systems including digital audio workstations, plugin architectures like VST and Audio Units, audio engines for games, software packages like MaxMSP and PureData and pretty much all audio solutions that require realtime audio support.
138 Introduction to the C Programming Language Revision 5.1 8.7 Summary
This laboratory reexamined arrays and strings to show their close relationship with pointers. You should now know that an array is simple a block of memory, allocated by the compiler, which is refer enced by a pointer. Memory that is allocated by the compiler is called statically allocated memory.
Now that you have finished this lab you should know how to dynamically allocate memory using the malloc function call. You should know that all dynamically allocated memory should be deallocated using the free function call.
In the last part of the lab you should have used dynamic memory allocation with an array of structures.
Laboratory 9
Practical Software Design
9.1 Overview
This laboratory looks at the process of designing software and documenting the development process in the form of a report. The lab is split into two parts:
the first part of the lab sections ?? and ?? gives you an existing design for a piece of software. This is exactly the kind of design that you will be expected to produce. You will implement the design in C, and then add to the design to give you practice at designing software.
the second part of the lab section ?? is a reference guide, giving you some simple tips to help you write your own software development reports.
Section ?? will introduce you to the lab, and the software development process.
9.2 The Structure of Software Projects
This laboratory is a bit different to the ones you have done so far. In this lab, rather than look at another part of the C programming language, we will look at how you should use the C that you already know about in a formal software development process.
The best way to produce good quality software is to follow a well structured software engineering approach. A formal approach to the development process helps to prevent errors. A small error in an early stage of the process can grow to become a large problem in the finished program. Such large problems tend to be very expensive and timeconsuming to fix.
The software engineering process is usually broken down into the following steps:
understandingtheproblemsothatasetofRequirementsmaybecreated.Thisstageisoftencalled
Requirements Capture or Requirements Elicitation.
analysing the requirements to understand how the problem may be solved. This stage is usually referred to as Requirements Analysis or just Analysis. The aim is to gather information ready to produce a formal specification for what the software should do.
the creation of a formal Specification. A specification is typically split into things that the software is required to do, and things that are desirable for the software to do.
using the specification as the starting point for a software Design. There are many approaches to designing software but the aim is always the same: to decide exactly how the software will work, and how it will be used before any actual programming takes place.
the Implementation of the program. In your case this would be done in the C programming language. This is the only part of the process that actually involves programming. The way in which the design is implemented is documented in an Implementation Report.
140 Introduction to the C Programming Language Revision 5.1
the software that has been produced must be carefully tested against the original specification and its functionality verified against the original requirements. There are a number of ways to approach the Testing and Verification of software. Usually more than one method is used to improve confidence in the correct operation of the program.
before the software is passed on to a user, or the original customer or client, the operation of the program is documented in a User Manual.
An important part of the software engineering process is the documentation of each stage. In the list above, the words in bold indicate the names of each section of a typical software report. A high quality of documentation is essential when software is being developed by a team of engineers rather than a single programmer. Section ?? is a reference guide for software report writing, giving you some tips for producing your own programs and reporting on the development process.
Rather than spend a lot of time in this lab doing paper work you will be learning about program design by using a design which has already been written. This lab script will give you the specification and design for a piece of software, assuming that the requirements and analysis have already been done. They are not given here. You will have to implement the software design you have been given. Doing this will help you understand what is necessary in a good software design. This should help you when you come to write your own software reports.
There are two designs in this script: one is for the graphics option, the other is for the music option. You should attempt the one you are most familiar with.
9.3 Graphics Option
This design takes the example of a simple piece of software intended to behave like a simple drawing device an EtchaSketch.
9.3.1 Specification
The program is required to:
allow the user to draw a line using the arrow keys; allow the user to clear the drawing and start again; drawing should start from the centre of the screen; allow the user to exit at any time.
Additionally, it would be desirable if the program:
ensures that the drawing does not leave the visible screen area; is easy and straightforward to use.
9.3.2 Design
The design will be split into three stages: the user interface design, a structural design and an algorithm design. This process roughly corresponds to a topdown design approach, which starts from what the program should appear to do and works towards the question of how that functionality should be achieved.
User Interface Design
The program will start by welcoming the user, informing them how to use the program and then dis playing the graphics window in which they can draw.
Revision 5.1 Introduction to the C Programming Language 141
At program start up, the following text should be displayed:
Welcome to SketchPad
Arrow keys let you draw
Press c to clear your drawing
Press q to quit
Press any key to start drawing…
The program should then wait for a key press.
Once the user has pressed any key the graphics window should be displayed. To ensure that the window fits comfortably onto most peoples screens, the graphics window should have a drawing area of 640 by 480 pixels. To allow these numbers to be changed easily they should be defined as symbols:
Once the graphics screen is displayed, the drawing may begin. Drawing should begin at the centre of the screen, i.e. at the location WINDOW SIZE X 2, WINDOW SIZE Y 2.
When the user presses a key it should be handled as follows:
the up arrow key should cause a line to be drawn from the current location upwards for a small amount;
the right arrow key should cause a line to be drawn from the current location right for a small amount;
the down arrow key should cause a line to be drawn from the current location downwards for a small amount;
the left arrow key should cause a line to be drawn from the current location left for a small amount;
the c key should cause the drawing to be cleared and the drawing location reset to the middle of the screen;
the q key should cause the program to exit.
All key presses should be case insensitive. Once a line has been drawn, the current location will be the end of the new line. The amount that a line is drawn by should be small, but not too small, 10 pixels is reasonable in a 640 by 480 pixel window. To allow this amount to be changed easily, it should be defined as a symbol:
Program Structure Design
The program can be split up into separate functions corresponding to the different tasks the program must perform. Separate functions are used for programming clarity and to enable code reuse.
The structure of the program is shown in the diagram below:
Each of the structural units in the diagram is a function. These functions are documented in the table below:
Symbol Name
Value
WINDOW SIZE X
640
WINDOW SIZE Y
480
Symbol Name
Value
MOVE DISTANCE
10
142 Introduction to the C Programming Language Revision 5.1
Function Name
Input Parameters
Return Value
Description
main
None
Integer, error level passed to environ ment
Driving function, calls all others, always returns 0. Handles the actual draw ing.
display welcome
None
None
Displays the welcome message and instructions to the user
reset
xcoordinate Integer ycoordinate Integer
None
Clears the graphics win dow and sets the current location to the x and y coordinate specified
Program Algorithm Design
This section examines each of the functions identified by the structural design and outlines an algo rithm for its implementation. All algorithms conform to the data conventions identified in the previous section.
The main function is responsible for carrying out most of the programs functionality. It calls the other functions, whenever necessary, to display the welcome message and reset the graphics window. The most important role of the main function is the processing of key input from the user and the drawing of lines in the graphics window.
The main function uses four variables:
The structure for the main function algorithm is as follows:
display welcome message
initialise graphics window
set initial position to be centre of screen
set leave to be zero
begin loop
get a key press from the user
if it was an arrow key, set current position correctly
if it was c or C set the current position to be the centre of screen
check that the position does not fall off the edge of the window
if it does, adjust so that it is within the window
if the key was an arrow key draw a line to the new current position
if the key was c or C clear the screen and reset the position to centre
if the key was q or Q set leave to be 1
loop while leave is zero
close the graphics window
The detailed algorithm for the main can be described in pseudocode as follows:
function main
call displaywelcome function
initialise the graphics window to WINDOWSIZEX, WINDOWSIZEY
set currx to be WINDOWSIZEX 2
set curry to be WINDOWSIZEY 2
Variable
Range
C Type
Description
curr x
0 640
int
The xcoordinate of the current drawing location
curr y
0 480
int
The ycoordinate of the current drawing location
leave
0 or 1
int
0 indicates that the program should continue run ning, 1 indicates the program should finish
key
, , , , c, C, q, Q
int
The number of the key that was pressed by the user
Revision 5.1 Introduction to the C Programming Language 143
call reset specifying currx and curry
set leave to be 0
begin loop
call getch to get a key from the user, put the result in key
if key is zero then
call getch again, putting the result in key
end if
switch using key
case up arrow key
subtract MOVEDISTANCE from curry
case left arrow key
subtract MOVEDISTANCE from currx
case down arrow key
add MOVEDISTANCE to curry
case right arrow key
add MOVEDISTANCE to currx
case C or c
set currx to be WINDOWSIZEX 2
set curry to be WINDOWSIZEY 2
end switch
if currx is greater than 640
set currx to be 640
else if currx is less than zero
set currx to be zero
end if
if curry is greater than 480
set curry to be 480
else if curry is less than zero
set curry to be zero
end if
switch using key
case any arrow key
draw a line to the new currx and curry position
case C or c
call reset specifying currx and curry
case Q or q
set leave to be 1
end switch
loop while leave is zero
close the graphics window
end function main
The main function always returns 0.
The two other functions are considerably simpler. The display welcome function simply displays the
welcome message and then waits for a key press. The pseudocode is as follows:
begin function displaywelcome
display welcome message
call getch to wait for a key press
end function displaywelcome
The display welcome function has no variables or parameters. The reset function takes two parameters:
Parameter
Range
C Type
Description
x
0 640
int
The xcoordinate that the drawing location should be set to
y
0 480
int
The ycoordinate that the drawing location should be set to
144 Introduction to the C Programming Language Revision 5.1 The reset function clears the graphics window and sets the current location to the x and ycoordinate
specified by the parameters. The pseudocode is as follows:
begin function reset
call cleardevice to clear graphics window
call moveto passing x and y parameters
end function reset
The reset function has no variables.
This completes the design.
9.3.3 Implementation
You should now take the time to make sure that you understand how the design is proposing to solve the problem. The pseudocode for the main function is quite complicated. Have a think about how you are going to translate it into C.
Change the target to lab9. You will find that the lab9.c source file is completely empty. This is ready for your own code.
Exercise 9.1: Implementing the Design
Implement the SketchPad program according to the design. You will need to choose appropriate C statements that match with the pseudocode. You will also need to make sure that you include the correct header files.
Exercise 9.2: Checking Your Implementation
Test your implementation to make sure that it works. Does it do what you expected it to?
Try out an implementation that a friend has done you could let them try yours. How similar is it? If it is different, why is it different?
If a design is good then different implementations of it should be indistinguishable to a user. Do you think the design could be improved? If so, how?
9.3.4 Extending the Design
You now have the chance to add to the design. Although you are not producing a software report for this program, you should make some notes as if you were writing a proper design. This gives you the chance to practice writing a small part of a design.
Revision 5.1 Introduction to the C Programming Language 145
Exercise 9.3: Adding to the Design
Imagine that the specification contained an extra point: The program is required to: allow the user to change between red, green, blue and white drawing colours.
Make notes on how you would amend the design to meet this new part of the specification. Make sure that each decision you take is fully justified.
Exercise 9.4: Implementing Your Design Addition
Follow your design, and implement the additions you have just made. How easy is it to follow your design? Are you having to correct design mistakes whilst you program? Do you think that you missed anything in your design?
9.4 Music Option
This design takes the example of a simple piece of software intended to make the QWERTY computer keyboard behave like a basic musical keyboard with only one octave.
9.4.1 Specification
The program is required to:
allow the user to play any note from an octave;
use the octave that starts on middleC;
each note should be activated from a key press on the QWERTY keyboard; each note should be played for a short, but fixed amount of time;
allow the user to exit at any time.
Additionally, it would be desirable if the program:
uses keys on the keyboard that roughly correspond in layout to a musical keyboard; is easy and straightforward to use.
9.4.2 Design
The design will be split into three stages: the user interface design, a structural design and an algorithm design. This process roughly corresponds to a topdown design approach, which starts from what the program should appear to do and works towards the question of how that functionality should be achieved.
146 Introduction to the C Programming Language Revision 5.1 User Interface Design
The program will start by welcoming the user and informing them how to use the program. The pro gram will then play notes in response to key presses, until the user requests that the program should exit by pressing the q key.
At program start up, the following text should be displayed:
Welcome to KeyNote
Press q to quit
The keyboard is the following keys:
a C
w C s D
e Eb d E
f F
t F
g G
y G
h A
u Bb
j B k C
The program should then wait for a key press.
When the user presses a key that is part of the list displayed, the corresponding note should play for half a second 500ms. To allow this duration to be changed easily, it should be defined as a symbol:
For example, when a user presses the a key, a middleC should be played for half a second. When the user presses the t key, the F above middleC should be played for half a second. All key presses should be case insensitive, i.e. a and A should be treated identically.
If the user presses the q key, the program should end.
Program Structure Design
The program can be split up into separate functions corresponding to the different tasks the program must perform. Separate functions are used for programming clarity and to enable code reuse.
The structure of the program is shown in the diagram below:
Each of the structural units in the diagram is a function. These functions are documented in the table below:
Symbol Name
Value
NOTE DURATION
500
Revision 5.1 Introduction to the C Programming Language 147
Function Name
Input Parameters
Return Value
Description
main
None
Integer, error level passed to environ ment
Driving function, calls all others, always returns 0
display welcome
None
None
Displays the welcome message to the user
display keys
None
None
Displays the instructions for how to use the key board to the user
key to pitch
key code Integer
Integer, the pitch of the note to play or zero if the key was not valid or 1 if the program should exit
Converts a key number to a pitch, or to zero if the key wasnt valid, or to 1 if the key was q or Q and the program should exit
The key to pitch function translates a key numbers like that returned from getch into a pitch. If the key was not a valid note key it returns zero. If the key was q or Q it returns 1. To allows these numbers to be easily read and recognised symbols should be defined for them as follows:
The main contains the main loop which keeps the program running. Its most important role is to accept key presses from the user and then to call the key to pitch function to translate the key numbers into a pitch value. It then reacts to the pitch number that is returned and plays a note as necessary.
The main function uses three variables:
Symbol Name
Value
PITCH INVALID
0
PITCH QUIT
1
Variable
Range
C Type
Description
leave
0 or 1
int
0 indicates that the program should continue run ning, 1 indicates the program should finish
key
a, A, w, W, s, S, e, E, d, D, f, F, t, T, g, G, y, Y, h, H, u, U, j, J, k, K, q, Q
int
The number of the key that was pressed by the user
pitch
60 72, 0, 1
int
The pitch of the note to play or zero if the note should not be played, or 1 if the program should exit
148 Introduction to the C Programming Language
The detailed algorithm for the main can be described in pseudocode as follows:
function main
call displaywelcome function
call displaykeys function
set leave to be 0
begin loop
Revision 5.1
call getch to get a key from the user, put the result in key
if key is zero then
call getch again, putting the result in key
end if
call keytopitch passing key, assigning the result to pitch
if pitch is equal to PITCHQUIT
set leave to be 1
else if pitch is not equal to PITCHINVALID
turn on a midi note of pitch, on channel 1 with velocity 64
pause for NOTEDURATION
turn off a midi note of pitch, on channel 1
end if
loop while leave is equal to 0
end function main
The two display functions are very simple. The display welcome function simply displays the first
part of the welcome message. The pseudocode is as follows:
begin function displaywelcome
display Welcome to KeyNote
display Press q to quit
end function displaywelcome
The display welcome function has no variables or parameters.
The display keys function displays the list of keys with their corresponding notes see earlier in the design.
begin function displaykeys
display list of keys and notes
end function displaywelcome
The display keys function has no variables or parameters.
The key to pitch takes one parameter:
The key to pitch also has one variable:
Parameter
Range
C Type
Description
key
a, A, w, W, s, S, e, E, d, D, f, F, t, T, g, G, y, Y, h, H, u, U, j, J, k, K, q, Q Other values should be handled as invalid
int
The number of the key that should be translated to a pitch
Variable
Range
C Type
Description
pitch
60 72, 0, 1
int
The pitch of the note to play or zero if the note should not be played, or 1 if the program should exit
Revision 5.1 Introduction to the C Programming Language 149 The way in which the key to pitch function works is very simple, but quite long. It simply recognises
each of the valid key numbers and translates them to a pitch. The pseudocode is shown below:
begin function keytopitch
switch using key
case a or A
set pitch to be 60
case w or W
set pitch to be 61
case s or S
set pitch to be 62
case e or E
set pitch to be 63
case d or D
set pitch to be 64
case f or F
set pitch to be 65
case t or T
set pitch to be 66
case g or G
set pitch to be 67
case y or Y
set pitch to be 68
case h or H
set pitch to be 69
case u or U
set pitch to be 70
case j or J
set pitch to be 61
case k or K
set pitch to be 72
case q or Q
set pitch to be PITCHQUIT
any other case
set pitch to be PITCHINVALID
end switch
return from the function with pitch
end function displaywelcome
This completes the design.
9.4.3 Implementation
You should now take the time to make sure that you understand how the design is proposing to solve the problem. The way that the main function uses the special pitch values PITCH INVALID and PITCH QUIT is quite complicated. Have a think about how this translates into C.
Change the target to lab9. You should find that the lab9.c source file is completely empty. This is ready for your own code.
Exercise 9.5: Implementing the Design
Implement the KeyNote program according to the design. You will need to choose appropriate C statements that match with the pseudocode. You will also need to make sure that you include the correct header files.
150 Introduction to the C Programming Language Revision 5.1
Exercise 9.6: Checking Your Implementation
Test your implementation to make sure that it works. Does it do what you expected it to?
Try out an implementation that a friend has done you could let them try yours. How similar is it? If it is different, why is it different?
If a design is good then different implementations of it should be indistinguishable to a user. Do you think the design could be improved? If so, how?
9.4.4 Extending the Design
You now have the chance to add to the design. Although you are not producing a software report for this program, you should make some notes as if you were writing a proper design. This gives you the chance to practice writing a small part of a design.
Exercise 9.7: Adding to the Design
Imagine that the specification contained an extra point: The program is required to:
allow the user to change the volume at which the notes are played using the up and down arrow keys.
Make notes on how you would amend the design to meet this new part of the specification. Make sure that each decision you take is fully justified.
Exercise 9.8: Implementing Your Design Addition
Follow your design, and implement the additions you have just made. How easy is it to follow your design? Are you having to correct design mistakes whilst you program? Do you think that you missed anything in your design?
9.5 Writing Your Own Report
This section contains some very brief tips to help you write your own software reports. These points should reinforce the material you have covered in the lectures. Each of the sections below is intended to reflect a section of your software report.
9.5.1 Requirements
The Requirements section should state the problem you have been given, in its entirety. You can imagine that the problem you have been given is a problem from a customer, or client. Quite often you will have requirements that are not explicitly stated in the problem. In your case these requirements arise because you are doing a course on C programming. Even though these requirements are implicit, you should still state them. They should include:
the fact that you are expected to use the C programming language;
Revision 5.1 Introduction to the C Programming Language 151 the platform that you are expected to program for a PC running Microsoft Windows;
the graphics or MIDI library you are expected to use.
9.5.2 Analysis
Your Analysis section should take the Requirements section as its starting point. You should then at tempt to analyse the requirements to extract more information from them. This is where you should flesh out the requirements with assumptions of your own, if you have to.
The most important rule is that when you are doing an analysis you must treat the problem as a black box. Treating something as a black box means that you should only be concerned with the the problem itself, and its effects, not how you will solve the problem. You are aiming to gather information so that you can put together a concrete specification for what the software should do.
The main things you should be concerned with in an analysis are:
The inputs to the problem including units and expected range.
The outputs the solution will have to produce including units and expected range.
What kind of screen output is implied by the specification; will it be graphics or text?
What size screen especially for graphics is reasonable on your platform?
What is the available range of midi noteschannels?
All formulae your program will use including calculation formulae and others such as physics, tempo conversion etc.
State how the results of your program will appearsound, in general terms.
Who is your user? What are their needs? Are they technically or musically literate? Are they computer literate?
As a general rule of thumb, it shouldnt matter that you are going to implement your program in C. The design should be independent of programming language. This means that it should not contain C terms like int, double or functions like scanf or midi note.
Be careful not to begin your design in your analysis. You cannot begin a design until you have a formal specification.
9.5.3 Specification
You should use your analysis to put together a list of exactly what your program needs to do. It is very useful if you split this list into things that your program must do, and what it would be desirable if your software did.
You may find it helpful if you number the points in your specification so that you can refer to them in later stages of your report.
9.5.4 Design
As you will have seen in this laboratory, your design is where you make all the major decisions about how your program will work. All these decisions should be made before you begin writing source code because you have a far better understanding of how the different pieces of your program fit together at the design stage.
A good design will be very detailed and should leave very few decisions to the programmer who im plements the design. If you gave your design to someone else to code as well as yourself, a user should not be able to tell the difference between the two versions. No design decision should appear arbitrary they should all be linked to the points in your specification.
Here are some guidelines for things that you should include in your design:
152 Introduction to the C Programming Language Revision 5.1
Describeyouruserinterfaceindetailincludingexactcoordinatesofalllinesonthegraphicsscreen
if appropriate, exact wording of text the user will see and how, when and where this will appear.
Describe all acceptable user input and when it should be accepted by the program.
Include a detailed structure diagram showing data flow between functions or parts of your pro gram.
Give a description of all algorithms used, including how you will validate user input.
Specify a data table showing the name, type and value range of each variable you will use.
There should be a logical flow through your design, starting from the specifications and ending up at a full design for the program.
9.5.5 Source Code Implementing the Design
You will be expected to include the full source code to your software as part of a software report. This is so that someone reading your report can understand how your software works and how they might add to it or change it.
Your code should be well commented. Assume the reader of your code understands C. Comments should explain why something is happening, not what is happening. They way you write code can also help a reader understand it. Make sure that you use variables and programming statements in a logical way. It helps if you choose logical names for variables and functions.
The way that you choose to lay out functions in your source files can heavily influence how logical your program seems to the reader. It is often best to put the main function first, in a C file with the same name as the program.
9.5.6 Implementation Report
Your source code should be supported by an Implementation Report. This section tells the reader how the different elements of the design have been turned into C.
You should include in your implementation report:
decisions you have taken when implementing the design, such as what files you have used and what functions are in them;
the way that your functions in different files interact, along with information about any header files that you have created;
documentation and justification for any changes that you have made to the design whilst doing the implementation.
Someone should be able to understand your source code, and how it works, by reading your design, implementation report and the source code itself.
9.5.7 Verification and Testing
The Verification and Testing section of your report should aim to prove that your software functions correctly. This means that it should always react appropriately to user input, it should meet the speci fication that you set out after your analysis and it should satisfy the requirements that were originally given to you.
Testing software is a very complicated process. A perfect testing process, or regime, would test your software against all the possible inputs it could ever take, in all the conditions it all the conditions it could ever be run, making sure that the outputs are appropriate. In all but the most simple of cases, this is infeasible. It would just take too long. So most software testing is a compromise.
Revision 5.1 Introduction to the C Programming Language 153
With your own testing, you must decide, and justify, what testing is necessary to prove that your soft ware works. You should also comment on how you think your testing regime compares to the ideal in which every part of your program is tested. How much of your program has been tested is often called the test coverage.
Your testing and verification report should:
describe your testing strategy to show that your program works correctly under all conditions; explain why you think you strategy is sufficiently comprehensive;
include all test input data and test results and comment on your test coverage;
detail any modifications you made following test failure and show the results of retesting.
9.5.8 User Manual
You can imagine that most of your software report is written for someone who understands software development in C and wants to understand your program. The user manual, on the other hand, is written for the user that you identified in your analysis. It may be that this user is not technically literate. That way that your user manual is written should reflect the type of person you think will be using your program.
Your user manual should include:
installation instructions this may just be copying the executable file for your program;
user and system requirements you should say what type of computer is necessary to run the program and what kind of expertise you are expecting on behalf of the user;
full usage instructions for all your programs features, ideally with examples;
you might also like to include answers to frequently asked questions FAQs.
9.6 Summary
Now that you have finished this laboratory you should have a good idea of what needs to be in a software design, and how you might go about writing one yourself.
You should also know that the reference section of this lab will be useful to you when you come to write your own software reports.
154 Introduction to the C Programming Language Revision 5.1
Appendix A
Further information about using Code::Blocks
A.1 Introduction
This appendix gives you more detailed guidance on various important aspects of the Code::Blocks clab project that has been created for you to do C programming. There is further infomation about the various software libraries that we have integrated into the clab project to allow you to handle graphics, audio and midi. In addition further guidance is provided on an number of useful topics such as creating your own targets, associating source files with targets and importing source files into targets.
The information in this appendix will be more important as your experience of programming in C de velops and in the construction of your assessed assignment.
A.2 Graphics, audio and music software libraries
The C course has a set of core exercises for all students, but also contains exercises that are degree spe cific. Students on music technology related courses have some additional programming exercises that relate to the manipulation of audio files and the production of computer generated music using MIDI. Students who are not on music technology related courses have additional programming exercises that are based around graphics. However, both groups of students are encouraged strongly to utilize aspects of both graphics and audio in their programming assignment.
In order to circumvent OS specific code for graphics, audio and musicMIDI we use a number of cross platform libraries that provide these functionalities; Allegro for graphics, libsndfile for reading and writing audio files to disk, portaudio for realtime audio capabilities and portmidi for MIDI. All these software libraries are widely used.
These libraries provide the developer with one common programming interface, hiding any system spe cific code. Although you will not deal directly with these libraries it is good to know that all the exercises on this course and the programs that you will develop use them internally. We have created some wrap per functions that utilise the Allegro graphics and libsndfile, portaudio and portmidi libraries. These functions make using these libraries relatively easy.
We chose these libraries for graphics, audio and MIDI for three main reasons:
1. They are written in pure C and are well suited for this course.
2. They are crossplatform libraries meaning that you can write your code once and compile the same code in multiple architectures like for example Windows, Apple OS and Linux.
3. Theyarefreesoftwarewhichmeansthatwecanusethemforeducationalpurposeswithouthaving to pay any license fee.
Four files have been created:
156 Introduction to the C Programming Language Revision 5.1
graphics lib.h which uses Allegro internally and provides graphics capabilities. This must be
included in all program that use allegro graphics.
amio lib.h which uses libsndfile, portaudio and portmidi internally and provides audio and MIDI capabilities. This must be included in all program that use audio or midi functions.
graphics lib functions.c which must be associated with all targets that use graphics. This file gives the implementations of the wrapper graphics functions.
amio lib functions.c which must be associated with all targets that use midi. This file gives the implementations of the wrappers functions for all audio and midi functions.
In C files that end in .h need to be included via a special instructions which begins with the hash symbol. For example:
include graphicslib.h
include amiolib.h
We will discuss these types of instructions later on in the course.
A.3 Project Build Options
Right click on your project clab and select the Build options… menu item. The Project build options window will open. On the left of that window you see a tree structure containing all targets of your project. Clab is your main project and you will see many targets: lab1, lab2 and so on. Each target has its own options Selected Compiler and the settings in each individual tab i.e. compiler settings, linker settings etc. The settings that we are interested in are the following:
Selected compiler: This should always be set to GNU GCC Compiler.
Compiler settings: These settings should be left untouched. Look into the defines tab and youshouldseeALLEGRO STATICLINK.Thisistheonlysettingthatwechangedandensures that the allegro software libraries are statically linked. This allows you to end up with a single executable file that contains all the binaries compiled files inside of it, so when you open your programs folder you see one executable file along with the rest of the files related to your game images, sound etc..
Linker Settings: In this tab all third party libraries are specified. The linker tries to link against the libraries that are found in this page. The Link libraries panel has all allegro related libraries. The Other linker options has some additional libraries related to allegro that we need to link against plus the portmidi and winmm libraries that we need for MIDI functionality. Some targets that do not use these libraries will not have any linker settings.
Search directories: In this tab we have set up the directories that contain the include files header
files and the libraries. The compiler will look into these directories to find any files needed for compiling the source and linking the object file against any needed libraries. First look in the Compiler tab. There are five directories : includeallegro,includeportmidi, includeportaudio, includelibsndfileand include containing the graphics and audio header files and the wrap
per function header files. Now click on the Linker tab. There is only one directory called lib which contains all necessary library files .a and .dll files.
Now close the Project build options window.
A.4 ProjectTargets Options
Right click on your project clab and select the Properties… menu item at the bottom.
The Projecttargets options window will open. This window has many tabs but the only one we are
Revision 5.1 Introduction to the C Programming Language 157
interested in is the Build targets tab. Click on the Build targets tab. This is where we manage all our targets programs. On the left you should see the Build targets panel which lists all the current targets that are included in the project and has some buttons on the right for basic operations; these will be explained in a later section. Now focus on the Selected build target options panel. As the title suggests the settings that you see in this panel correspond to the selected target. Let us now look at each setting separately.
Platforms: This is set to All. It instructs the compiler which OS is the target being built for. Leave this as it is.
Type: This is set to Console application. The kind of programs that we will write are all console applications so leave as is. The Pause when execution ends box keeps the command window open when the program exits. It is checked by default but you can uncheck it if you want. It does not affect the behaviour of the program at run time.
Output filename: This sets the location and file name of the produced executable. In this case it is set to binDebuglab1.exe. This means that when we build the Debug target the executable will be placed inside the binDebug folder and will be given the name lab1.exe. The two boxes below are checked by default. Leave them as is.
Executionworkingdir:ThissetsthelocationoftheexecutablewhenitisrunthroughCode::Blocks. It is set up to be the directory where the compiled executable resides.
Objects output dir: This sets the location of the object files. Object files are produced by the com pilation process. Leave as is.
Now look at the Build target files panel. This is where we specify which source files belong to which targets. When lab1 target is selected you fille find that the lab1.c file is selected, this means that the target only requires this file. Click on the graphics1 target and you will see that the files srcgraphics1.c and srcgraphics lib functions.c are selected in the Build tar get files panel. The file graphics1.c is the source file it contains the main function. The file graphics lib functions.c is a library file that has the source code relating to the graphics functions. It must be part of all projects which use graphics functions. Build target files are source files not .h files that belong to the graphics1 target. Each target will have one or more files assignedassociated to it and this is the place where we can do this. As we will see later on, every time we add a new file in the project we will be given the opportunity to select the target that the importedcreated file belongs to.
Close the Projecttargets options window.
A.5 Creating a Project from a Target
Later on in this course when you develop your own programs you might want to create a separate Code::Blocks project for them. In order to do so:
Execute Project Properties… from the menu bar.
Select the Build targets tab.
Choose one of the targets in the build targets panel
Click on Create project from target button at the bottom of the build targets panel. Give your own name for your this project.
Press ok.
Now using windows explorer navigate to your clab folder and you should see the Code::Blocks project you just created. If you double click on it while Code::Blocks is open with the clab project already open your new project will open on the same workspace. You can close any open project in the workspace by right clicking on the project and clicking on close project. Also note that the new project will have the same settings as the target it originated from. You might like to verify that.
158 Introduction to the C Programming Language Revision 5.1 A.6 Creating new targets
1. Go to the build targets tab in the projecttargets options window right click on clab project and select properties.
2. Select the graphics1 target.
3. Press the Duplicate button.
4. Enter an appropriate target name i.e graphics1 new.
5. Make sure that your newly created target is selected in the build targets panel. Change the output filename from graphics1.exe to your targets name e.g graphics1 new.exe.
6. Close the projecttargets options window. At this point you should have a new target called graphics1 new.
The targets: graphics1.c, graphics2.c, graphics3.c, music1.c, music2.c, and music3.c have the same set tings i.e. both allegro and audiomidi libraries are linked in. Some of the other targets do not have links to these libraries as the exercises are pure C exercises and do not require these libraries. So if you wish to create your own target and you know it will use graphics libraries, then it would be wise to copy and edit one of the graphics targets. Likewise if it is a midi program you wish to work on then it is best to copy and edit a music target. If the program uses neither graphics or midi libraries then copy and edit one of the targets that does not use them typically labX.c, where X is a lab number.
A.7 Associating Source Files to Targets and Creating a New Source File
After you create your targets you need to either import a source file or create a new one. When doing that you have to associate the file with a target.
Execute File New Empty file CtrlShiftN.
Press yes to Add file to project.
Give the source file an appropriate name e.g. myprog.c and save it inside the src directory of your clab folder. This way all your source files are organised. You can create any additional folders inside the src folder, if you wish; anything that suits you.
The multiple selection message will pop up. This is the step where we can select the target that this file should correspond to. Only select the targets you created in the previous section. graphics
new in my example and deselect everything else.
Press ok.
Your file should appear in the projects tab in the management panel and also open in the editor panel.
At this point you are ready to start writing code and building applications.
A.8 Importing a Source File
1. Right click on the clab project in the projects tab, management panel.
2. Click on Add files
3. Select the required source file. It is advisable to have copied your source file inside the src folder of your clab project using windows explorer. This ensures that when copyingmoving your clab project around all your files are copiedmoved together.
Revision 5.1 Introduction to the C Programming Language 159
4. The multiple selection message will pop up. This is the step where we can select the target that
this file should correspond to. Only select the targets you created in section ??
5. Press ok.
6. Your file should appear in the projects tab in the management panel and also open in the editor panel.
At this point you can test your imported source file by building and running the targets.
A.9 Possible errors and solutions
In some cases on the machines in the classroom or your personal machines you might see compiler, debugger or other unexpected errors. Simple solutions to more common problems are presented in this section.
Compiler was not found:
Go to the Settings in the top menu bar. Choose Compiler, Go to Toolchain executables tab and press AutoDetect. If you are still receiving the same error InstallReinstall MinGW and try AutoDetect again.
Debugger was not found:
Go to the Settings in the top menu bar. Choose Debugger and go to the Default on the left
side menu. You will most likely see a red input text box called Executable path. If you are work
ing int the Computer Classroom you should enter Executable path as C:AppsMinGWbingdb.exe. If you are working on your Personal Computer, you will have to find the location of the MinGW installation and you should find gdb.exe in the bin directory.
Program crashes when changing midi instrument using program change function
You have to make sure that the program change function is called after the MIDI has been started midi start has been called. If you close MIDI using midi close and then call program change your program will crash. Instruments can only be change while MIDI is active.
160 Introduction to the C Programming Language Revision 5.1
Appendix B
The C Preprocessor and Useful Debugging Techniques
B.1 Overview
This laboratory covers a number of different topics that are useful to know about when constructing, and particularly, troubleshooting debugging your C programs.
We will look at:
a part of the compiler called the preprocessor, which deals with all of the lines in your code that
begin with a hash or sharp symbol ;
how to use preprocessor commands to stop parts of your program from compiling;
how to use conditional compilation for debugging;
setting breakpoints and using them for debugging your program;
finding the executable file that corresponds to your program and running it without the IDE.
Some of the tasks you do will be different depending on whether you are following the graphics or music option, but there are no special sections for the different options in this laboratory.
B.2 Stages of Compilation
When you build a prgram, the output window shows messages generated by the compiler. If everything goes well, the output window in the Code::Blocks IDE looks like this:
From this window you can see the two major stages of compiling your programs this is a reminder from the first lab:
compiling, which produces an intermediate file called an object file for every source file related to your program;
linking, which combines all of the object files with library files which contain the code for pre existing functions such as printf to form an executable file: your program.
We are going to look at the compiling stage in a little bit more depth.
What we have been called the compiling stage can actually be split into two major parts:
162 Introduction to the C Programming Language Revision 5.1
the preprocessor which processes the text in your source file, before it is passed on to…
the compiler which does the work of translating your text written in C syntax into machine code object files.
The preprocessor takes, as input, a text file, which contains the C program that you have written. It produces, as output, another version of that text file, still in text, but expanded and altered slightly. For example, an important job that the preprocessor usually does is to remove all of your comments from the file so that the compiler never sees them.
The next few sections of this laboratory are going to focus on the preprocessor, to understand what it does and to be able to use it to our advantage.
B.3 Introducing the C Preprocessor
Most of the time the C preprocessor silently goes about its work every time you build your program, for example stripping out comments as mentioned above. Sometimes you might want to communicate with the preprocessor directly. This is done by including preprocessor commands, or directives, in your program. All preprocessor directives begin with the hash or sharp symbol, . Preprocessor directives are not statements, so they are not followed by a semicolon.
You have already used one preprocessor directive many times: include. For example: include stdio.h
You might have noticed that there are two kinds of include directive:
include filename
and
include filename
We will see what the difference is between these forms in a moment. In common with most preprocessor directives, the include directive does not do anything very complicated. When the preprocessor sees a include directive it looks for the file that have specified, for example stdio.h. When it finds the file it simply takes all of the text out of the file an inserts it into your source file in place of the include directive. It does not try and process anything in the file, or try to understand it in any way. That is the compilers job. The difference between enclosing the filename in angle brackets like this stdio.h and quotation marks like this stdio.h is in where the preprocessor looks to find the file you have specified.
Ifthefilenameisenclosedinquotationmarksthenthepreprocessorlooksforthefileinthecurrent folder where your source file is stored before looking in any places that you have specified.
If the filename is enclosed in angle brackets then the compiler assumes it is a standard library header file. Standard library header files describe functions that are part of the the C standard library: functions that are specified as part of the C language. This includes functions like printf and scanf in stdio.h, and getch in conio.h. It does not include any of the graphics or music functions.
So the preprocessor handles a include by finding the file looking where the angle brackets or quota tion marks tell it to look and substituting the entire contents of the file for the include line.
Revision 5.1 Introduction to the C Programming Language 163
Syntax: The include Directive
include filename or include filename
The include preprocessor directive is completed as part of the preprocessor, before the compiler is run. The directive identifies a file filename, which is usually a header file, but can be anything. The directive takes the text from the header file and inserts it in place of the include directive.
The angle brackets and quotation marks determine where the preprocessor looks for the file. As a general rule, angle brackets are for header files that are part of the C standard library such as stdio.h and quotation marks are for header files that are not such as the graphics and music libraries. With most modern compilers including the one you are using, using quotation marks instead of angle brackets or viceversa will not stop your program from working.
B.4 Using the Preprocessor for Text Substitution
A lot of Windows programs, like Microsoft Word, have the facility to search the text of a document to find a particular bit of text that you specify. This is called Find. You may also have come across the facility also in Word to find bits of text and automatically replace them with another bit of text that you specify. This is usually called Replace and is an example of text substitution.
The C preprocessor has a facility for doing text substitution for you. It allows you to define keywords of your own which will get substituted for usually more complicated bits of text, which you specify. This is done using the define preprocessor directive.
Open the appendixa program. This is a very simple example of how to use the define directive for text substitution. The source code for appendixa.c is shown below.
These lines allow the compiler to understand the
printf and getch functions
include stdio.h
include conio.h
An example use of the define directive
The preprocessor will replace HELLOSTRING,
wherever it appears, with Hello, World!n
define HELLOMESSAGE Hello, World!n
A numeric example, wherever PI appears
it will be replaced by 3.14159265
define PI 3.14159265
int mainvoid
Print a message to the screen
printfHELLOMESSAGE;
Display pi
printfPi lf roughlyn, PI;
A program to demonstrate the use of the define directive
C Programming laboratory appendixa
164 Introduction to the C Programming Language Revision 5.1 Wait for a key press
getch;
return 0;
If you build and execute the program you should find that it displays the following text on the screen:
Hello, World!
Pi 3.141593 roughly
Remember that the preprocessor runs through the source code before it gets to the compiler. So the code that the compiler sees looks a bit like this:
…
int mainvoid
printfHello, World!n;
printfPi lf roughlyn, 3.14159265;
getch;
return 0;
Notice how the code was changed by the preprocessor.
Like the include directive, a define is also very simple. It is structured like this:
define tag replacement
The define directive tells the preprocessor: from now on, everywhere you see the text tag, replace
it with the text replacement.
Syntax: The define Directive define tag replacement
Starting from where the define directive is written the preprocessor replaces an occurrence of the text tag with the text replacement.
For example, the directive:
define E CONST 2.71828
replaces any occurrence of the text E CONST with the text 2.71828.
It is generally considered good programming practice to use UPPERCASE names for define tags to visually distinguish them from variable and function names.
define directives are used to define replacement tags for two main reasons: To make your program more readable. For example:
circle area PI radius radius;
Revision 5.1 Introduction to the C Programming Language 165 is a lot easier and quicker to read and understand than:
circle area 3.141592653 radius radius;
To make your program easier to change. For example, it is common to use a define directive for your programs version number. This allows you to put a define directive clearly at the beginning of the source code, like this:
define PROGRAM VERSION 2.3
Somewhere in your source code, perhaps when the program starts, you might write:
printfWelcome to myprog Version lfn, PROGRAM VERSION;
When you make a change to your program, you dont have to go looking for all the places where you display the version number, you simply change the number in the define directive at the top of the source file.
Exercise B.1: Using the define Directive Add to the appendixa example program to:
prompt the user for a number, the radius of a circle;
store the number in variable of type double;
calculate the area of a circle with the radius they entered using PI; display the result.
Exercise B.2: Problems with define Directives
You are now going to change the define PI directive so that it is wrong. Change the line to be
something like this:
define PI error 3.14159265 error ThismeansthatthetextthatwillbesubstitutedforthetagPIwillbeerror 3.14159265 error,
which is obviously not going to be valid C! Try compiling your program.
The compiler will give you an error message. Which line does the compiler think the error is on? Why is this?
If you dont understand this, ask one of the demonstrators to explain it to you. Remember to put the define directive back to how was before you continue.
Choose one of the following two exercises depending on which option you have been doing.
166 Introduction to the C Programming Language Revision 5.1
Exercise B.3: Adding a define Directive: Graphics Option
Open the graphics program you have been working on, which should be called graphics1. The horizontal location of the stick person is controlled by the user. The vertical location is fixed. Use define directives to define tags for:
the width and height of the graphics window. You could call these something like WINDOW HEIGHT and WINDOW WIDTH.
the vertical location of the stick person. You could call this something like PERSON POS Y. the key number for the Enter key 13. You could call this something like ENTER KEY.
Have a look to see what other parts of your program you think would be better substituted for a define tag. Good programming practice says that you should consider using define tags whenever you have a fixed value in your program that you might want to change at compilation time like the window size.
Exercise B.4: Adding a define Directive: Music Option
Open the music program you have been working on, which should be called music2. Add a program change function call for each channel you are using. The instrument number used should be defined as a define tag. For example, the tag PIANO might be defined to be replaced by the number 1, like this
define PIANO 1
Once you have done this add one or more define directives like the following:
define FIRST CHANNEL INSTRUMENT PIANO
You would then change the program change function call to be:
program change1, FIRST CHANNEL INSTRUMENT;
Notice how you are using one define tag to define another. This technique can be very useful in making your program easier to read, understand and change.
Have a look to see what other parts of your program you think would be better substituted for a define tag. Good programming practice says that you should consider using define tags whenever you have a fixed value in your program that you might want to change at compilation time like instruments, maybe even the musical key.
B.5 Using define Directives for Conditional Compilation
In laboratory ?? we saw how to get parts of your program to execute only under certain conditions using an if statement. There is a similar preprocessor directive that allows you to conditionally compile parts of your program under certain conditions. Logically, the directive is called if.
Close whatever program you have open. Change the target to appendixaa and open appendixaa.c in the program editor. You should see that the code is very similar to the example we looked at in the
Revision 5.1 Introduction to the C Programming Language 167
first laboratory. It has some additional lines at the end to display the results, it also has this bit of code:
if definedDEBUG
printftimetofly d, timetodrive dn, timetofly, timetodrive;
endif
What do you think this will do? Try building and executing the program to find out.
Exercise B.5: Investigating Conditional Compilation 1
Make the compiler ignore the line:
define DEBUG
by enclosing it in a comment enclose it between and . Build and execute the program. What has happened?
You should have seen that the code inside if…endif directives is only compiled under certain conditions.
The if directive allows you to set conditions under which parts of your program will be removed by the preprocessor and therefore ignored by the compiler. For example:
if 0 …
endif
will never compile the code between the if and endif directives because 0 is treated as false. On the
other hand, in this example:
if 1 …
endif
the code between the if and endif directives will always be compiled because a nonzero value is treated as true. It is not common to use if directives with a constant value after them like this. It is more common to use them like this:
define ADDEXTRAFUNCTIONALITY 0
…
if ADDEXTRAFUNCTIONALITY
…
endif
This means that the compilation of the section of code between the if and endif directives is de pendent on the value that the ADD EXTRA FUNCTIONALITY tag has defined as its replacement. In the case above, the code between the if and endif directives would not be compiled.
Rather than test the value of a defined tag, it is more common to test whether a tag has been defined at all. You have already seen how to do this in the example program.
168 Introduction to the C Programming Language Revision 5.1
Syntax: The if and endif Directives
if condition …endif
The if directive tells the preprocessor to remove all the parts of your program until the next endif directive, only if the condition is false. When testing the condition, a value of 0 is in terpreted as false; a nonzero value is interpreted to be true.
The most common way to use the if directive is with the special preprocessor syntax definedtag. This tests to see if the specified tag has been previously specified as part of a define directive. It is used in the following way:
if definedSOMETAG
…
endif
You can form more complicated tests using the logical operators , and !. The not operator !
is perhaps the most useful. For example:
if !definedSOMETAG
…
endif
In this case the guarded code would only be compiled if the tag SOME TAG is not defined. There are two very useful abbreviations for these simple operations:
ifdef SOME TAG is short for if definedSOME TAG ifndef SOME TAG is short for if !definedSOME TAG
Exercise B.6: Investigating Conditional Compilation 2
Change the if directive so that the code is compiled only if DEBUG is not defined. You will need to use the information in the syntax box about the if and endif directives to do this.
if directives are very useful for including code such as printf statements which you only want to use for finding problems in your code debugging. It means you can add lots of extra statements to your program and stop them from being seen by the compiler by removing a single define line from the top. Even better, if you find similar problems again, you can add the lines back into your program again by putting just one define line back.
Using if directives for including special lines for debugging is a very useful technique in situations where stepping through your code is tedious. For example, inside a loop you could add an if statement that displays the value after the tenth iteration. The code could be removed from the final program by ensuring that you do not define a DEBUG tag.
B.6 Using Breakpoints for Debugging
Right from the beginning of this course we have used the IDEs debugging facility for stepping through your programs. If you are confident that all of the code at the beginning of you program works then stepping through it to get to the bit you are worried about can be very boring. If you have loops with a large number of iterations then it could take all day!
Revision 5.1 Introduction to the C Programming Language 169 Fortunately, the debugger has a facility for you to be able to specify a line in your source code that you
want to be able to stop on. To do this you mark a line in your code with a breakpoint.
Open a project you have been working on in previous labs. Choose something with a fairly substantial
amount of code in it; a project from your option either graphics or music would be a good idea.
Pick a line of source code that will execute i.e. not a comment and click on it with the righthand mouse button. You should see as menu like this one:
Select the option Toggle Breakpoint.
You should find that the line in the source code that you clicked on now has a red dot at the righthand side of the line.
This indicates that the line in the source code has a breakpoint on it.
Start the program running in the debugger by selecting Debug Start
You should see that the program starts running, until it reaches the breakpoint. It then stops the pro gram, but you have the chance to continue the program from where it is using the step commands or to continue running using the Continue option on the Debug menu. When the debugger stops on a breakpoint, it is exactly as if you had used the step commands to get there, just a lot quicker!
You can remove a breakpoint by clicking on the line of source code with the breakpoint on it using the righthand mouse button. Then choose the Toggle Breakpoint option from the menu.
Exercise B.7: Trying Out the Breakpoint Feature
Now is your opportunity to try out breakpoints. Try setting them, removing them and using them for debugging. Breakpoints are very useful and you will probably find them invaluable when de bugging your programs for your assessments.
B.7 Locating the Programs You Have Written
All the programs you have produced so far do not have to be run in the IDE. In fact, they do not need the C source code or the C compiler to run once you have built them. If you sent your program to a friend you would only have to send them one file: the executable. Just to prove this point you are now going to try executing some of your programs without using the IDE.
First close the IDE; we wont be using it now. Now we have to find the executable file that was built by the compiler and linker from your C source code.
Open up the clab folder that you created in the first lab. You should now see a number of folders: bin, include, lib, obj, src and .objs. Go into the bin folder. You will see two folders: Debug and Release. Double click on the Debug folder to view its contents. You will see many files which has the same name as the targets in the IDE. It will have an icon a bit like this:
This example is for the graphics1 project. This is the executable that was produced when you built the graphics1 or music2 project. If you double click on it, the program will run. Try it.
Exercise B.8: Running Your Programs from Executables
Prove that some of your other programs can be executed this way by finding their executable files and double clicking on them.
170 Introduction to the C Programming Language Revision 5.1
It is important to note that if you were to give your program to someone else to try out, this is usually the only file they would need. Actually, if it is a midi program you may need the file portmidi.dll. The executable file is exactly the same type of file that executes when you run any program on your computer. You could copy this file onto any medium, like a memory stick or a CD, or even make it available over the internet. Anyone with access to just this file could run your program on a MS Windows machine. Note: The program will only run if the operating systems is the same as the one you used when you compiled the program.
B.8 Summary
Now that you have finished this laboratory you should understand the basic functions of the C prepro cessor including the include, define, if and endif directives.
You should be able to use define directives, both on their own, and in combination with if and endif directives for debugging.
You should have seen what a breakpoint does, and understand how to use them to debug your pro grams.
Finally, you should have seen where to find the executable file that corresponds to each of the programs you have written.
Appendix C File Handling
C.1 Overview
Up to this point in the course you have used functions from the standard C library to display information on the screen and receive information from the user. This laboratory will introduce you to a set of very similar functions which allow you to both write and read information tofrom files stored on the computer or a network drive.
In the final part of the lab you will use this to store information from the program you have been working as part of you graphics or music option.
C.2 Getting Access to Files
Since very nearly the beginning of this course you have been using the printf function for output to the screen and the scanf function for input from the keyboard. This lab will use very similar functions, fprintf and fscanf, to output and input tofrom a file.
Before you can either read or write tofrom a file you have to request access to the file. When you do this, the file you have requested is usually locked meaning that only your program can access the file at that time. This is called opening the file. When you are finished with the file you must close it again.
When you open a file you are given a pointer which acts a shorthand for the file you are talking about. This pointer is called a file handle or a file pointer. You get a different file handle for each file that you open. Once you have closed the file, the file handle is no longer valid. A file handle variable is declared like this:
FILE filehandle;
To open a file you should use the fopen function. This function requires two arguments, both of which are strings: the name of the file you want to open and the access mode you wish to have. The access mode is to do with what kinds of operations you wish to carry out on the file. Specifying w indicates that you wish to write to the file; r specifies you wish to read and w specifies that you want to be able to both read and write. For example, the following line of code:
filehandle fopennumber.txt, w;
opens the file numbers.txt for writing. If the fopen function could not open your file, for whatever
reason, the file handle in this case the file handle variable is set to NULL.
When you are finished with the file, you must close it again using the fclose function. This function
takes only one argument: the file handle of the open file you wish to close:
fclosefilehandle;
172 Introduction to the C Programming Language Revision 5.1
Function Reference: fopen Opens a File
FILE fopenchar filename, char access mode; e.g.
filehandle fopendata.txt, w;
secretfile fopenimportant.dat, r;
tempfile fopentemporary.tmp, rw;
The fopen function attempts to open the file specified by the filename argument with the access mode specified by the access mode argument. Both of these arguments should be strings. Valid access modes are:
r open file for reading, the file must already exist;
w open file for writing, if the file already exists it will be overwritten;
a open file for writing, if the file already exists it will be not overwritten, writing takes place at the end of the file this is called append mode;
r open file for both reading and writing, the file must already exist;
w open file for both reading and writing, if the file already exists it will be overwritten;
a open file for both reading and writing, if the file already exists it will be not overwritten, reading and writing take place at the end of the file.
If the file cannot be opened the fopen function returns NULL. The fopen function is defined in stdio.h.
Function Reference: fclose Closes an Open File
int fcloseFILE file handle;
The fclose function closes an open file identified by the argument file handle. If there is a problem during the close operation the fclose function returns the predefined constant EOF. If there were no problems the function returns zero.
The fclose function is defined in stdio.h.
Revision 5.1 Introduction to the C Programming Language 173 C.3 Simple File Read and Write Operations
Change the target to appendixb and open appendixb.c in the IDE. The source code for the ap pendixb.c file is shown below:
A Program to Demonstrate File Handling
Lab appendixb
include stdio.h
int mainvoid
FILE filehandle;
int number;
Ask the user for a number
printfPlease enter an integer number: ;
scanfd, number;
Get access to the file by opening it
filehandle fopennumber.txt, w;
Write a single number to the file
fprintffilehandle, d, number;
Were done with the file, close it
fclosefilehandle;
return 0;
This simple program first obtains an integer number from the user. It then opens the file number.txt for writing. The next line of code uses the fprintf function to write to the file. The fprintf function works exactly like the printf function, or the sprintf function. The difference between the fprintf function and the printf function is that the fprintf function takes an extra first argument: the handle of the file to write to. For example, the code:
fprintffilehandle, Hello;
Outputs the text Hello to the file identified by the file handle file handle. The line in the ap
pendixc program:
fprintffilehandle, d, number;
Outputs the integer number held in the number variable to the file as text.
174 Introduction to the C Programming Language Revision 5.1
Function Reference: fprintf Outputting to a file using printflike place holders
int fprintfFILE file handle, char format string, …;
e.g.
The fprintf function works like the printf function except that, instead of outputting its results onto the screen, it places them into the file specified by the file handle argument. It is called in exactly the same way as printf but with an extra first argument file handle.
fprintf takes at least two arguments but, like printf, it can take more, depending on how many variables you want to include.
file handle is a handle to a file, previously opened with fopen, which will be used as the destination for all fprintf write operations;
format string is a string containing placeholders, just like with printf;
after the first two arguments where the … is you should include variables whose values
will be substituted for the placeholders in the format string. The placeholders you will use most often are:
d for integer int variables; lf double variables;
c for single characters char; s for strings char.
These are the same as for printf.
The return value of fprintf is an integer, which specifies how many characters were written into
the file not including the null termination. This number will be negative if an error occurs. The fprintf function is defined in stdio.h
fprintffilehandle, d, intvariable;
fprintfresultfile, The answer is d, integeranswer;
numchars fprintftempfile, lf, doublevariable;
Exercise C.1: Investigating File Writing
Try building and executing the appendixb program. When it has terminated. Go to the File manager and double click on your clab folder. Find the executable correspondng to appendixb in the Debug folder. You should see a file called number or number.txt. If you double click on this file it will open. You should see that the number you entered into the appendixc program is stored in this file as text. Note, if you ran the program from within the Code::Blocks IDe it actually creates the file number.txt in the folder where the clab project folder sits i.e. the clab folder.
Just as writing to a file can be done with fprintf, reading from a file can be done with fscanf. The fscanf function works just like the scanf function except that it takes an extra first argument: the handle of the file that it should read from. For example, the following line of code reads an integer from
Revision 5.1 Introduction to the C Programming Language 175 a file:
fscanffilehandle, d, intvariable;
Function Reference: fscanf Performs a scanflike read from a file int fscanfFILE file handle, char format string, …;
e.g.
fscanffilehandle, d, anintvariable;
fscanftextfile, c, acharvariable;
numberofmatches fscanfresultfile, lf, adoublevariable;
The fscanf function obtains textual input from the file identified by the file handle argument. This handle must identify a file previously opened by the fopen fucntion for reading. The input is converted according to the format string argument. The format string argument specifies placeholders in an identical manner to the scanf function.
fscanf takes at least two arguments but, like scanf, it can take more, depending on how many variables you want to include.
file handle is a handle to a file, previously opened with fopen, which will be used as the source for all fscanf read operations;
format string is a string containing the place holders that fscanf will try to match input to;
fscanf uses the same place holder system as scanf. As a reminder, the most useful place holders are:
d for integer int variables;
c for single characters char;
lf real valued double variables.
The return value of fscanf is the number of place holders that were successfully matched or the predefined constant EOF End Of File if there was a problem.
The fscanf function is defined in stdio.h.
Exercise C.2: Reading from a File
Alter the appendixb program so that it reads a number back from the number.txt file using fscanf and displays it to the user. Remember to change the access mode in the fopen function call.
C.4 Reading and Writing Many Lines tofrom a File
The fprintf and fscanf operations are very powerful, they are not just limited to writing a single number into a file and reading it back again. There is no reason why you cannot place a fprintf
176 Introduction to the C Programming Language Revision 5.1
function call like:
fprintffilehandle, dn, numbersindex;
into a loop to write many consecutive number to a file from an array. Notice the use of the newline escape sequence n to make sure that each number is on a new line in the file.
The next exercise will use the rand number which is defined in the graphics library file graphics lib.h or the equivalent function random number which was discussed in the music option in lab ?? and is defined in the music library music lib.h 1. The function generates an integer random number within the bounds that are specified by the two arguments to the function. For example, the function call:
number randnumber1, 10;
Will assign a random number to the number variable. The random number will be anywhere between
and including 1 and 10.
Function Reference: rand number Generates a random number
int rand numberint lower range, int upper range;
The rand number function returns a random number which could be anywhere in the range lower range to upper range, including the values lower range and upper range. For ex ample:
x randnumber60, 71;
will assign a value to x that could be 60, 71 or any integer value inbetween. rand number is defined in graphics lib.h.
Exercise C.3: Writing Multiple Numbers to a File
Alter the appendixb program so that it fills an array of 40 elements with random numbers and writes all of the numbers to a single file. Each number should be on a new line in the file. Open the file you have written into to check the write operation worked correctly.
Adjust the program to write 500 random numbers between 1 and 100 to a file called numbers.txt.
Exercise C.4: Reading Multiple Numbers from a File
The appendixba program is a nearlyempty template for this exercise, change the target to appendixa and open the source file in the IDE. Write a program that opens the file that was to written by the program in Exercise ??. It should read 20 numbers from this file into an array. At the end of the program it should display the numbers.
1the reason why each library has an implementation of the same function with a different name is so that if both libraries were included in a program, no conflict would occur.
Revision 5.1 Introduction to the C Programming Language 177
Exercise C.5: Making the Read Operation More Flexible
The appendixba program you have just written depends on there being 20 numbers in the file it is reading from. If there are more than that, the numbers do not get read. If there are fewer, there will be a problem. In this case the fscanf function will return the constant EOF, which stands for End Of File.
Alter the appendixba program so that it will read any amount of numbers in from a file. The numbers should be read into an array, the memory for which is dynamically allocated using malloc. To do this the simplest thing to do is read the file twice a:
once to determine how many numbers there are in the file so that you can allocate the array; a second time to read the numbers into the array.
aUsing a standard C function called realloc which allows a redefinition of the memory required for an array makes it possible to acheive this with a single read of the file
C.5 File Operations with Structures
The examples we have looked at so far have only written or read a single number with each fprintf and fscanf function call. There is no reason why this has to be the case. A fprintf function call could insert multiple numbers into a file, like this:
fprintffilehandle, d, dn, firstnumber, secondnumber;
This would write two numbers on a single line in the file, separated by a comma and a space. To read these numbers back in from the file we would use the following fscanf function call:
fscanffilehandle, d, dn, firstnumber, secondnumber;
There is also no reason that we must only work with numbers. We may also work with strings.
In labs ?? you worked with a structure which stored information about a student. You created a type definition for this structure called student type. To write information from this type of structure to disk you would use a piece of code like the following:
fprintffilehandle, s, , student.familyname;
fprintffilehandle, s, , student.givenname;
fprintffilehandle, d, , student.yearofbirth;
fprintffilehandle, dn, student.coursecode;
Notice that each of the pieces of information about the student will all appear on the same line in the file, each separated by a space and a comma. A similar system could be used for reading information in.
178 Introduction to the C Programming Language Revision 5.1
Exercise C.6: Reading and Writing Structure Information tofrom a File
Alter the appendixb program so that it prompts the user for details about a student and stores them in a structure. Write a separate function which will write the details of that student to a file. The student details should all appear on the same line in the file, separated by commas.
The appendixbb program is another nearempty template. Basing your appendixbb program on appendixba, write a program which uses a separate function to read the details of a single student in from the file that was written to by the appendixb program. The program should display the details it reads in.
You might like to copy some of your code from the program you worked on in lab ?? to make this task easier.
Exercise C.7: Adding Save and Load Functionality to a Program
If you have been following the graphics option, change the target to graphics3; if you have been following the music option, change the target to music3 and open the corresponding source code in the editor window. Each of these programs use an array of structures to store either a drawing in the case of the graphics option or a musical sequence in the case of the music option. Based on the exercises you have done in this lab, add functionality to your program to allow the user to save the contents of the array to a file, or to load all the information from a file into the array. This will allow a user to save and then reload their drawing or sequence.
C.6 Summary
Now that you have finished this laboratory you should understand how to carry out basic file opera tions. You should know that:
to begin operating with a file, you must open it with the fopen function;
when you have finished using the file you should close it with the fclose function;
when operating on the file you use an identifier that you obtained from the fopen function called a file handle;
you can write to the file using the fprintf function, which is very similar to printf;
you can read from the file using the fscanf function, which is very similar to scanf.
You should have used these concepts to add load and save functionality to the program that you have been working on as part of your option. This gives you the ability to save drawings as a file in the case of the graphics option or musical sequences as a file in the case of the music option.
Appendix D
Structuring a Software Project
D.1 Overview
This laboratory introduces good programming practice for structuring software projects. As your pro grams grow you will find that it is useful to split the functions you write across multiple source files. This laboratory teaches you the best way to do this. Although the concepts that are introduced in this lab will not have an effect on how your programs look once they are built, well structured source code is important. By using multiple files you can make your programs easier to understand and debug. You can also make it easier to reuse code you create for one program when you are writing another. Something which could save you a lot of effort!
Finally, a few tips on good programming practice are covered. Focussing on how to use indentation to make your programs more readable, and how to use the IDE to do this easily.
D.2 Splitting Your Program into Multiple Files
In laboratory ?? you learned how, and why, to split your programs into functions. One of the most important effects of splitting your code into functions is to wrap it up or encapsulate it into small chunks which can be reused easily. To be able to reuse your function in another program, you have had to copy it and paste it into another source file.
It is usual for more complicated C programs to be made up of more than one source file. Each source file typically contains multiple functions. The reasons for doing this are very similar to the reasons for using functions in the first place:
using multiple files adds structure to your program and makes it easier to understand. For exam ple, you could collect all the functions that produce output on the screen into one file, making it easier to find functions of a particular type.
putting a set functions into a file allows you to use the same file in multiple projects. If there are bugs in the functions in that file, you only have to fix them once, rather than having to change the code in every project it is used in.
In this lab you will learn how to split your source code into multiple files, by placing different functions in each file.
It is assumed that you have created independent projects for your option work. If you have been doing the graphics option it is assumed that the name of his project is graphics1 and if you have been doing the music option, then it is assumed that the name of the project is music1. If you do not know how to create your own project then look back at lab 1.
Begin by opening the project that you have been using for your option work in the IDE. These programs are getting quite complicated by now, and probably contain a number of functions. You are going to separate these functions into two files depending on their role in your program.
180 Introduction to the C Programming Language Revision 5.1
Exercise D.1: Deciding on a File Structure
Before you actually create any new files, or change your program in any way, you should decide how, and why, you will structure the files.
Decide how many files you want to use. This should be more than one and no more than about four at the moment. This decision should be based on what each of the functions you have written do. Some things to think about:
You could collect together into one file the functions which interact with the user.
If the main function is very complicated, you might want to leave it in a file on its own. You might want to collect the graphicsmusic functions together into one file.
Dont make things more complicated than necessary; try to create a structure which is logical and would help someone else understand your program. Decide on names for your files which reflect what they do. To keep things simple, it is best to avoid file names that have spaces in.
Make some notes about your file structure to help you remember your decisions.
You can now create a new file in which to place some of your code. Select the New item from the File menu. Select Empty file. You will see a message about whether you want to add the new file to your active project. Say Yes. You will then be able to edit your new file.
A blank file will appear in the editor ready for you to put some source code in it. Copy or cut and paste at least one function into this file. You will need to include any header files which the function needs. Save the file with the extension .c. The best place to put the file is in the src directory where all the source files are located.
Repeat the process until you have the file structure that you decided on. If you want to remove a file from your project, select the file in the source file tree and press the Delete key. This will not actually remove the source file from the folder. But it will remove it from the project, so it is no longer part of your program.
You should now have a set of source files, which are all part of your program, and are all shown in the source file tree on the lefthand side of the IDE window. Each function in your program should only be in one of these source files.
Unfortunately, you are not yet ready to build your program. At the moment there is no way for a function in one file to know about a function in another file. To understand this, we must look at how projects are compiled and linked. You should remember from earlier labs that programs are built in two stages:
compilation which produces an object file for each source file;
linking which joins all of the object files together to make one executable.
The important part of this process is that the compiler only ever works on one source file at a time. This is shown in the diagram below:
In this example, the graphics1 project is being built. There two source files: graphics1.c and graph fun.c. The compiler first works on the graphics1.c file and produces the intermediate file graphics1.obj. It
then works on the file graph fun.c and produces the intermediate file graph fun.obj. The compiler
has now finished its work. The linker now runs. It takes the intermediate files graphics1.obj and graph fun.obj and combines them together to make the executable file graphics.exe. The files in
your project will probably have different names, but the principle is the same.
To make sure that you dont get compiler errors or warnings, you must make sure that for each function that is used in one file, and declared in another, you must specify a prototype for that function. So, for
Revision 5.1 Introduction to the C Programming Language 181 example, in the example above:
say graph fun.c defines a function called show welcome, which is called by the main function in graphics1.c;
for the compiler to know that the function exists in another file, there must be a prototype for show welcome in graphics1.c.
This situation is shown in the diagram below:
Exercise D.2: Declaring the Correct Prototypes
You should now have created the files that you decided on, and moved the parts of your source code to the relevant files.
Make sure that each source file you have created contains the prototypes of each of the functions it needs that are in other files. It is standard practice to put a comment at the top of each file docu menting what the purpose of the functions in the file are. Make sure you add a comment like this to the top of each file that you create.
Your program should now build and execute without warnings or errors.
D.3 Creating Your Own Header Files
To decide what prototypes are necessary you have to check your source file to find out what functions if any you use from other files. When your source files are large it is easy to forget which functions are called. Including prototypes which are not called will not generate an error or warning, but it is misleading for anyone reading your source code. The need to include prototypes for each function called in another file is inconvenient when you want to use one source file in more than one project.
The easiest way to solve these problems is to place the prototypes for all the functions in particu lar source file into a header file with the same name. For example, assume that a source file called graph fun.c contains the following functions:
show hello
draw stick person draw throw
To accompany this source file a header file called graph fun.h should be created. A header file is just like a source file, except that the code that it contains shouldnt be code that actually executes. For example, the header file graph fun.h will only contain function prototypes. The function prototypes will used by the compiler and linker to match up the functions in graph fun.c to other files in which they are called. The function prototypes themselves are not converted into executable code.
In our example, the header file graph fun.h should contain the prototypes for the three functions in graph fun.c. For example, the contents of graph fun.h might be as follows:
Header file for graphfun.c
Function prototypes only
void showhellovoid;
182 Introduction to the C Programming Language Revision 5.1 void drawstickpersonint x, int y;
void drawthrowint x, int y, double velocity;
As you can see, header files can be very short!
In the file graphics1.c, which uses the functions show hello, draw stick person and draw throw,
the header file must be included with the line
include graphfun.h
There is now no need to put any prototypes for the functions show hello, draw stick person and draw throw in graphics1.c. If we wished to use any of these functions in another file, we would simply put the include directive at the top of the file. You will remember from laboratory ?? that the include directive just includes the source from the file that is named into the current file. In this case it is used to make sure that prototypes for the functions in graph fun.c are included wherever they might be used.
Creating a new header file is very similar to creating a new source file. Choose New from the File menu: However, when you save it you should make sure that your file name ends in .h.
Exercise D.3: Creating Header Files
You should now create a header file for each one of your source files which contains functions that are used by another file. For example, if the file music1.c contains functions that are called only by other functions inside the music1.c file, there is no need to create a header file for it.
Use appropriate include lines to allow you to remove function prototypes from your source files. Your program should still build and execute correctly.
D.4 Protecting Your Header Files
You have just created header files which allow you to encapsulate a set of functions in a source file in a way that makes them easy to use in other source files. Sometimes header files will have include di rectives in them which include other header files. These header files may also have include directives and so on. The process can become very complicated. In these situations two problems can occur:
a circular reference can occur. This is where one header file includes another header file which includes the original header file. The compiler would then travel round this loop forever actually it would run out of memory and crash, which is probably worse.
a header file can be included into the same source file twice. If the header file only contains pro totypes this is not a problem because you can declare the same prototype as many times as you want as long as the definitions are the same. Later in the course you will put more complicated things in header files which can only be seen by the compiler once for each source file it processes.
Both of these problems can be solved if we make sure that the contents of a header file are seen only once by the compiler for each source file. We can do this by using the define, ifndef and endif preprocessor directives you met in laboratory ??.
Let us take the example of a header file called graph fun.h. At the top of the header file there should be a line which checks to see whether a label has been defined. The label must be unique to the header file. To try and ensure that the label is unique the name of the file is often used in some way. It is most common to use a label which is made of two underscores , the name of the file except for the .h extension another underscore, the letter H and finally another two underscores. As with all preprocessor labels, it is good programming practice to use only UPPERCASE letters for these labels. For example, for the header file graph fun.h we would use the label GRAPH FUN H . We would check whether it is defined using the preprocessor directive ifndef like this:
Revision 5.1 Introduction to the C Programming Language 183 ifndef GRAPHFUNH
If the label has not been defined then the preprocessor will continue reading the contents of the file. To make sure that the file does not get processed again, the first thing we do is define the label using the define directive like this:
define GRAPHFUNH
At the end of the source file we must include a endif directive to match the ifndef directive, like
this:
endif
Now that the compiler has seen the contents of the header file once the label GRAPH FUN H has been
defined. If the header file is included again, the compiler will reach the line:
ifndef GRAPHFUNH
where it will find that the label GRAPH FUN H has already been defined. It will therefore skip to the endif directive at the end of the source file. So the contents of the header are only processed once no matter how many times the file is included.
The example header file that we looked at earlier, graph fun.h should look like this:
Header file for graphfun.c
Function prototypes only
ifndef GRAPHFUNH
define GRAPHFUNH
void showhellovoid;
void drawstickpersonint x, int y;
void drawthrowint x, int y, double velocity;
endif
This system of protection, made up of a define directive, a ifndef directive and a endif directive
is called a sentry.
Exercise D.4: Adding Sentries to Your Header Files
Make sure you understand how sentries work, and why they are useful. If you need any help, ask one of the demonstrators.
Include the correct preprocessor directives to make a sentry in each of your header files. Your pro gram should still build and execute correctly.
D.5 Good Programming Practice: Some More Tips
This course has stressed, many times, the importance of creating source code that is easy to read and understand. The best way to achieve this is:
structure your code logically into functions which allow for reusability;
184 Introduction to the C Programming Language Revision 5.1
structure your functions logically into different source files;
use header files so that your source files are easily reused and are not cluttered with prototypes;
documentyoursourcecodewithplentyofcommentsthatareaimedatsomeonewhounderstands C but does not necessarily understand how your program works.
You can make your easy to read through careful use of indentation. Indentation is about changing where a line of code in your source file has its lefthand edge. It is very useful for making the structure of code inside functions clear. You should control where the lefthand edge of your lines of source code are using the Tab key. Whenever you start a new structure, like an if statement or a while loop, you should indicate which lines are part of this structure by moving the lines to the right by inserting a tab character at the start of each line.
For example, an if statement should always be structured like this: if numberentered 10
printfThats less than 10n;
Notice how the printf line is indented by one tab character relative to the if clause. The next line after this one is not part of the if statement and so should start in the same vertical position as the if clause.
The editor in the IDE will try to carry out the correct indentation for you automatically. Sometimes, however, it may get it wrong. You can move a line to the right by placing the text cursor at the beginning of the line and pressing Tab, which inserts a tab character. You can move the line left by holding down the Shift key and pressing Tab.
In the IDE editor, this also works with blocks of code. If you highlight a block of code, like this:
and press the Tab key, the editor inserts a tab character at the beginning of every line in the block. The block of code therefore moves to the right:
You can move a block of code to the left by highlighting it and holding down the Shift key when you press Tab.
Exercise D.5: Cleaning Up Your Code
To make sure your code is easy to understand you should:
make sure you have commented your code thoroughly. If you are unsure, ask a friend to have a look at your code and see if they can understand what it does and how it works.
make sure your indentation is correct and consistent. If you are unsure about this, check with one of the demonstrators.
There are no hard and fast rules for how to lay out and comment your source code in C, although there is some generally accepted good practice. With things like indentation it is most important that you are consistent across all of the source code in your project.
D.6 Summary
Now that you have finished this laboratory you should have either a music or graphics project that is split into multiple files in a logical way. It should use header files, protected by sentries, to allow easy
Revision 5.1 Introduction to the C Programming Language 185 use and reuse of the code your have written. You should understand the reasons for wanting to structure
your code into multiple files, and how to apply these techniques to other projects.
You should also have spent some time making sure that you code is wellformatted, wellcommented and easy to read.
You are now ready to tackle larger projects.
186 Introduction to the C Programming Language Revision 5.1
Appendix E
Graphics: Mouse control
E.1 Overview
This appendix explains how to detect events e.g. display and mouse operations and use a number of functions that relate to using the mouse.
The appendix is only relevant if you are using the graphics library graphics lib.h. E.2 Event detection
We will discuss in detail a small program that allows the user to draw on the display using either a filled or unfilled circle. It will detect where the cursor cordinates are and whether the left and right mouse buttons have been pressed. It also will count the number of times the right mouse button is pressed down and allow the selection of various actions depending on that. It will close the graphics window down if the left mouse button is depressed. It employs a while loop to allow the user to draw using circles unless either the left mouse button is depressed or the graphics window is closed.
E.3 Examining the mouse program mouse.c
Assuming you have the clab project open in Code:: Blocks change the target to mouse and open the source code for the mouse program mouse.c. We will examine this program now.
The program mouse.c begins with some include statements which allow the use of the graphics wrap per functions defined in graphics lib.h and a few other libraries in the standard C library. Then inside the main function we define some local variables that are used by the program. To use the mouse we have to initialize it with the function initmouse.
include graphicslib.h
include stdio.h
include conio.h
int mainvoid
int done 0, overpaint 0, outlined 0;
int hidecursor;
int xpos, ypos;
int numclicks 0;
initialize the graphics window
initwindow640, 480;
188 Introduction to the C Programming Language
Revision 5.1
setbkcolorBLACK;
cleardevice;
setcolorBLUE;
initialize the mouse
initmouse;
create an event queue
createeventqueue;
register display and mouse as event sources
regdisplayevents;
regmouseevents;
printfnDo you want to hide the mouse cursor? 0 NO, 1 YES ;
scanfd, hidecursor;
if hidecursor
hidemousecursor;
initfont;
xpos 320;
ypos 240;
outtextxy5,5,Press left mouse button to quit;
while !done
wait for event
waitforevent;
if graphics windows closed then exit loop
if eventclosedisplay
done 1;
else if eventmousepositionchanged mouse moved
getmousecoordinates;
xpos XMOUSE;
ypos YMOUSE;
else if eventmousebuttondown
if eventmouseleftbuttondown if left mouse button down
done 1;
if eventmouserightbuttondown if right mouse button down
numclicks;
count clicks from 0 to 3
numclicks numclicks 4;
if numclicks 0
overpaint 0;
outlined 0;
Revision 5.1
Introduction to the C Programming Language 189
else if numclicks 1
overpaint 0;
outlined 1;
else if numclicks 2
overpaint 1;
outlined 0;
else if numclicks 3
overpaint 1;
outlined 1;
if outlined
setcolorBLUE;
circlexpos, ypos, 10, 2; outlined circle
else
filledcirclexpos, ypos, 10 ,BLUE; filled circle
updatedisplay;
if overpaint
filledcirclexpos, ypos, 10 ,BLACK;
Wait for a key press
printfnPress a key to quit;
getch;
close the mouse
closemouse;
remove the display
closegraph;
return 0;
To detect events like the mouse cursor position being changed, or whether a mouse button is being pushed down we need to create an event queue. This is done by calling the function create event queue. Next we register both the display and the mouse state as sources of events, so that changes in them will
be detected as events. This is accomplished with the calls to the functions reg display events and reg mouse events.
The program allows the user to decide whether they would like to show or hide the mouse cursor while
it is inside the graphics window. Often graphics application programs have their own cursor or do not show the default cursor. This is accompliashed in the program by calling the function hide mouse cursor.
After outputting a message to the graphics window the program enters the game loop which is the code in the scope of while statement. The first statement inside the loop is wait for event. This waits for the user to do something. In this case, doing something, means either closing the display, moving the mouse, or pressing a mouse button. These events are detected through a number of functions which
190 Introduction to the C Programming Language all begin with event. These are respectively:
eventclosedisplay
eventmousepositionchanged
eventmousebuttondown
eventmouseleftbuttondown
eventmouserightbuttondown
Revision 5.1
If the mouse position has changed the program needs to know where to draw the new circle i.e. it needs the current position of the cursor. This is done by first calling get mouse coordinates. This function changes two integer global variables, XMOUSE and YMOUSE which hold these coordinates. The program then assigns these to some local variables, x pos and y pos
The program counts the number of right mouse button clicks and according to the remainder on division of this number by four, sets a number of circle drawing actions. The remainder on division by operation is given by the symbol. This is a very useful command. Its role here is to make sure that num clicks has only one of four values: 0, 1, 2, 3. These values are used as options which change the nature of the circle drawing operations through the local variables, outlined and overpaint. It is important to realise that the call to update display copies the screen buffer to the active display, which means that it will draw blue circles at the current values of x pos, y pos but overwrite in black if overpaint is 1 the circle drawn in the previous position.
The main function ends with some closedown operations.
We give the reference to the new graphics functions that have been used in mouse.c below.
Function Reference: initmouse Sets up the mouse for use initmouse;
The initmouse function initializes the mouse so that mouse actions can be detected and acted on. initmouse is defined in graphics lib.h.
Function Reference: create event queue Create an event queue create event queue;
The void create event queue function initializes an event queue so that types of events can be detected.
create event queue is defined in graphics lib.h.
Function Reference: reg display events Allow display events to be de tected
reg display events;
The void reg display events function allows display events to be detected. reg display events is defined in graphics lib.h.
Revision 5.1 Introduction to the C Programming Language 191
Function Reference: reg mouse events Allow mouse events to be detected reg mouse events;
The void reg mouse events function allows mouse events to be detected. reg mouse events is defined in graphics lib.h.
Function Reference: hide mouse cursor Hide the mouse cursor in the dis play window
hide mouse cursor;
The void hide mouse cursor function prevents the mouse cursor from being visible in the display
window.
hide mouse cursor is defined in graphics lib.h.
Function Reference: event close display Detect whether the display win dow has been closed
event close display;
The int event close display returns 1 if the display window has closed otherwise it returns 0. event close display is defined in graphics lib.h.
Function Reference: event mouse position changed Detect whether the mouse position has changed
event mouse position changed;
The int event mouse position changed returns 1 if the mouse has been moved, 0 otherwise. event mouse position changed is defined in graphics lib.h.
Function Reference: get mouse coordinates Get the integer coordinates of the mouse cursor
get mouse coordinates;
The void get mouse coordinates writes the integer coordinates of the mouse cursor to global
variables XMOUSE and YMOUSE.
get mouse coordinates is defined in graphics lib.h.
192 Introduction to the C Programming Language Revision 5.1
Function Reference: event mouse button down Detect whether a button on the mouse is pressed
event mouse button down;
The int event mouse button down returns 1 if any mouse button is down, otherwise it returns 0. event mouse button down is defined in graphics lib.h.
Function Reference: event mouse left button down Detect whether the left button on the mouse is down
event mouse left button down;
The int event mouse left button down returns 1 if the left mouse button is down, otherwise it
returns 0.
event mouse left button down is defined in graphics lib.h.
Function Reference: event mouse right button down Detect whether the right button on the mouse is down
event mouse right button down;
The int event mouse right button down returns 1 if the right mouse button is down, otherwise
it returns 0.
event mouse right button down is defined in graphics lib.h.
Function Reference: closemouse Shut down the mouse reading functions closemouse;
The void closemouse closes down the mouse as an event device. closemouse is defined in graphics lib.h.
E.4 Running and altering the mouse program
Build and execute the program mouse.c. Do this from the command prompt window. Choose to hide the mouse cursor and try moving the mouse and depressing the right mouse button. It is easy to get interesting looking pictures! Left click the mouse and you will find the graphics window closes and returns the program to the command prompt. Run the program again and after you have finished drawing close down the graphics window by clicking the X at the top right corner.
Revision 5.1 Introduction to the C Programming Language 193 E.5 Summary
After reading through this appendix and running the mouse program, you should have a good idea how to use the mouse in your programs. If you are doing the music option and want to use the mouse in your program you will have to include the graphics library graphics lib.h in your code.
194 Introduction to the C Programming Language Revision 5.1
Appendix F
Graphics: Simulating movement and keyboard event handling
F.1 Overview
This appendix explains how to create the fast movement of mutiple graphical primitives. It also explains how you can detect keyboard events using allegro. This is much more convenient that using getch which pauses the program. It is only relevant if you are using the graphics library graphics lib.h.
F.2 Movement
We have already seen how the appearance of movement can be made. The principle is this. We draw a graphical element on an area of the display and then subsequently we paint over it with the same colour as the display background. We can paint over using any the filled functions: filled circle, filled ellipse , filled rectangle. Alternatively we can used the cleardevice function, which clears the entire display area by paiting over it with the background colour.
To give the appearance of multiple graphical elements moving we simply need to draw multiple ele ments and redraw them in a new position and paint over the previous drawn elements with the screen background colour. We will discuss in detail a small program that gives the appearance of two balls endlessly bouncing off walls. Often when you have simulated movement, you need some user input that can decide to stop the movement or carry out another action. The example program will allow this by having a mouse event handler that checks if the user has pressed the right mouse button. If so, it will halt the movement of the balls, resuming their movement after the right mouse button is released. It will also shut down the graphics window when the left mouse button is pressed and end the whileloop in preparation for terminating the program.
Finally, the program introduces keyboard event handling in allegro. This allows detection of keyboard events while the ball is moving, without causing any delay in the movement unlike using getch.
F.3 Examining the program events.c
Assuming you have the clab project open in Code:: Blocks change the target to events and open the source code for the mouse program events.c. We will examine this program now. The program begins with some include statements which allow the use of the graphics wrapper functions defined in graphics lib.h and a few other libraries in the standard C library. Then it defines some useful global constants that are used by the program.
include graphicslib.h
include stdio.h
include conio.h
196 Introduction to the C Programming Language include math.h
define XWINDOW 640
define YWINDOW 480
define TICK 0.5
define RADIUS 10
Revision 5.1
define XMAX
define XMIN
define YMAX
define YMIN
define MAXCOUNT 10000
XWINDOW RADIUS
RADIUS
YWINDOW RADIUS
3RADIUS
make a data type hold position and velocity
typedef struct
double pos;
double vel;
posvel;
posvel hitboundarydouble pos, double vel, int isx;
It defines a data structure called posvel which allow variables to be used that hold two double precision numbers accessed via the structure member variables pos and vel. The data structure is very useful in a function called hit boundary. The function hit boundary checks when the two balls encounter a boundary. If they do, then they are made to appear to bounce of the walls. This requires a change to their position and velocity. The hit boundary function is shown below:
handle what happens to balls at boundaries of the graphics window
posvel hitboundarydouble pos, double vel, int isx
posvel z;
z.pos pos;
z.vel vel;
if isx
if pos XMIN
z.pos XMIN;
z.vel vel;
else if pos XMAX
z.pos XMAX;
z.vel vel;
else
if pos YMIN
z.pos YMIN;
z.vel vel;
if pos YMAX
z.pos YMAX;
z.vel vel;
Revision 5.1 Introduction to the C Programming Language 197
return z;
The parameter isx which takes the values 0 or 1 is used to choose whether the boundary apply on the vertical or horizontal boundaries. If the balls do not hit boundaries then the function just returns the original values of position and velocity supplied by the calling function in this case, the main function.
The main function is given below:
int mainvoid
int count 0;
int Gpressed 0, Rpressed 1;
char vstring10, wstring10;
double x1old, y1old;
double x2old, y2old;
double x1new, y1new;
double x2new, y2new;
double vx, vy, wx, wy;
double v, w;
posvel pv;
x1old 100.0; y1old 100.0;
vx 10.0; vy 5.0;
x2old 250.0; y2old 250.0;
wx 8.0; wy 4.0;
v sqrtpowwx,2powwy,2;
w sqrtpowvx,2powvy,2;
open the graphics window
initwindowXWINDOW, YWINDOW;
allow mouse operations
initmouse;
allow keyboard operations
initkeyboard;
create an event queue
createeventqueue;
register display, mouse and keyboard as event sources
regdisplayevents; regmouseevents; regkeyboardevents;
initialize the font
initfont;
outtextxy4,5,To quit press left mouse button or close graphics window;
outtextxy4,15,To pause press right mouse button;
outtextxy4,25,To change ball speed use arrow keys updown red, leftright b
outtextxy4,35,To make the red ball green press G or g ;
198 Introduction to the C Programming Language do
Revision 5.1
if checkifevent
wait for event
waitforevent;
if eventclosedisplay
break;
else if eventmousebuttondown
if eventmouseleftbuttondown
break;
else if eventmouserightbuttondown
waitforevent;
else if eventkeydown
change speed of first ball
ifeventkeyuparrow
vx 1.25vx;
vy 1.25vy;
else ifeventkeydownarrow
vx 0.75vx;
vy 0.75vy;
else ifeventkeyleftarrow
wx 0.75wx;
wy 0.75wy;
else ifeventkeyrightarrow
wx 1.25wx;
wy 1.25wy;
if eventkeyG
Gpressed 1;
Rpressed 0;
else if eventkeyR
Rpressed 1;
Gpressed 0;
v sqrtpowwx,2powwy,2;
w sqrtpowvx,2powvy,2;
calculate new ball positions
x1new x1old vxTICK;
y1new y1old vyTICK;
x2new x2old wxTICK;
y2new y2old wyTICK;
handle what to do if balls hit boundaries
Revision 5.1 Introduction to the C Programming Language 199
pv hitboundaryx1new, vx, 1;
x1new pv.pos;
vx pv.vel;
pv hitboundaryx2new, wx, 1;
x2new pv.pos;
wx pv.vel;
pv hitboundaryy1new, vy, 0;
y1new pv.pos;
vy pv.vel;
pv hitboundaryy2new, wy, 0;
y2new pv.pos;
wy pv.vel;
draw balls on screen buffer in new positions
filledcirclex1new, y1new, RADIUS , BLUE;
if Gpressed
filledcirclex2new, y2new, RADIUS , GREEN;
else if Rpressed
filledcirclex2new, y2new, RADIUS , RED;
make the balls visible on the screen display
and remove the balls in the previous positions
sprintfvstring, 4.2lf, v;
sprintfwstring, 4.2lf, w;
setcolorRED;
outtextxyVELTEXTX,VELTEXTY,v ;
clear area for numeric output
filledrectangleVELTEXTX40, VELTEXTY10, VELTEXTX100, VELTEXTY20,
outtextxyVELTEXTX60,VELTEXTY,vstring;
setcolorBLUE;
outtextxyVELTEXTX120,VELTEXTY,w ;
clear area for numeric output
filledrectangleVELTEXTX160, VELTEXTY10, VELTEXTX220, VELTEXTY20,
outtextxyVELTEXTX180,VELTEXTY,wstring;
updatedisplay;
remove the balls in the previous positions on
the screen buffer
filledcirclex1old, y1old, RADIUS , BLACK;
filledcirclex2old, y2old, RADIUS , BLACK;
update the old positions
x1old x1new;
y1old y1new;
x2old x2new;
y2old y2new;
count;
pausefor8; wait 8 miliseconds
while count MAXCOUNT;
close the mouse
200 Introduction to the C Programming Language closemouse;
remove the display
closegraph;
return 0;
Revision 5.1
If you are familiar with appendix ?? which discussed how to register display and mouse events, you will be familar with many of the functions within the main function. However several new functions have been introduced. The first is a function that allows the execution of a program to pause. The graphics library graphics lib.c has its own pause function called pausefor. It is defined below:
Function Reference: pausefor Waits for a specified amount of time
pauseforduration;
The pausefor function causes the computer to wait before continuing. The amount of time the computer waits for is determined by the duration argument, which is a integer number, and spec ifies the amount of time the computer should wait for in one thousandths of a second milliseconds.
For example:
pausefor500;
will cause the computer to wait for half a second 500 milliseconds before continuing. pausefor is defined in graphics lib.h.
Another new function check if event is extremely useful in a situation where the computer is exe cuting a loop but you want it to be able to be interupted without causing any appreciable slowing down of the loop. You see the idea of the bouncing balls is that you want them to continue doing this until the user carries out a specific action. In this case the action is either closing the display or clicking a mouse button, or detecting what keys have ben pressed on the keyboard.
Function Reference: check if event Detect whether any new event has been added to the event queue
check if event;
The int check if event returns 1 if a registered event source has encountered an event, otherwise
it returns zero.
check if event is defined in graphics lib.h.
Although it was not used in this program another useful function is one that can add random variation. For instance we could have made the balls bounce off the walls at random angles. The function is called rand number and is defined in the graphics library graphics lib.h and the equivalent function random number is defined in amio lib.h. The definitions of these function were given in appendix ?? and lab ??.
Other functions introduced in the program are:
Revision 5.1 Introduction to the C Programming Language 201
Function Reference: reg keyboard events Allow keyboard events to be de tected
reg keyboard events;
The void reg keyboard events function allows keyboard events to be detected. reg keyboard events is defined in graphics lib.h.
Function Reference: event key down Detect whether any keyboard key has been pressed
event key down;
The int event key down returns 1 if any key on the keyboard has been pressed, otherwise it returns
zero.
event key down is defined in graphics lib.h.
The following functions are more specific and test whether a particular key on the keyboard has been pressed.
Function Reference: event key up arrow Detect whether the up arrow key has been pressed
event key up arrow;
The int event key up arrow returns 1 if the up arrow key has been pressed, otherwise it returns
zero.
event key up arrow is defined in graphics lib.h.
Function Reference: event key down arrow Detect whether the down arrow key has been pressed
event key down arrow;
The int event key down arrow returns 1 if the down arrow key has been pressed, otherwise it
returns zero.
event key down arrow is defined in graphics lib.h.
202 Introduction to the C Programming Language Revision 5.1
Function Reference: event key left arrow Detect whether the left arrow key has been pressed
event key left arrow;
The int event key left arrow returns 1 if the left arrow key has been pressed, otherwise it returns
zero.
event key left arrow is defined in graphics lib.h.
Function Reference: event key right arrow Detect whether the right arrow key has been pressed
event key right arrow;
The int event key right arrow returns 1 if the right arrow key has been pressed, otherwise it
returns zero.
event key right arrow is defined in graphics lib.h.
Function Reference: event key Detect whether a character key has been pressed
event keychar letter;
The int event key returns 1 if the letter supplied as an argument case insenstive has been pressed,
otherwise it returns zero. For example
eventkeyG;
detects whether either the g or G keys have been pressed. In the porgram above, this is used to change the colour of one of the bouncing balls.
event key is defined in graphics lib.h.
F.4 Running and altering the bouncing balls program events.c
Build and execute the program events.c. Notice how the upper horizontal boundary is invisible and prevents the balls from overwriting the text which explains how to stop the program. Try pressing the right mouse button. It pauses the movement of the balls and as soon as it is released the balls start moving again. The smoothness of the ball motion i.e. the number of times a ball is drawn is determined by the TICK constant. While the apparent speed at which the balls move is determined by a combination of TICK and the pause time see pausefor.
Revision 5.1 Introduction to the C Programming Language 203 F.5 Summary
After reading through this appendix and running the events program, you should have a good idea how to simulate the movement of multiple graphical entities in your programs. You will also have learned how to detect keyboard events using the allegro graphics library. This should allow you to build interesting games and graphical interfaces.
204 Introduction to the C Programming Language Revision 5.1
Appendix G
Suggested Further Reading
G.1 Tutorial Material
1. Perry G. Absolute Beginners Guide to C. SAMS Publishing. 1994. This book gets great reviews on Amazon and looks excellent for beginners.
2. Davies P. The Indispensable Guide to C With Engineering Applications. AddisonWesley. 1995.
3. Kelley A. L. and Pohl, I. A Book on C. AddisonWesley. 1997.
4. Tyrrell, A. M. and Smith, S. L. and Dell, J. A. Essence of C for Electronic Engineers. Prentice Hall. 1998.
5. Deitel, H. and Deitel, P. C: International Version: How to Program. Prentice Hall International. 2009
G.2 Reference Material
1. Kernighan, B. W. and Ritchie, D. M. The C Programming Language. PrenticeHall. 1988. This is still the definitive guide to C written by the creators of the C language.
2. Prinz P. and PrinzKirch U. Pocket Reference. OReilly 2002.