Uploaded by selimon.s

48622 C Primer

advertisement
48622 Mechatronics 1
C programming primer
Adapted from a range of materials found at:
http://www.le.ac.uk/users/rjm1/cotter (© University of Leicester, 2012)
http://www.cs.cf.ac.uk/Dave/C/ (© A. D. Marshall 1994-2005)
http://upload.wikimedia.org/wikipedia/commons/0/07/C_Programming.pdf (Public
Domain License, Wikibooks, 2012)
TABLE OF CONTENTS
1. INTRODUCTION........................................................................................................................... 3
2. WORKFLOW ................................................................................................................................ 3
3. CONCEPTS .................................................................................................................................. 3
3.1. Chapter 1: Program structure, Variable types and I/O on screen ............................................. 3
3.1.1 History of C ....................................................................................................................... 3
3.1.2 The Edit-Compile-Link-Execute Process ............................................................................ 4
3.1.3 Structure of a C program ................................................................................................... 4
3.1.4 Pre-processor directives .................................................................................................... 5
3.1.5 Your first C program .......................................................................................................... 6
3.1.6 Variables and data types ................................................................................................... 6
3.1.7 Basic operators in C .......................................................................................................... 7
3.1.8 Basic input/output operations............................................................................................. 8
3.2. Chapter 2:............................................................................................................................. 11
3.2.1 Conditional statements .................................................................................................... 11
3.2.2 Looping statements ......................................................................................................... 12
3.2.3 Arrays and Strings ........................................................................................................... 14
3.3. Chapter 3:............................................................................................................................. 15
3.3.1 Functions ........................................................................................................................ 15
3.4. Chapter 4:............................................................................................................................. 19
3.4.1 Pointers........................................................................................................................... 19
3.5. Chapter 5:............................................................................................................................. 24
3.5.1 Structures........................................................................................................................ 24
4. EXERCISES ............................................................................................................................... 27
4.1. Chapter 1:............................................................................................................................. 27
4.2. Chapter 2:............................................................................................................................. 28
4.3. Chapter 3:............................................................................................................................. 30
4.4. Chapter 4:............................................................................................................................. 30
4.5. Chapter 5:............................................................................................................................. 31
1. INTRODUCTION
During the final Chapters of 48622 Mechatronics 1 we will be working on programming
microprocessors. This type of programming – i.e., creating code which can run on a standalone
microprocessor – is generally referred to as embedded programming. Embedded system is a generic
term for some combination of hardware and software designed to carry out a specific pre-defined task
as part of a larger system. Examples of embedded systems could be the controller of a robot, an
electronic telephone's core, the microprocessor inside a TV remote control, and many many more.
There are two favourite languages to write programs for embedded systems: Assembly and C/C++.
They are preferred because they allow the programmer to have complete control of microprocessor
operation (in the case of assembly, at single microprocessor operation level, while in the case of C at
a slightly higher level of abstraction).
Many of the students enrolled in MX1 have a poor knowledge of the C programming language, and
even before we can start thinking of programming microprocessor, this deficiency must be addressed.
Such is the purpose of this primer document: to cover some essential features of the language
throughout a few Chapters of self-guided learning.
What you will find in this document is not embedded C. You will learn the basics of the C language
and we will build on those basics to develop microprocessor-specific knowledge later in the course.
Working with your PC rather than a small chip with only a few inputs and outputs (on-screen words are
easier to interpret than jumpy voltages on metal pins) will allow you to "see" the code in action and
hopefully learn the basics quickly.
For information on how to run a C compiler on your system and run a program after you have written it,
refer to the software info guide on UTSonline. As this course component is based on self-learning, I
also recommend that students use the forums to share ideas and help each other (solutions to exercises
should not be exchanged in the interest of individual learning, but more skilled students can and should
share their knowledge of C with those who are beginners in this subject).
2. WORKFLOW
The primer is divided into 2 sections: concepts and exercises. Each section has 5 subsections and it is
recommended that you go through one subsection each Chapter (read the concepts and carry out the
exercises). No exercises are mandatory but they are all recommended so that you can get a minimum
amount of programming experience under your belt.
3. CONCEPTS
3.1. Chapter 1: Program structure, Variable types and I/O on screen
3.1.1 History of C
C is a general-purpose language which has been closely associated with the UNIX operating system
for which it was developed - since the system and most of the programs that run it are written in C.
Many of the important ideas of C stem from the language BCPL, developed by Martin Richards. The
influence of BCPL on C proceeded indirectly through the language B, which was written by Ken
Thompson in 1970 at Bell Labs, for the first UNIX system on a DEC PDP-7. BCPL and B are "typeless"
languages whereas C provides a variety of data types.
In 1972 Dennis Ritchie at Bell Labs writes C and in 1978 the publication of The C Programming
Language by Kernighan & Ritchie caused a revolution in the computing world.
In 1983, the American National Standards Institute (ANSI) established a committee to provide a modern,
comprehensive definition of C. The resulting definition, the ANSI standard, or "ANSI C", was completed
late 1988. A much more detailed (and longer) document on the history of C, for those interested, can
be found here.
3.1.2 The Edit-Compile-Link-Execute Process
Developing a program in a compiled language such as C requires at least four steps:
1.
2.
3.
4.
editing (or writing) the program
compiling it
linking it
executing it
Editing
You write a computer program using words and symbols that are understandable to human beings.
This is the editing part of the development cycle. You type the program directly into a window on the
screen and save the resulting text as a separate file. This is often referred to as the source file. The
custom is that the text of a C program is stored in a file with the extension .c .
Compiling
You cannot directly execute the source file. To run on any computer system, the source file must be
translated into binary code understandable to the computer's Central Processing Unit (for example, an
Intel microprocessor). This process produces an intermediate object file (with the extension .obj in
Microsoft systems).
Linking
The first question that comes to most people's minds is: Why is linking necessary? The main reason is
that many compiled languages come with library routines which can be added to your program. These
routines are written by the manufacturer of the compiler to perform a variety of tasks, from input/output
to complicated mathematical functions. An example of a standard C library is stdio.h, which contains a
number of fundamental input/output functions. After linking, the program is transformed into an
executable file (extension .exe in Microsoft DOS/Windows systems).
Executable files
Executable files can be run by the operating system as any other application, simply by typing their
names at the command prompt or using the Windows menu.
3.1.3 Structure of a C program
All C programs will consist of at least one function, but it is usual (when your experience grows) to write
a C program that comprises several functions. The only function that has to be present is the function
called main. For more advanced programs the main function will act as a controlling function calling
other functions in their turn to do the dirty work! The main function is the first function that is called when
your program executes.
C makes use of only 32 keywords which combine with the formal syntax to the form the C programming
language. Note that all keywords are written in lower case - C, like UNIX, uses upper and lowercase
text to mean different things. If you are not sure what to use then always use lowercase text in writing
your C programs. A keyword may not be used for any other purposes. For example, you cannot have
a variable called main.
The layout of C Programs
The general form of a C program is as follows:
pre-processor directives
global declarations
f1() {
local variables to function 1 ;
statements associated with function 1 ;
}
f2() {
local variables to function f2 ;
statements associated with function 2 ;
}
int main() {
local variables to function main ;
statements associated with function main ;
}
etc...
Note the use of the bracket sets () and {}. () are used in conjunction with function names whereas {} are
used as to delimit the C statements that are associated with that function. Also note the semicolon (;),
which is used to terminate C statements. C is a free format language and long statements can be
continued, without truncation, onto the next line. The semicolon informs the C compiler that the end of
the statement has been reached. Free format also means that you can add as many spaces or
tabulations as you like to improve the look of your programs.
A very common mistake made by everyone, who is new to the C programming language, is to miss off
the semicolon. The C compiler will concatenate the various lines of the program together and then tries
to understand them - which it will not be able to do. The error message produced by the compiler will
relate to a line of you program which could be some distance from the initial mistake.
3.1.4 Pre-processor directives
C is a small language with a small set of keywords. Most operations are carried out by calling upon
functions, and many useful functions are already available in libraries. It is wise for programmers to
check whether a library function is available to perform a task before writing their own version. This will
reduce program development time. The library functions have been tested, so they are more likely to
be correct than any function which the programmer might write. This will save time when debugging
the program.
Libraries often come in the form of header files (extension .h) and are referred to the pre-processor with
a directive which is common in most C programs:
#include <library_name.h>
Note the use of the # symbol as the first character of a directive line and the angle brackets around the
header name. The angle brackets indicate that the header file is to be looked for on the system path
which stores the rest of the C programming environment. Some text books will show the above
statement as follows:
#include "library_name.h"
The double quotes indicate that the current working directory should be searched for the required
header file. This will be true when you write your own header files but the standard header files should
always have the angle brackets around them.
Note: as a notable exception, include directives do not require a semicolon as a line terminator.
3.1.5 Your first C program
Below is an example of simple code which implements the ubiquitous "Hello World!" program. All the
program does is print the message "Hello World!" on the screen. Note also the use of the construct
/* comment text */ for comments (use comments in your programs!).
#include <stdio.h>
int main() {
printf("Hello World\n"); /*prints a greeting to the screen*/
}
The first line is the standard start for all C programs - main(). After this comes the program's only
instruction enclosed in curly brackets { }. The curly brackets mark the start and end of the list of
instructions that make up the program - in this case just one instruction. Note that the curly brackets
are on separate lines: this is not required but it is a convention to assist with visualising matching
brackets.
The printf function prints its argument on the screen (\n is a special character meaning "new line").
Try to write and run this program to ensure you have figured out how to compile and run your code in
the programming environment of your choice.
3.1.6 Variables and data types
This section deals with local variables. These are variables that are used within the current program
unit (or function). In a later section we will looking at global variables - variables that are available to all
the program's functions.
There are five basic data types associated with variables:
•
•
•
•
•
int - integer: a whole number.
float - floating point value: ie a number with a fractional part.
double - a double-precision floating point value.
char - a single character.
void - valueless special purpose type which we will examine closely in later sections.
In C it is compulsory, upon creation of a variable, to declare what data type it represents. Note:
variable names in C must begin with a letter or a "_" (underscore) character.
Integer Number Variables
The first type of variable we need to know about is of class type int - short for integer. An int variable
can store a value in the range -32768 to +32767. You can think of it as a largish positive or negative
whole number: no fractional part is allowed. To declare an int you use the instruction:
int variable name;
For example:
int a; declares that you want to create an int variable called a.
Decimal Number Variables
As described above, an integer variable has no fractional part. Integer variables tend to be used for
counting, whereas real numbers are used in arithmetic. C uses one of two keywords to declare a
variable that is to be associated with a decimal number: float and double. They are each offer a
different level of precision as outlined below.
float
A float, or floating point, number has about seven digits of precision and a range of about 1.E-36 to
1.E+36. A float takes four bytes to store.
double
A double, or double precision, number has about 13 digits of precision and a range of about 1.E-303
to 1.E+303. A double takes eight bytes to store. For example:
float total;
double sum;
Character Variables
Unlike other programming languages where the concept of "string" exists, C can only deal with numbers
and characters. A character is simply the numeric value corresponding to a particular character. A string
will be given by an array of characters.
To declare a variable of type character, use the keyword char. - A single character stored in one byte.
For example:
char c;
To assign, or store, a character value in a char data type is easy - a character variable is just a symbol
enclosed by single quotes. For example, if c is a char variable you can store the letter A in it using the
following C statement:
c='A';
Again, notice that you can only store a single character in a char variable.
Assignment Statement
Once you've declared a variable you can use it. Always remember that attempts to use a variable that
has not been defined will cause a compiler error. You can store a value in a variable using: name =
value;
For example:
a=10;
The four basic arithmetic operations do not require additional libraries, e.g.:
a=a+b;
a=a-b;
a=a*b;
a=a/b;
You should be careful with operations. The precision of the result stored in a variable will depend on
the data type of the variable. For example int a=10/3; will store the value 3 (as opposed to 3.333..)
in variable a. (The integer type does not support decimals therefore the result is truncated). The
example above also shows that simultaneous declaration and assignment is allowed in C.
3.1.7 Basic operators in C
Arithmetic operators
As well as the standard arithmetic operators (+ - * /) found in most languages, C provides some
more operators. A notable feature is the increment and decrement operators: ++ and --. For example:
x++;
is equivalent to x=x+1;
z--;
is equivalent to z=z-1; (actually, from a computing perspective it is more efficient)
C also has a convenient shorthand syntax for writing operations like i=i+3 or x=x*(y + 2) i.e.,
variable operator = expression;
e.g., i+=3; or x*=(y+2);
Comparison Operators
The equality operator is ==. For inequality C uses !=. Other operators < (less than) , > (greater than),
<= (less than or equals), >= (greater than or equals) are as usual.
A warning: Beware of using ``='' instead of ``=='', such as writing accidentally if(i = j) ... This is a
perfectly LEGAL C statement (syntactically speaking) which copies the value in "j" into "i", and delivers
this value, which will then be interpreted as TRUE if j is non-zero. This is unlikely to be the intended
program behaviour. Hence the warning.
Logical Operators
Logical operators are usually used with conditional statements (more on these later).
The two basic logical operators are:
&& for logical AND,
|| for logical OR.
Beware: & and | have a different meaning. They refer to for bitwise AND and OR.
Order of operations
When multiple operators are used in the same expression confusion about precedence may arise. C
follows standard precedence for arithmetic. There are precedence rules for other operators but the best
advice (also to improve readability of your code) is to use brackets where appropriate to make the order
of operations explicit.
3.1.8 Basic input/output operations
A very quick overview
The variable assignments you have seen so far are fixed, that is, a=100; stores 100 in the variable a
each time you run the program, no matter what you do. Without some sort of input command every
program would produce exactly the same result every time it was run. In practice, of course, we need
programs to do different jobs each time they are run. There are a number of different C input commands,
the most basic of which is the scanf command. To read a single integer value into the variable called
a you would use:
scanf("%d",&a);
For the moment don't worry about what the %d or the &a means - concentrate on the difference between
this and a=100;. When the program reaches the scanf statement, it pauses to give the user time to
type something on the keyboard and continues only when <Enter> is pressed to signal that the value
has been entered. Then the program continues with the new value stored in a. In this way, each time
the program is run the user gets a chance to type in a different value to the variable and the program
also gets the chance to produce a different result!
A basic and useful function for output is printf, the one we have already used to print "Hello World".
This can print the current value of a variable. To display the value stored in a you would use:
printf("The value stored in a is %d",a);
The %d, both in the case of scanf and printf, informs the compiler that the value being read in, or printed
out, is a decimal integer - that is, a few digits but no decimal point.
Note: the scanf function does not prompt for an input. You should get in the habit of always using a
printf function, informing the user of the program what they should type, before a scanf function.
More details on printf
The printf function is usually of the form:
printf(string,variable,variable,variable...)
where the ... means you can carry on writing an arbitrarily long list of variables separated by commas.
The string is all-important because it specifies the type of each variable in the list and how you want it
printed. The string is usually called the control string or the format string. The way that this works is that
printf scans the string from left to right and prints on the screen, or any suitable output device, any
characters it encounters - except when it reaches a % character. The % character is a signal that what
follows it is a specification for how the next variable in the list of variables should be printed. printf uses
this information to convert and format the value that was passed to the function by the variable and
then moves on to process the rest of the control string and anymore variables it might specify. For
example: printf("Hello World"); only has a control string and, as this contains no % characters,
it results in Hello World being displayed without any variable values. The specifier %d means convert
the next value to a signed decimal integer and so: printf("Total =%d",total); will print Total
= and then the value of total as a decimal integer.
The %d isn't just a format specifier, it is a conversion specifier. It indicates the data type of the variable
to be printed and how that data type should be converted to the characters that appear on the screen.
That is %d says that the next value to be printed is a signed integer value (i.e. a value that would be
stored in a standard int variable) and this should be converted into a sequence of characters (i.e. digits)
representing the value in decimal. If by some accident the variable that you are
trying to display happens to be a float or a double then you will still see a value displayed - but it will
not correspond to the actual value of the float or double. The reason for this is twofold:
1. The first difference is that an int uses two bytes to store its value, while a float uses four and
a double uses eight. If you try to display a float or a double using %d then only the first two
bytes of the value are actually used.
2. The second problem is that even if there wasn't a size difference ints, floats and doubles use
a different binary representation and %d expects the bit pattern to be a simple signed binary
integer.
This is all a bit technical, but that's in the nature of C. You can ignore these details as long as you
remember two important facts:
1. The specifier following % indicates the type of variable to be displayed as well as the format in
which that the value should be displayed;
2. If you use a specifier with the wrong type of variable then you will see some strange things on
the screen and the error often propagates to other items in the printf list.
If this seems complicated then I would agree but I should also point out that the benefit is being able to
treat what is stored in a variable in a more flexible way than other languages allow. Other languages
never let on to the programmer that what is in fact stored in a variable is a bit pattern. Of course whether
you view this as an advantage depends on what you are trying to do. It certainly brings you closer to
the way the machine works.
More details on scanf scanf is similar to printf in terms of syntax. The only remark is that the name
of the variable must be preceded by the symbol &. This has to do with the advanced concept of pointers
(later). For now please accept this and remember to include it. An example of input syntax for 3
variables:
scanf("%c %d %f",&ch,&i,&x);
scanf can be tricky when used to input sequences of characters (strings) as it may not recognise
blank characters, such as spaces or newline ("enter"). You will find that this can cause malfunctions in
your programs at times. More on this when we will work with strings later.
The % Format Specifiers
The % specifiers that you can use in ANSI C are:
•
•
•
•
•
•
•
•
•
•
%c char single character
%d (%i) int signed integer
%e (%E) float or double exponential format
%f float or double signed decimal
%g (%G) float or double use %f or %e as required
%o int unsigned octal value
%p pointer address stored in pointer
%s array of char sequence of characters
%u int unsigned decimal
%x (%X) int unsigned hex value
3.2. Chapter 2: Conditions, Loops and Array
3.2.1 Conditional statements
Conditional statements can control the flow of logic in a program. Apart from slight syntactic variation
they are similar to other languages. As we have seen following logical operations exist in C:
==,
!=,
||,
&&
The NOT operator also exists !. These operators are used in conjunction with the following statements.
The if statement
The if statement has the same function as other languages. It has three basic forms:
If (expression)
statement
...or:
if (expression)
statement1
else
statement2
...or:
if (expression)
statement1
else if (expression)
statement2
else
statement3
The switch statement
The C switch caters for choice where more than two outcomes are contemplated. It can be much
neater than writing multiple if statements:
switch (expression) {
case item1:
statement1;
break;
case item2:
statement2;
break;
}
case itemn:
statementn;
break;
default:
statement;
break;
In each case the value of itemi must be a constant, variables are not allowed. The break is needed if
you want to terminate the switch after execution of one choice. Otherwise the next case would be
evaluated. Note: This is unlike most other languages.
We can also have null statements by just including a semicolon ; or let the switch statement fall through
by omitting any statements (see e.g. below). The default case is optional and catches any cases not
explicitly stated. For example:
switch (letter){
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
numberofvowels++;
break;
case ' ':
numberofspaces++;
break;
default:
numberofconstants++;
break;
}
In the above example if the value of letter is `A', `E', `I', `O' or `U' then numberofvowels is incremented.
If the value of letter is ` ' then numberofspaces is incremented. If none of these is true then the default
condition is executed, that is numberofconstants is incremented.
3.2.2 Looping statements
The for statement
The C for statement has the following form:
for
(expression1; 2; expression3)
statement;
or, alternatively, {block of statements}
expression1 initialises; expression2 is the terminate test; expression3 is the modifier (which may be more
than just simple increment); For example:
int main()
{
int x;
for (x=3;x>0;x--){
printf("x=%d\n",x);
}
}
gives the on-screen outputs
x=3 x=2
x=1
Below are other examples of valid statements in C. The practical application of such statements is not
important here, we are just trying to illustrate peculiar features of C for that may be useful:
for (x=0;((x>3) && (x<9)); x++)
for (x=0,y=4;((x>3) && (y<9)); x++,y+=2)
for (x=0,y=4,z=4000;z; z/=10)
The second example shows that multiple expressions can be separated a comma , . In the third
example the loop will continue to iterate until z becomes 0;
The while statement
The while has the form:
while (expression)
statement
For example:
int main()
{
int x=3;
while (x>0) {
printf("x=%d\n",x);
x--;
}
}
gives the on-screen outputs
x=3 x=2
x=1
Because the while loop can accept expressions, not just conditions, the following are all legal:
while (x--);
while (x=x+1);
while (x+=5);
Using this type of expression, only when the result of x--, x=x+1, or x+=5, evaluates to 0 will
the while condition fail and the loop be exited.
The break and continue statements
C provides two commands to further control loop operation:
• break -- exit from loop or switch.
• continue -- skip 1 iteration of loop.
Consider the following example where we read in integer values and process them according to the
following conditions. If the value we have read is negative, we wish to print an error message and
abandon the loop. If the value read is greater than 100, we wish to ignore it and continue to the next
value in the data. If the value is zero, we wish to terminate the loop.
while (scanf( ``%d'', &value ) == 1 && value != 0) {
if (value < 0) {
printf(``Illegal value \n'');
break;
/* Abandon the loop */
}
if (value > 100) {
printf(``Invalid value \n'');
continue;
/* Skip to start loop again */
}
/* Process in some way the the value read,
which is guaranteed to be between 1 and 100 */
....;
....;
} /* end when value no longer != 0 */
3.2.3 Arrays and Strings
In principle arrays in C are similar to those found in other languages. As we shall shortly see arrays
are defined slightly differently and there are many subtle differences due the close link between array
and pointers (more later).
Single and Multi-dimensional Arrays
Let us first look at how arrays in C are defined:
int listofnumbers[50];
BEWARE: In C, Array subscripts start at 0 and end at index [array length -1]. For example, in the
above case valid subscripts range from 0 to 49. This is a BIG difference between C and other
languages and does require a bit of practice to get your head around it.
Elements can be accessed in the following ways:Thirdnumber = listofnumbers[2];
listofnumbers[5] = 100;
Multi-dimensional arrays can also be defined, as follows (two-dimensional example):
int ableofnumbers[50][50];
For further dimensions simply add more [ ], e.g., int bigD[50][50][40][30];/*This is 4D*/
Elements can then be accessed in the following ways:
anumber = tableofnumbers[2][3];
tableofnumbers[25][16] = 100;
Strings
In C, strings are defined as arrays of characters. For example, the following defines a string of 50
characters:
char name[50];
C has no built-in string handling facilities and therefore the following are all illegal:
char firstname[50],lastname[50],fullname[100];
firstname = "Arnold"; /* Illegal */
lastname = "Schwarznegger"; /* Illegal */
fullname = "Mr" + firstname + lastname; /* Illegal */
There is a special library of string handling routines but we will not work with that in this document.
To carry out a simple printout of a string we use printf with a special %s control character:
printf("%s",name);
NOTE: We just need to give the name of the string (no need to specify the array index).
In order to allow variable length strings the \0 character is used to indicate the end of a string. So
we if we have a string, char name[50]; and we store “DAVE” in it, its contents will look like:
Tip for future exercises: you can find the end of a string by locating the \0 character (called null).
3.3. Chapter 3: Functions
3.3.1 Functions
In C programming, all executable code resides within a function. A function is a named block of code
that performs a task and then returns control to a caller. A function is often executed (called) several
times, from several different places, during a single execution of the program. After finishing a
subroutine, the program will branch back (return) to the point after the call.
Functions are a powerful programming tool. As a basic example, suppose you are writing code to
print out the first 5 squares of numbers, do some intermediate processing, then print the first 5
squares again. We could write it like this:
#include <stdio.h>
int main(void)
{
int i;
for(i=1; i <= 5; i++){
printf("%d ", i*i);
}
for(i=1; i <= 5; i++){
printf("%d ", i*i);
}
return 0;
}
We have to write the same loop twice. We may want to somehow put this code in a separate place and
simply jump to this code when we want to use it. This would look like:
#include <stdio.h>
void Print_Squares(void)
{
int i;
for (i=1; i <=5; i++){
printf("%d ", i*i);
}
}
int main(void)
{
Print_Squares();
Print_Squares();
return 0;
}
This is precisely what functions are for.
More on functions
A function is like a black box. It takes in input, does something with it, then spits out an answer. Note
that a function may not take any inputs at all, or it may not return anything at all. In the above
example, if we were to make a function of that loop, we may not need any inputs, and we aren't
returning anything at all (Text output doesn't count - when we speak of returning we mean to say
meaningful data that the program can use).
We have some terminology to refer to functions:
• A function, call it f, that uses another function g, is said to call g. For example, f calls g to print
the squares of ten numbers.
• A function's inputs are known as its arguments
•
A function g that gives some kind of answer back to f is said to return that answer. For example,
g returns the sum of its arguments.
Writing functions in C
It's always good to learn by example. Let's write a function that will return the square of a number.
int square(int x)
{
int square_of_x;
square_of_x = x * x;
}
return square_of_x;
To understand how to write such a function like this, it may help to look at what this function does as a
whole. It takes in an int, x, and squares it, storing it in the variable square_of_x. Now this value is
returned.
The first int at the beginning of the function declaration is the type of data that the function returns. In
this case when we square an integer we get an integer, and we are returning this integer, and so we
write int as the return type. Next is the name of the function. It is good practice to use meaningful
and descriptive names for functions you may write. It may help to name the function after what it is
written to do. In this case we name the function "square", because that's what it does - it squares a
number. Next is the function's first and only argument, an int, which will be referred to in the function
as x. This is the function's input.
In between the braces is the actual guts of the function. It declares an integer variable called
square_of_x that will be used to hold the value of the square of x. Note that the variable square_of_x
can only be used within this function, and not outside. We'll learn more about this sort of thing later,
and we will see that this property is very useful.
We then assign x multiplied by x, or x squared, to the variable square_of_x, which is what this
function is all about. Following this is a return statement. We want to return the value of the square
of x, so we must say that this function returns the contents of the variable square_of_x. Finally, the
brace is closed, and we have finished the declaration.
Written in a more concise manner, this code performs exactly the same function as the above:
int square(int x)
{
return x * x;
}
Technically, you have been writing functions already, in fact - main is a function that is always written.
Note: main is always of type int in this document. Discussion of this might take us astray. Please
accept it is standard C practice.
General function declaration
In general, if we want to declare a function, we write
type name (type1 arg1, type2 arg2, ...)
{
/* code */
}
We’ve previously said that it is possible for a function to take no arguments, or return nothing, or both.
When a function does not return anything the type void is used. void basically means "nothing" so if we want to write a function that returns nothing, for example, we write
void sayhello(int number_of_times)
{
int i;
for (i=1; i <= number_of_times; i++){
printf("Hello!\n");
}
}
Notice that there is no return statement in the function above. Since there's none, we write void as
the return type.
Below is an example of a function with no arguments:
float calculate_number(void)
{
float to_return=1;
int i;
for (i=0; i < 100; i++){
to_return += 1;
to_return = 1/to_return;
}
return to_return;
}
Notice this function doesn't take any inputs, but merely returns a number calculated by this function.
Naturally, it is possible to also have a function with both void return and void in arguments together.
Using C functions
We can now write functions, but how do we use them? When we write main, we place the function
outside the braces that encompass main. When we want to use that function, say, using our
calculate_number function above, we can write something like
float f;
f = calculate_number();
In general a function call is done as follows. If a function takes in arguments, we can write something
like
int square_of_10;
square_of_10 = square(10);
If a function doesn't return anything, no “assignment to a variable” is required and we can just write
say_hello();
since we don't need a variable to catch its return value.
Recursion
An advanced way of using functions. Not for the faint hearted and risky as it can exhaust memory
resources very quickly. On the other hand, it can create very neat and efficient code. Recursion
occurs when a function calls itself as part of its operation. An example: Write a C program to find
sum of first n natural numbers using recursion.
#include <stdio.h>
int sum(int n);
int main()
{
int num, add;
printf("Enter a positive integer:\n");
scanf("%d",&num);
add=sum(num);
printf("sum=%d",add);
}
int sum(int n){
if(n==0)
return n;
else
return n+sum(n-1);
}
/*self call
to function sum() */
The output will look as follows:
Enter a positive integer:
5
15
In this simple C program, the sum() function invokes itself. If n is not equal to 0 then, the function calls
itself passing argument 1 less than the previous argument it was called with. Suppose, n is 5 initially.
Then, during next function calls, 4 is passed to function and the value of argument decreases by 1 in
each recursive call. When, n becomes equal to 0, the value of n is returned which is the sum numbers
from 5 to 1. A way to visualise the recursion is shown below:
sum(5) =5+sum(4)
=5+4+sum(3)
=5+4+3+sum(2)
=5+4+3+2+sum(1)
=5+4+3+2+1+sum(0)
=5+4+3+2+1+0
=5+4+3+2+1
=5+4+3+3
=5+4+6
=5+10
=15
Every recursive function must be provided with a way to end the recursion. In this example when, n is
equal to 0, there is no recursive call and recursion ends.
Standard C functions and libraries
A number of standard libraries exist which contain many pre-prepared functions. We have seen the
stdio.h file in the Hello World example earlier. printf and scanf are functions declared and described
inside the stdio.h file. A file can contain multiple functions. There are many more header files in the
standard libraries, a list of the most common is below*.
<assert.h>
<ctype.h>
<errno.h>
<float.h>
<limits.h>
<locale.h>
<math.h>
<setjmp.h>
<signal.h>
<stdarg.h>
<stddef.h>
<stdio.h>
<stdlib.h>
<string.h>
<time.h>
<complex.h>
3.4. Chapter 4: Pointers
3.4.1 Pointers
Pointers are a very powerful, but primitive facility contained in the C language. Pointers have great
affinity with low-level assembly language programming and as a result they are sometimes difficult to
understand and subject to subtle and difficult-to-find errors. Still, pointers are one of the great attractions
of the C language and most C programmers would object to the idea that pointers are 'primitive'! Since
we will use C on microprocessors, pointers are an important topic for our purposes.
A variable is an area of memory that has been given a name. For example, int x; is an area of
memory that has been given the name x. The advantage of this scheme is that you can use the name
to specify where to store data. For example, x=10;is an instruction to store the data value 10 in the
area of memory named x. The variable is such a fundamental idea that using it quickly becomes second
nature, but there is another way of working with memory.
The computer accesses its own memory not by using variable names but by using a memory map with
each location of memory uniquely defined by a number, called the address of that memory location. A
pointer is a variable that stores a memory location. In more fundamental terms, a pointer stores the
memory address of a variable. A pointer “points” to a variable.
A pointer has to be declared just like any other variable - remember a pointer is just a variable that
stores an address. For example, int *p; is a pointer to an integer. Adding an asterisk in front of a
variable's name declares it to be a pointer to the declared type. Notice that the asterisk applies only to
the single variable name that it is in front of, so int *p, q;, for example, declares one pointer to an
int and one int variable, not two pointers.
Pointer operators
Once you have declared a pointer variable, you can begin using it like any other variable. First, however,
there are new operators you must understand: & and *.
The & operator returns the address of a variable. Thinking of the ampersand (&) symbol as the ‘A’
for ‘address’ might help you remember. For example:
int *p, q;
declares p, a pointer to int, and q an int. The instruction
p=&q;
stores the address of q in p. After this instruction you can think that p is pointing at q. Compare this
with p=q;, which attempts to store the value in q in the pointer p - something which has to be
considered an error since a pointer contains the address, not the value of a variable.
The * operator returns the value of the variable pointed at by the address saved in the pointer.
This operation is a little more difficult to understand. In other words, p stores the address, or pointer,
to another variable and *p is the value stored in the variable that p points at.
The * operator is called the de-referencing operator and you should not confuse it with
multiplication. [The multiple use of the asterisk symbol (i.e., for pointers and multiplication depending
on the context) is an example of operator overload in C].
Much confusion over pointers can be avoided by focussing on three basic ideas:
• To declare a pointer, add * in front of its name.
• To obtain the address of a variable, use & in front of its name.
• To obtain the value of a variable, use * in front of a pointer's name.
Here is a worked example:
int *a , b , c;
b = 10; a = &b;
c = *a;
Firstly, three variables are declared: a (a pointer to int), and b and c (both standard integers). The
instruction stores the value 10 in the variable b in the usual way. Then a=&b; stores the address of b
in a. After this, a points to b. Finally, c=*a; stores the value in the variable pointed to by a into c. As
a points to b, its value i.e. 10 is stored in c. In other words, this is a long winded way of writing c=b;
Notice that if a is an int and p is a pointer to an int then a=p; is nonsense because it tries to store the
address of an int, i.e. a pointer value, in an int. Similarly: a=&p; tries to store the address of a pointer
variable in a and is equally wrong!
The only assignment between an int and a pointer to int that makes sense is: a=*p;
Pointers and functions
At the moment it looks as if pointers are just a complicated way of doing something we can already do
by simpler methods. Pointers are, however, extremely powerful tools. A useful area of application is
their involvement in function calls. We did not specifically look at this when we discussed functions
but functions can have arguments passed to them either by value or by address.
Let’s have a look at the following code, which tries to implements a simple variable swap:
void swap(int x , int y)
{
int temp;
temp = x;
x = y;
y = temp;
}
int main()
{
int a, b;
a=10; b=5;
swap(a,b);
printf(“Values: a is %d and b is %d”,a,b);
}
This code suffers from a major problem: although a swap function is created and executed as part
of the main, the result of the printf statement will be: “Values: a is 10 and b is 5.”. It appears
that the variables have not been swapped after all. Why??
The function arguments in this example are passed by value. This means that the invoked function
creates copies (located in other available memory locations) of the variables passed (the ‘copies’ are
called x and y in this example). These new variables are local to the function (i.e., they are not seen
by the main) and any changes made do not affect the original a and b. Furthermore, the function
created is of return type void, which suggests that it does not return anything to the calling function
main. Of course one could rectify this by creating a non-void function (although using structures to
pass multiple outputs might be undesirably complex), or by using global variables†. Pointers offer a
much neater way to achieve the desired result. Look at the code below:
void swap(int *x , int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
int main()
{
int a, b;
a=10; b=5;
swap(&a,&b);
printf(“Values: a is %d and b is %d”,a,b);
}
This code passes the arguments by address. Note the use of & in the invoking statement. This means
that the invoked function receives the memory addresses of the variables. The use of pointers inside
the function ensures that any changes made are performed onto those very memory addresses used
by main. Therefore, in this case the values of a and b will be correctly swapped and the output will be:
“Values: a is 5 and b is 10.”. You can try to write and run this code yourself to get some handson
feel for how it works.
The rule is that whenever you want to pass a variable so that the function can modify its contents
you have to pass it as an address. Equally, the function has to be ready to accept an address and
work with it. You can't take any old function and suddenly decide to pass it the address
We haven’t discussed these, but global variables can be seen and modified by all functions in a program,
as opposed to local variables (the ‘standard’ type) which are only seen by the function they are declared in.
†
of a variable instead of its value. If you pass an address to a function that isn't expecting it, the result is
usually disaster and the same is true if you pass a value to a function that is expecting an address.
For example, in the second version of the code, calling swap as swap(a,b) instead of swap(&a,&b)
will result in two arbitrary areas of your computer’s memory being swapped over, usually with the result
that the entire system, not just your program, crashes.
The need to pass an address to a function also explains the difference between the two I/O functions
that we have been using since the beginning of this course. printf doesn't change the values of its
parameters so it is called as printf("%d",a), but scanf does, being an input function, and so it is
called as scanf("%d",&a).
Pointers and arrays (basic pointer arithmetic)
Another area where pointers become extremely useful is when handling arrays. In C there is a very
close connection between pointers and arrays. In fact they are more or less one and the same thing!
When you declare an array as:
int a[10];
you are in fact declaring a pointer a to the first element in the array. That is, a (with no index attached)
has the same meaning in the program as &a[0]. The only difference between the bare array name (a
in this case) and a pointer variable is that the array name is a constant pointer - you cannot change the
location it points at. Another pointer in disguise is the expression a[i]: this is converted by the compiler
into a pointer expression that gives the value of the appropriate element. To be more precise, writing
a[i] is exactly equivalent to *(a+i) i.e. the a[1] returns the value located at address a+i. In the same
way *(a+1) is equivalent to a[1] and so on.
The strange concept here is the idea of adding ‘one’ to the address stored in a pointer to get to
the next element of an array. What it means to add 'one' to a pointer? In most implementations, an
int takes two memory locations and a float takes four. So if you declare an int array and add one to a
pointer to it, then in fact the pointer will move on by two memory locations. However, if you declare a
float array and add one to a pointer to it then the pointer has to move on by four memory locations. In
other words, adding one to a pointer moves it on by an amount of storage depending on the type it is
a pointer to.
This is precisely why you have to declare the type that the pointer is to point at! Only by specifying, e.g.,
int a[10]; (a pointer to int array) and float b[10]; (b pointer to float array) can the compiler
figure out that a+1 means move the pointer on by two memory locations and
b + 1 means move the pointer on by four memory locations. In practice, you don't have to worry about
how much storage a pointer's base type takes up. All you do need to remember is that pointer
arithmetic works in units of the data type that the pointer points at. Notice that you can even use
increment and decrement operators ++ and -- with a pointer, but not with an array name because this
is a constant pointer and cannot be changed.
Summarising the key ideas:
1. An array's name is a constant pointer to the first element in the array that is a ≡ &a[0] and
*a ≡ a[0]. 1
2. Array indexing is equivalent to pointer arithmetic - that is a+i ≡ &a[i] and *(a+i) ≡ a[i].
Pointers, arrays and functions
One final point connected with both arrays and functions is that when you pass an entire array to a
function then by default you pass a pointer. This allows you to write functions that process entire
arrays without having to pass every single value stored in the array - just a pointer to the first element.
If you compare this with a hypothetical alternative option of passing an array by value, i.e., copying all
of the array elements in a local copy for use by a function, you should be able to see how passing
pointers between functions is a much less resource-intensive option. However, unless the
concepts are clear in your head, you could easily write code which causes your computer to crash
altogether.
Here is an example of a program featuring a function which assigns numbers 1 to n to an array of int of
size n.
void enum_fcn(int *pa, int n) //pa a handy name for “pointer to array”
{
int i;
for (i=0;i<n;i++){
*pa = i+1;
//assigning a value to the location pointed at
pa++;
//incrementing the pointer }
}
1
the symbol ≡ means ‘is identical to’
}
int main()
{
int a[5], i;
int arr_size=5;
enum_fcn(a,arr_size);
for (i=0;i<arr_size;i++)
printf (“%d\t”,a[i]);
}
The output will be:
1
2
3
4
5
Note how the array was passed to the function as a and not &a, that is because a is a bare array name
and automatically represents the address of a[0] as previously explained. Also, if your understanding
of these pointer concepts is good, you should also be able to see that I could have used this equivalent
header for my function: void enum_fcn(int pa[], int n).
Common pointer mistakes
Not assigning a memory address to a pointer before using it, as in
int *x;
*x = 100;
This may be hard to spot because it will not raise a compiler error. x may be initialised randomly so the
value 100 will be written in a random location of your memory (potentially overwriting useful memory
information and causing havoc in your computer). Always ensure a location is assigned, e.g.,
x = &y;
*x = 100;
Illegal indirection. Assigning a value to a pointer or an address to a variable, as in
int y, *p;
or
int *a, b; p = y
*a = &b;
This may also fail to irritate the compiler and cause undesired program behaviour.
3.5. Chapter 5: Structures
In Chapter 5 you should do a good review of all of the previous Chapters. There is not too much new
content, but the exercises will test your skills in all of the previous areas as well.
3.5.1 Structures
An array is an example of a data structure. It takes simple data types like int, char or double and
organises them into a linear array of elements. The array serves most but not all of the needs of the
typical C program. The restriction is that an array is composed of elements all of the same type. At first
this seems perfectly reasonable. After all why would you want an array to be composed of twenty chars
and two ints? Well this sort of mixture of data types working together is one of the most familiar of data
structures. Consider for a moment a record card which records name, age and salary. The name would
have to be stored as a string, i.e. an array of chars terminated with an ASCII null character, and the
age and salary could be ints.
At the moment the only way we could work with such a collection of data is as separate variables. This
isn't as convenient as a single data structure using a single name and so the C language provides
struct as a way to define such collections of different variable types and sizes. At first it is easier to
think of this as a record - although it's a little more versatile than this suggests.
Defining new structures
Declaring a struct is a two-stage process. The first stage defines a new data type that has the required
structure which can then be used to declare as many variables with the same structure as required.
This two-stage process is best explained by example. For example, suppose we need to store a name,
age and salary as a single structure. You would first define the new data structure; this is done outside
the main type using:
struct emp_record{
char name[25];
int age;
int pay;
};
And then, in the main code, the variable is declared: struct emp_record employee
Notice that the new variable is called employee and it is of type emp_record which has been defined
earlier. emp_record is the name of the general employee record structure and employee is one
instance of this general type. It might help to compare the situation with that of a general int type and a
particular variable such as int count - emprec is a type like int (albeit user defined) and employee is a
variable like count. The following code, for example, creates three employee records: struct
emp_record employee, oldemploy, newemploy;.
The next problem when working with a structure is how to access the individual elements. The syntax
is structure_variable.component. For example, I could assign:
employee.age = 32;
employee.name[2] = 'a';
and so on.
It should be clear by now that a structure has a different value to that of an array. A struct can be
used to cluster together a group of variables which form a coherent entity.
A useful example follows. C does not have facilities to handle complex numbers, but it is possible to
create an ad-hoc structure which comprises of two numbers representing the real and imaginary
parts.
struct comp{
float real;
float imag;
};
After this you can declare the new complex variables using something like: struct comp a,b;
The new complex variables cannot be used as if they were simple variables - because they are not.
Although it might depend on your compiler version, the C language does not in general allow you to do
whole-of-structure operations such as:
a=b;
However, the extended version will definitely work:
a.real=b.real;
a.imag=b.imag;
Similarly, the compiler will not be able to sort out what you mean by c = a + b, so you will have to write
out the rule for addition (e.g., in a function) as:
c.real=a.real+b.real;
c.imag=a.imag+b.imag;
Structures and functions
Of course a sensible alternative to writing out the addition each time is to define a function to do the
same job - but this raises the question of passing structures as parameters. Fortunately this isn't a big
problem. It is possible to pass entire structures as parameters and set a structure as return type for a
function. Here is an example for the complex number addition:
struct comp add(struct comp a , struct comp b){
struct comp c;
c.real=a.real+b.real;
c.imag=a.imag+ b.imag;
return c;
}
After the add function has been written you can call upon it to perform a complex addition as
x=add(y,z)
which isn't too far from the x=y+z that you would really like to use.
Finally notice that passing a struct by value might use up rather a lot of memory as a complete copy
of the structure is made for the function, especially if the structure is large. It is of course possible to
pass a pointer instead of a value.
Structures and pointers
You can define a pointer to a structure in the same way as any pointer to any type. For example:
struct emp_record *ptr // ptr = "pointer to record"
ptr = &employee;
defines a pointer to an emp_record and associates to the memory address of employee. You can use
a pointer to a struct in more or less the same way as any pointer. There are just some peculiarities
about addressing the components internal to the structure. For this there are two equivalent syntax
options. For example:
(*ptr).age
ptr->age
//equivalent ways to point to the 'age' component
The latter is most often used because it does not require the use of brackets and also the arrow symbol
is quite intuitive. Below is the complex addition function rewritten with pointers:
void comp add(struct comp *a , struct comp *b , struct comp *c)
{ c->real = a->real + b->real; c>imag = a->imag + b->imag;
}
In this case c is a pointer to a structure of type comp. The function in the main program would be called
as:
add(&x,&y,&z);
Notice that in this case the address of each of the structures is passed rather than a complete copy of
the structure - hence the saving in memory! Also notice that the function can now change the values
of x, y and z if it wants to. It's up to you to decide if this is a good thing or not!
Arrays of structures
It is also possible to have arrays of structures. For example, I can cater for all of my company's
employees by creating:
struct emp_record employees[100];
which is an array of 100 identical employee records. The statement
printf("%d",employees[6].age);
will print to screen the age of the employee saved in record 6.
4. EXERCISES
These are recommended exercises. They are not mandatory and you could work on other exercises if
you like. There is a wealth of information out there. The main point of this section is to help you get a
minimum of programming experience under your belt.
4.1. Chapter 1:
Write C programs to perform the following tasks.
Exercise 1.1
Input two numbers and work out the difference, average and sum of the squares of the numbers.
Exercise 1.2
Write a program to read a "float" representing a number of degrees Celsius, and print (also as a "float")
the equivalent temperature in degrees Fahrenheit. Print your results in a form such as 100.0 degrees
Celsius converts to 212.0 degrees Fahrenheit.
Exercise 1.3
Write a program which will ask you about your name, student number and favourite colour and print
those on separate lines. You may use either several printf instructions, each with a newline character
in it, or one printf with several newlines in the control string.
Note: Your name is an array of characters. We will look at arrays later on but I will give you an example
of a declaration of a char array of 10 letters just for the purpose of this exercise char a[10]§. Don't
forget to use the correct type specifier for a string of characters in your i/o functions.
Exercise 1.4
Write a program to read a number of units of length (a float) and print out the area of a circle of that
radius. Assume that the value of pi is 3.14159.
Your output should take the form: The area of a circle of radius ... units is .... units.
If you want to be clever, and have looked ahead in the notes, print the message "Error: Negative values
not permitted." if the input value is negative.
Exercise 1.5
Given as input an integer number of seconds, print as output the equivalent time in hours, minutes and
seconds. Recommended output format is something like
7322 seconds is equivalent to 2 hours 2 minutes 2 seconds
§ I did mention that scanf can do silly things when dealing with inputting spaces or characters/strings terminated
with "enter". This should not concern us too much at this time. If you are encountering problems, for now, consider
the below scanf formulations as hints for you go through your exercises (it's ok if you do not fully understand them).
scanf(" %c", &c);
\\ to input a single character e.g. char c. Note the space before %c
scanf("%[^\n]s", &c[0]);
\\ if you enter a string e.g. char c[10] terminated by "enter"
Exercise 1.6
Write a program to read two integers with the following significance.
The first integer value represents a time of day on a 24 hour clock, so that 1245 represents quarter to
one mid-day, for example.
The second integer represents a time duration in a similar way, so that 345 represents three hours and
45 minutes.
This duration is to be added to the first time, and the result printed out in the same notation, in this case
1630 which is the time 3 hours and 45 minutes after 12.45.
Typical output might be e.g.,
Start time is 1415. Duration is 50. End time is 1505.
Start time is 2300. Duration is 200. End time is 100.
You are not allowed to use if... else statements to solve this exercise. You can however, use
expressions containing comparison operator, e.g., the expression x_gr_zero=(x>0)*x; yields x for
x>0 and 0 otherwise.
4.2. Chapter 2:
Exercise 2.1
Write a program to read two characters, and print their decimal value when interpreted as a 2-digit
hexadecimal number. Accept upper case letters for values from 10 to 15. Return an error for invalid
entries.
Exercise 2.2
Read an integer value. Assume it is the number of a month of the year; print out the name of that month.
If the number is invalid, print an error message. Write a program that repeats this for 3 month entries.
Exercise 2.3
Write a program to read in 10 numbers and compute the average, maximum and minimum values.
Finally, sort them in order to get an output something like (only 5 numbers shown): (hint for printing to
screen: just as \n means a new line, \t introduces a tabulation)
You entered
10
15
2
1
43
The sorted list is
1
2
10
15
43
Exercise 2.4
Write a program to read in numbers until the number -999 is encountered. The sum of all number read
until this point should be printed out. TIP: you don’t need to use arrays for this exercise.
Exercise 2.5
Read in three values representing respectively: 1) a capital sum (integer number of dollars), 2) a rate
of interest in percent (float), and 3) a number of years (integer).
Compute the values of the capital sum with compound interest added over the given period of years.
Each year's interest is calculated as
interest = capital * interest_rate / 100;
and is added to the capital sum by capital
+= interest;
Print out money values in dollars accurate to two decimal places. (hint: try and use output format %.nf
to get n decimal places)
Print out a floating value for the value with compound interest for each year up to the end of the period.
Print output year by year in a form such as:
Original sum 30000.00 at
12.5 percent for 10 years
Year Interest Sum
----+-------+-------1 3750.00 33750.00
2 4218.75 37968.75
3 4746.09 42714.84
4 5339.35 48054.19
5 6006.77 54060.96
6 6757.62 60818.58
7 7602.32 68420.90
8 8552.61 76973.51
9 9621.68 86595.19
10 10824.39 97419.58
Exercise 2.6
Read a positive integer value, and compute the following sequence: If the number is even, halve it; if
it's odd, multiply by 3 and add 1. Repeat this process until the value is 1, printing out each value.
Finally print out how many of these operations you performed.
Typical output might be:
Initial value is 10
Next value is
5
Next value is 16
Next value is
8
Next value is
4
Next value is
2
Final value 1, number of steps 5
If the input value is less than 1, print a message containing the word Error
Exercise 2.7
Write a function that asks for an input n and outputs a right-side-up triangle of height n and width 2n1;
the output for n = 6 would be:
*
***
*****
*******
*********
***********
Exercise 2.8
Write a program which asks you to input your student number (XXXXXXX) and then presents you with
a menu for the following operations (by inputting a number the corresponding activity is executed):
1. Write the number back to you in reverse order
2. Asks you to state a digit number n, then prints the nth character of the student number
3. Asks you for a particular character and tells you if it is found in the student number
4. Quit
After each operation (except ‘quit’), the program goes back to the main menu.
4.3. Chapter 3:
Exercise 3.1
Write a function to check if an integer is negative; the declaration should look like int
is_positive(int i); The program will keep asking for inputs and will keep delivering outputs
(informing the user of whether the number is negative or not) until the number entered is 999 (such
input will force quit).
Exercise 3.2
Write a function with two arguments to raise a floating point number to an integer power, so for example:
float a = raise_to_power(2, 3); //a gets 8 float
b = raise_to_power(9, 2); //b gets 81
float raise_to_power(float f, int power); //make this your declaration
The program will keep asking for inputs and will keep delivering outputs (informing the user of the
computed result) until the numbers entered are 999, 999 (such input will force quit).
Note: you are not allowed to use the function pow here (elevating to power) but should rather use
iterative multiplication to compute the result.
Exercise 3.3
Write a function which returns 1 if a positive integer is prime and 0 otherwise. A prime number can only
be divided (without remainder) by itself and by 1. (hint, the modulo operator % might be helpful for your
function)
Exercise 3.4
Write a function to determine the number and identity of all prime numbers below an inputted positive
number n. To check operation, try at least two separate runs for values of n in excess of 41. Hint: have
you solved the exercise above?
Exercise 3.5
Write a program to calculate the factorial of an integer number using recursion (hint: very similar to the
example in the concepts section). Remember that 3!=3*2*1=6 and 0!=1. Create suitably explanatory
inputs and outputs.
Exercise 3.6
Write a function called half() that takes an integer argument. The function must print the number it
received to the screen, then the program should divide that number by two to make a new number. If
the new number is greater than zero the function then calls the function half() (itself!) passing it the new
number as its argument. If the number is zero or less than zero the function exits.
So, for example, calling the function half() with an argument of 100, the screen output should be
100
50
25
...
...
1
4.4. Chapter 4:
Exercise 4.1
Write a C program that asks the user for an input and stores it in a variable. Then, the program prints
out something like.
The value entered is <value> and is stored at memory location <location
value>.
Tip: use the %p type identifier to visualise the memory address (pointer value) in hexadecimal format.
Exercise 4.2
Write a program that takes three variable (a, b, c) in as separate parameters and calls on a function
which rotates the values stored so that value a goes to b, b to c and c to a. Output the values of your
variables before and after the swap in an understandable manner.
Exercise 4.3
Write a program that creates an array of type float. How you populate this array is up to you. Print out
the content of the array and the corresponding memory addresses for each entry. (you may want to try
with both equivalent ways of referencing an array to make sure your syntax is up to speed). Take note
of the numeric difference between successive address entries. What does that suggest regarding the
way the array is stored to memory? What is the size of a float entry?
Exercise 4.4
Write a C program to read through an array of type int using pointers. How you populate this array is
up to you. Write the array to screen so that it fits in one screenshot. Then ask the user to input a value.
Your C program is to scan through the array to find the value and output how many occurrences were
found. You must use pointers.
Exercise 4.5
Write a program to find the number of times that a given word (i.e. a short string) occurs in a sentence
(i.e. a long string!). Read data from standard scanf input (you will store two arrays of char to memory).
You will first acquire a single word, and then a longer string of general text. Your program should pass
the two strings to a function which will count the number of occurrences. Extension: Let the function
also turn any blank spaces into dashes.
Typical output should be something like:
The word is "the".
The sentence is "the cat sat on the mat".
The word occurs 2 times.
If I remove the spaces: "the-cat-sat-on-the-mat"
Important Tip: when you type a space scanf will think that your string is finished. The syntax:
scanf("%[^\n]s", c);, where c will be your string array, will ignore the spaces and capture the
string as a whole once the enter key is pressed (it sets \n as the string delimiter). By the way, note that
the variable is passed as c and not &c, you should be able to tell why.
4.5. Chapter 5:
Exercise 5.1
Implement, using structures and functions as appropriate, the sum and product of two fractions.
Simplification is not required. To get full marks, you should pass your structures to your functions as
pointers.
Exercise 5.2
Implement, using structures and functions as appropriate, a program which requires you to enter a
number of points in 3 dimensions. The points will have a name (one alphanumeric character) and
three coordinates x, y, and z. Find and implement a suitable way to stop the input loop. The program,
through an appropriate distance function, should identify the two points which are the furthest apart.
Another function should calculate the centre of gravity of the point cloud (i.e., the average of each
coordinate for all points entered)
The output should show a list of the points entered, then name and list the two that are furthest apart,
and finally list the centre of gravity.
Exercise 5.3
Create a C program which describes a store management software. The records will be saved in a
structure called goods. You can have up to 10 goods in your store (array of struct). Each good will
have a name, a record id (sequential numbering), a price, and a flag as to whether it is in stock or not.
Use appropriate variable types for each.
Your program will present a menu, allowing the user to choose:
1. Open record (by number)
2. List all records
3. Quit
Quit is self-explanatory. List all records will print out a list of record IDs and product names.
If Open record is selected, then the program should show
Record <number> opened
<a list of the details of the item should appear here>
And give the following options:
1. Change item name
2. Change item price
3. Change stock availability
4. Go back
After a suboption has been chosen, the user should have the opportunity to enter the new name/price
or toggle availability. Then the program should show the updated details of the record and show the
second menu for a new choice.
Create a suitable main program structure which calls on functions which will carry out the operations
as described, asking for appropriate inputs and returning appropriate outputs.
Note: you should use pointers when passing structs to functions.
Download