CPS125 - Course Guide
CPS125 - Course Guide
A Comprehensive Overview
e-jja
Ryerson University
Preface
Greetings, this is going to be a written guide from the perspective of a student. From this document you
will be able to learn the basics of the course. This was primarily done to improve my writing while trying
to create something useful. I may never use these notes again, but they are really pretty. Please follow
along with these notes, and mark any corrections as I am only human. I’ve had multiple people willing to
pay for one on one tutoring, but I don’t take money from others.
The only word I can describe CPS 125 is useless.
As a course, it moves slowly and there are still major components of C not covered. As a programmer, it
can barely be called an introduction to computer science as it does not include any study of algorithms.
This course is similar to a free online 7 week courses. The assignments are outdated, the twitter account
is annoying as they should simply push D2L notifications, and the online web page feels like they are
mocking students. Every assignment is confusing to read as they make you write code, then expect you
to erase it and add on more, instead of saying what is required from the start. In other words, the course
should be an online credit.
Disclaimer: I am not responsible for any plagiarism committed by the presence of this document, this
only serves as a guide. Any plagiarism will not be tolerated by Ryerson University, nor is this guide
intended to be an answer sheet. This guide will help only if you apply yourself by programming.
1
Contents
1 Definitions and Conversions 4
2 The C Language 9
4 Libraries 22
4.1 The Math Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
4.2 The Standard Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
4.3 The Standard Input Output Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
5 Modes of Operation 24
5.1 Interactive Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
5.2 Batch Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
6 The if Statement 26
6.1 Else if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
6.2 Nested if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
7 Switch Statement 28
8 Loops 29
8.1 While . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
8.2 Do While . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
8.3 for Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2
10 Independent Functions 35
10.1 Create Your Own Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
10.2 Multiple Return Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
10.3 Using Two Dimensional Arrays with Independent Functions . . . . . . . . . . . . . . . . . 36
11 Recursion 37
13 Linked Lists 41
14 Labs 44
14.1 Lab 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
14.2 Lab 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
14.3 Lab 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
14.4 Lab 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
14.5 Lab 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
14.6 Lab 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
14.7 Lab 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
15 Assignment 1 55
16 Assignment 2 57
17 Ending Comments 59
3
1 Definitions and Conversions
Definition: An algorithm is a series of instructions on how to solve the problem.
A computer is something we use in our everyday life, we recognize the keyboard, mouse, and display but
we rarely think about the complexity required to make such devices work seamlessly together. In computer
science, we try explain how computers work on the inside and why you should care.
Where di = 0,1,...,9. Recall, that every number is a place holder for a power of ten.
4
Representing an integer number N in binary
1. First largest power of two smaller than or equal to N.N ≥ 2i ‘. Keep track of the power i.
3. Repeat step 1 with your new smaller number until you get to zero.
4. In an empty space, write down the powers of two increasing from right to left. Starting at zero
5. Recall all the i’s found in step 1. Wherever that power of 2 exists, write a one above it.
6. For all other places which did not find a power. Write a zero above the power.
• 89 − 64 = 25
• 25 − 16 = 9
• 9−8=1
• Notice that 1 = 1 = 20 . i = 0
• 1−1=0
• We found i = {6, 4, 3, 0}
1 1 1 1
6 5 4 3 2 1 0
2 2 2 2 2 2 2
89 = 1 × 26 + 0 × 25 + 1 × 24 + 1 × 23 + 0 × 22 + 0 × 21 + 1 × 20 (5)
Exam tip: On the multiple choice, you do not have much time. Therefore, instead of converting the
number into binary slowly. Just check if the question asks for an odd number. If this is the case, the right
most bit must exist. You can prove this yourself.
Now we move on towards 32 bit number. To represent 89 in 32 bits, you use the same result. Except this
time there are 26 zeros in front.
5
Notice there is little spacing between every 4 bits. This is more visual, but it’s important for being orga-
nized. Since there are 32 bits, you expect there to be 8 chunks of 4 bits.
Up till now we have only been using positive numbers. This is because negative numbers add a small
layer of complexity. In order to make sure the computer can differentiate between a negative and positive
numbers, the left most bit is always reserved.
Currently, there are two methods for dealing with negative numbers,
2. Two’s Compliment
Sign Magnitude
Caution: This method is simple, but it is almost never used. This is due to fact adding and subtracting
are very difficult, and it leaves an ambiguous case for zero. You can literally have a −0 or +0.
Two’s Compliment
• flip every bit starting from the left to the right to a 1 until the least significant bit.
You do not flip the least significant bit, nor do you flip the bits after
9 = 0000 0000 0000 0000 0000 0000 0000 1001
−9 = 1111 1111 1111 1111 1111 1111 1111 0111
This method is used as adding and subtracting are works normally, has a defined case for zero. The term
least significant is the right most bit of your number if it was positive. In the example below, the least
significant bit(LSB) is marked as L.
Binary and decimal are not the only two numbering systems. We also have hexadecimal system, remember
hex means 16 so the maximum number this system can represent is 15. But since we only have numbers
up to 9, we have to switch to alphabets.
0123456789ABCDEF
6
This is technically a more efficient system for numbering as it uses less digits for larger numbers. Google
uses a similar method for numbering the amount of Youtube videos. As a reference, I created a table from
everything I have talked about.
Binary to Hexadecimal
When converting numbers from binary to decimal, simply take each block of 4 bits and convert them
individually,
Binary to Octal
When converting numbers from binary to octal, simply take each block of 4 bits re-bunch them starting
from the left in groups of 3. Then convert each bunch of 3 directly into octal.
7
Floating Point Numbers in Binary (Watch the Two Videos)
Floating point numbers are simply real numbers. Numbers such as 21.23. The problem is, how do we get
decimals into binary, we can’t really do 1001.1101.
Left most bit is allocated for sign, followed by 8 bits for the exponent, and 23 for the mantissa. That’s
right, we will be using 32 bits for this method. For more visual learners, the format follows as,
[sign][exp(8)][mantissa(23)]
Steps for converting a real number R to IEEE 754 Single Precision Binary
1. Determine the sign. If the number is positive, the sign is 0, if it is negative the sign is 1.
3. To determine exponent, take the greatest power of 2 that’s less than R(we shall call it i). Plugging
i into the formula,
exp = 127 + i
We get the exponent in decimal, represent this number in binary plug into allocated exp place.
5. If the number is now greater than or equal to one make note of it, subtract one. Continue to the
next step if the number is now zero or you find a pattern, else go back to step 4.
6. Take the ones which you noted multiplying by 2, and write them in a row. This is your binary value
for the mantissa. Rewrite the value as follows.
Eg: (floor(N ))2 .[Mantissa]
8. Copy everything after the decimal into the space for your mantissa.
You can see how long this method is, on the exam you will need to do this fast
I would love to say I am going to do an example, however words are never going to explain it better than
these two videos:
Decimal to Binary
Binary to Decimal
Exam Tip: For the multiple choice, instead of validating the mantissa, check if the sign and exp match.
8
2 The C Language
Using English, we are able to use multiple letters to form words, then use these words to form sentences,
and sentences to form proper arguments. However, computers speak in binary, this is due to the fact that
an electrical signal can either be on or off. People didn’t want to look at a screen filled with ones and zeros,
so instead they created Assembly language. Assembly language utilized human readable hexadecimal val-
ues instead of ones and zeros, and mnemonic codes to perform tasks which made it simpler than machine
language. Now, we get to the type of language which we know today. So called “high level languages” such
as: C, Fortran, Java, and Python. This made programming available to the masses as you could write a
program and never care about the registers or memory allocation.
C is one of the most widely known programming languages around. But why is this the case? C is portable,
efficient, easy to learn, and modular. It teaches proper memory management, and forces the programmer to
care about system resources and clean code. In this class we use C to program solutions to various problems,
Definition: A preprocessor is a system program that modifies the program prior to compilation
Definition: A preprocessor directive is instructions for the preprocessor, beginning with #
Definition: A library is a collection of functions, symbols, and values.
In C there are two types of preprocessor directives
# include
and
# define
Each command is terminated with a semi-colon(;). The compiler has no sense of tabs or line numbers, but
it is case sensitive.
9
Definition: A comment is a line or lines of code which is ignored by the complier. To declare a comment,
we generally use “// Single Line Comment” or “/* Multi line Comment */”
We have talked about functions in math. It can be thought of as some black box that takes some input
and produces some output. In programming, it’s the same as math, except we call inputs as function
arguments.
f (x, y, z) (6)
Where f is some function, x, y, z are some inputs. In the same you can see how programming is almost
identical,
function_name ( argument_1 , argument_2 , argument_3 ) ;
Just like f is a function, now you have a function with the name “function_name”, and it takes in 3
arguments just like x,y,z. This will provide an output based on the arguments.
10
3 Learning The Basics
The general skeleton of a program is,
1 # include < stdio .h >
2
3 int main ( void )
4 {
5 // This is your main function
6 return (0) ;
7 }
By the time you finish this course, you should be able to blindly type this code. Let us dissect this template,
# include < stdio .h >
This statement informs the preprocessor that some functions in our program may be defined in the stdio.h
library. The stdio.h library is simply short for “Standard Input Output Library” and contains a vast
majority of the functions we will learn about.
int main ( void )
In C, when the file is being compiled. The compiler searches for a function called main. Since main is a
function it will take inputs, but as you can see the arguments are “void”. In the very beginning of this line
you see “int” this is to inform the compiler, this function will return an integer value.
return (0) ;
This line is simply following suit as we are supposed to be outputting an integer value from this function.
Therefore, we simply return the integer 0.
In order to declare a variable you must write the type, followed by the name and data stored.
/*
< type > < variable name > = < stored value >;
This might seem easy, but you need to know what classifies as a identifier name by the compiler.
11
3.1 Hard Rules for Identifiers
1. It can only contain underscores, letters, and numbers ( _ , ABC , 123)
Additionally, there are conventions in the Computer Science field for variable names. It would be correct
not to follow the rules below, but your co-workers would probably kill you
2. Identifiers are are all lower case (eg. int class_average = 33)
12
3.3 Placeholders for IO Statements
In this course, only the following placeholders will be used,
3. %d - Integers (int)
4. %c - Characters (char)
%N d N is the number of assigned space for an integer, it begins to fill the space from right to left
%.N d N is the number of assigned space for an integer, it begins to fill the space from left to right
This fills the place holders to the left with zeros
% w.d lf w is the total space allocated for this double
d is the number of spaces reserved after the decimal point
Note: w is the space including the integer and decimal part of a floating point number. The integer
portion is always prioritized over the decimal. Therefore, if you have an l number of digits for the integer
component, the spots left for the decimal is w − l. If w − l ≥ d then the result is exactly what you would
expect, otherwise it would truncate(round) the decimal earlier.
Caution: If you use a wrong placeholder, the number will print zero.
These place holders are used IO functions like printf, scanf, and fscanf.
printf ( " Stuff to print : %d " , integer_variable ) ;
9 // You can print multiple variables as long as there exists placeholders for each value .
10 printf ( " Value of x : %4 d = %.4 d \ n " ,x , x ) ; // The \ n prints a newline
11 printf ( " Value of y: %f \n", y);
12 printf ( " Value of z : % lf = %5.3 lf = %2.9 lf = %0 lf \ n" ,z ,z , z ) ;
13
14 return 0;
15 }
Try and grab a piece of paper to determine the output. The answer is on the next page.
13
Note: The first time x is printed, the output is shifted one to the right due to the unused space allocated.
3.4 Pointers
Pointers are unbelievably useful, but it’s tricky to understand.
We know x is a variable, so therefore it must be stored somewhere in memory. To get the address(location)
of where it is located, you can use the & operator. We should note that the address is not the value of the
variable. Try this code,
1 # include < stdio .h >
2 int main ( void )
3 {
4 int x = 5;
5 printf ( " The value of x is % d \n " , x ) ;
6 printf ( " The address of x is %p \n " , & x ) ;
7 return (0) ;
8 }
You will notice, the second value that prints just seems like garbage number. This is in-fact the memory
address where the integer is stored. Now you may ask why would you ever want to use pointers? To which
I would reply with another question. Imagine you had a house, and you wanted to call a plumber over
to your house. How do you get a plumber to come over? I don’t think any logical person would bring
the house to the plumber. Instead, you would call up the plumber and tell them your home address. The
plumber can then come over do their job.
Similarly, if programming and you find a point where a function(plumber) needs to work on something
complex like a matrix or multi-dimensional array(house). You send over the address. Moving huge chunks
of data and recreating multi-dimensional arrays multiple times is cumbersome and simply bad code.
We have a specific type of variable that contains the address of another variable. This is what we call a
pointer.
14
9 ptr = NULL ;
10
11 return (0) ;
12 }
Major thing to notice is on line 7. I made sure my pointer was no longer pointing to x, instead it’s now
equal to null
The whole reason why C is such an amazing language to learn is the simplicity and how it forces good
memory management.
Now you might be wondering. If there is an address stored, shouldn’t we be able to work backwards and
see what the address contains? You are correct. This is called dereferencing a pointer. We use the
*pointer_name to dereference a pointer. In the example above, we can use
x = * p;
and that would be the same as saying,
x = x;
3.5.2 Strings
How do arrays relate to strings? Well a string is an array of characters as shown below.
char < string_name >[ max_letters_in_string ] = " some string " ;
Notice: You do not use single quotes, instead you use double quotes for strings.
A string and an array in the simplest form is a pointer. When declaring a string or an array, it is necessary
to inform the complier the amount of memory to be allocated towards it. After the memory is allocated,
there is a pointer used to keep track and grab values from the assigned memory. This process is similar to
those old multi-disk music players from the early 90’s.
15
3.5.3 String Arrays
You may want to create an array of strings. The code for such an idea is shown below.
int * array_of_strings [5] = { " Hello " , " My " , " Name " , " is " , " Student " };
The main difference between a regular array and an array that can store strings is shown in the code above.
For an array which can store strings, you use an array pointer (which is why you use of the ∗). If ∗ was
missing, then it would be a regular character array that can hold 5 characters. With the ∗, it means it can
hold 5 strings.
In order to create a two dimensional array, you would use the following code
<type > < array name >[ i ][ j]
In this class, you are being asked to use the Row-major order. Therefore, in the code above, i is the
column number and j is the row number. As an example, to create a 7 by 7 array of integers, you would
use the following code.
int matrix [7][7];
Caution: Once again remember the index of an array begins at 0. Therefore, a11 is column 0 and row 0.
16
3.6 Arithmetic
3.6.1 Evaluating Expressions
For the most part arithmetic in code is evaluated the same way as math.
2. Operators are evaluated in the order: *,/,+, -, % (More order of operations later)
4. If there is a floating point type value in an expression, it will take precedence over integers
This is an integer divided by a floating point number, so the final value is also going to be a floating point.
m = 3.6000000
int r = x *x + y *y + z * z ;
For r, we have an integer, float, and double all squared. int r = 9 ∗ 9 + (2.5 ∗ 2.5) + (3.1 ∗ 3.1). Let us go
through with the multiplication. int r = 81 + 6.25 + 9.61. Since we are adding an integer to a float and
double, our final result will be a float. int r = 96.86. But now since r can only store integers, we need
to convert a double to an integer. This is where rule below comes into play, by this logic, r = 96.
Note: If we change a float/double to an integer, it will always round down to a whole number. Addition-
ally, if we divide integers to get a decimal, it will be rounded down
double u = ( x *y ) *(1/ x) *( z /( x * y ) ) ;
We can see u = 0, because we have 1/x, which are two integers so it evaluates to zero.
17
3.6.2 Casting
Sometimes when doing arithmetic or dealing with functions of different types, it’s useful to temporarily
change the type of a variable or the return type of a function. This temporary change in type is called
casting
10 return (0) ;
11 }
If you were to compile and run the program above, you would find c = 0.000 Since we know since c is
an double, the code’s initial intention was to make c = 0.66667 = 2/3. Because a and b are integers, it
rounds down 0.6667 to 0.000. If we want to avoid such easy mistake, it’s a good idea to use casting. The
following code below shows how to cast.
( < new temp type >) variable
18
3.6.4 Increment and Decrement Operator
Similarly, you also use counter variables which require to increase by one or decrease by one each time.
Instead of writing every time,
i = i + 1;
// or
i += 1;
we use
i ++;
we use
i - -;
i++ runs through the code before incrementing the value, whereas ++i increments before evaluating. We
can easily show this with an example.
# include < stdio .h >
In the end a = b = 2. But x = 1 and b = 2, this is because ++b increments before evaluating the expression,
whereas a++ increments after.
19
2. The || or or operator which means either side of or has to be true
Note: For line 5 and 6 remember the rounding rule for integers we discussed.
2. Unary Operations
20
3. Multiplication, Division, and Modulus
4. Addition, Subtraction
5. Comparison Operators
6. and statements
7. = operator
You are expected to know how arithmetic works and what operations take precedence in a complex line
of code.
21
4 Libraries
In this course, we only use 3 different libraries. So therefore, I will introduce you to them and anything
testable.
In the math library all functions below will return floating point values no matter the input type. Some
important functions in this library are :
sqrt ( x) // Returns the squareroot of the input ( eg . sqrt (69) = 8. somthing )
floor (x ) // Returns the number rounded down ( eg . floor ( -1.2) = -2.0)
ciel ( x) // Returns the number rounded up ( eg . ciel ( -1.2) = -1.0)
log (x ) // Returns log base e of x or ln ( x ) ( eg . log ( e) = 1.0)
log10 (x ) // Returns log base 10 of x ( eg . log10 (100) = 2.0)
fabs ( x) // Returns absolute value of x ( eg . fabs ( -1.2) = 1.2)
22
1 int variable = 2
2 printf ( " variable % d" , variable ) // Will print " variable 2"
3 scanf ( " %d " , & variable ) // Gets an integer from user and stores it
We will go more in depth on these functions later and you will see them being utilized everywhere through-
out this course. For any programs you write, this will be the default include.
23
5 Modes of Operation
There are two modes by which a program can operate.
1. Interactive Mode - The program will print words on the screen and ask for input.
2. Batch Mode - The program will read and write to a file.
24
5.2 Batch Mode
Imagine you had a file with the name “data.txt” containing the number 42. In order to read from the file,
we use the following code.
1 # include < stdio .h >
2
3 int main ( void )
4 {
5 int data_from_file ;
6
To load a file, we use the function fopen. fopen takes two arguments. The first argument is a string of
the file name, and the second is the status. We set the status to “r” which means read only.
fscanf ( data_file , "% d " , & data_from_file ) ;
fscanf is exactly like scanf, except the first argument is now the file pointer. Each value we read, the file
pointer moves to the next value inside the file.
fclose ( data )
This deallocates the file pointer. We elaborate more on files after we cover loops.
Now imagine you wanted to write the number 42 to a named “data.txt”. The code is almost exactly the
same as reading, except now we use fprintf.
1 # include < stdio .h >
2
3 int main ( void )
4 {
5 int data_to_store = 42;
6
7 FILE * data = fopen ( " data . txt " , "w " ); // This time the mode is w. This is to write .
8
9 fprintf ( data , " %d " , data_from_file ) ;
10
11 fclose ( data );
12 reutrn (0) ;
13 }
You can notice the similarity between printf and fprintf. It’s almost identical but the first argument
for fprintf is the file pointer
25
6 The if Statement
If you want to implement conditional logic into your code, then you should consider the if statement. The
general form of the if statement is:
if ( condition )
{
// do something
}
else
{
// do something
}
Recall: the condition is statements or statements combined with logical operators. We saw how state-
ments and logical operators work in section 3.6.6.
If the condition is true, the code inside the parenthesis will run. In other words, the condition is checked
before running any code inside the parenthesis. The code inside the else statement will only run if the
condition is false
6.1 Else if
If you know there are many outcomes, but only one of them is true. You can use an else if statement.
An else if statement is used directly after an if statement or another else if statement. It optimizes
your code, because if the initial if statement or any other else if statement is true, then any else if
or else statements below are skipped.
You will find the structure of an else if statement identical to that of a regular if statement. An example
of using else if is shown below,
1 # include < stdio .h >
2
3 int main ( void )
4 {
5 int x = 0;
6
7 printf ( " Please input a number : " ) ;
26
8 scanf ( " % d" , &x ) ;
9
10 if (x == 0)
11 {
12 printf ( " Zero is such a boring number " );
13 }
14 else if ( x > 0) // Notice the position ( between if and else )
15 {
16 printf ( " Ohh a positive integer " ); // Notice the identical structure to if
17 }
18 else
19 {
20 printf ( " Ohh a negative integer " );
21 }
22
23 return (0) ;
24 }
6.2 Nested if
For more complex scenarios, you may find yourself trying to use an if statement inside another existing
if statement. This “if inside another if” is called a nested if statement. Below is an example to show the
structure of a nested if statement.
1 # include < stdio .h >
2
3 int main ( void )
4 {
5 int a = 2; int b = 3; int x = 4; int z = 9;
6 if ( a < b) // This is the main if statement
7 {
8 x - -;
9 if ((z -5) == x ) // This is nested if statement . It is inside another if
10 {
11 printf ( " Hello World " );
12 }
13 else
14 {
15 printf ( "I sleep 14 hours a day " ) ;
16 }
17 }
18 }
The code above will print “I sleep 14 hours a day”. You should note that if the main if statement is false,
then the nested if statement’s condition is never checked. Because the code inside your main if statement
is skipped.
27
7 Switch Statement
A switch statement is like an if statement, and is used when you have one condition and you know the
possible output values. The general form of a switch statement is,
switch ( variable )
{
case value1 :
\\ code here // Notice no parenethesis are being used .
break ; // the " break " keyword is used to end each case
case value2 :
\\ code here
break ;
case value3 :
\\ code here
break ;
...
default :
\\ code here
break ;
}
The break keyword in C is used to forcefully end loops. In the general form, we can only end each case
with a break. As an additional note, you must avoid ending while or for loops using break, as it is typically
considered as “bad code”. The example below shows one such use for using
1 # include < stdio .h >
2
If we run the code above, it will output the following statement: “Failing is a part of life”. This is because
the RAMSS_grade is an ’F’, and the code has instructions to run in that specific case. Note, when none of
the cases match the variable, then the default case runs.
28
8 Loops
A loop is just something that repeats itself. if you notice you are copying and pasting something multiple
times, chances are you need a loop.
1. while loop
2. do while loop
3. for loop
Again for the following section, I encourage you to pull up and compile the code yourself.
8.1 While
A while loop will literally do something while a condition is true. The general form of a while loop is as
follows,
while ( condition )
{
// Code here
}
The condition is only checked before any of the code inside the parenthesis is run.
29
8.2 Do While
Do while is exactly the same as a while loop. However, initially the code inside do is run before the
condition is checked. It has a general form,
do
{
// Some code here
} while ( condition ) ;
This type of loop is generally used for input validation, as it can be very simple to apply. The code below
is an example of input validation using this loop.
1 # include < stdio .h >
2
3 int main ( void )
4 {
5 int number = 0;
6 do
7 {
8 printf ( " Please input an integer number between 0 and 25: ") ;
9 scanf ( "% d " , & number );
10
11 } while ( number <= 0 || number >= 25) ;
12
30
1 # include < stdio .h >
2
Try and find out what the code above will print.
31
9 Dealing with Files using Loops
9.1 Reading a Whole File
Imagine we have a file called “data.dat”. Inside this file, we have the following values tabulated.
1 92
2 88
3 97
4 90
5 94
Since I am an Electrical Engineering student, for the second semester I only take 5 courses. The numbers
indicate each of my course averages. Your job is to take these 5 courses and find the TGPA.
32
9.2 Writing to Files
Time to step it up a notch.
Imagine you created a game. Every time your friend and you play, it always starts a fight because no one
kept track of score.
• There are 5 rounds per game, you will ask who won each round
• You should expect input of “1” or “2” as the winner of each round. Input Validation!
• At the end of each game, you must include the phrase “END–” on a newline followed by two additional
newlines.
33
33 printf ( " Player 2 wins " );
34 }
35
36 fclose ( data ) ;
37
38 return (0) ;
39 }
34
10 Independent Functions
10.1 Create Your Own Functions
Independent functions are functions other than main(void). We discussed this earlier when studying the
basics, but now we are going to be creating functions. In order to declare a new function we can follow
the outline below.
< return_type > < function_name > ( < arguments >)
{
// Code to run
}
Your function needs to be above main unless we use forward declaration. The following is an example of
how to use a function.
1 # include < stdio .h >
2
3 int print_number ( int number )
4 {
5 printf ( " Number you want to print is %d " , number ) ;
6 }
7
35
can manipulate the stored value at that address.
1 # include < stdio .h >
2 # inlcude < math .h >
3
4 int split_decimal ( double num , double * fractional_part ) ; // Expects a double and a
double address
5
6 int main ( void )
7 {
8 double fractional_part ;
9 int integer_part ;
10
11 // & integer_part is the address of integer_part
12 integer_part = split_decimal (3.14 , & integer_part ) ;
13
14 printf ( " The integer part is : % d\ n " , integer_part ) ;
15 printf ( " The fractional part is % lf " , fractional_part ) ;
16
17 return (0) ;
18 }
19
20 int split_decimal ( double num , double * fractional_part )
21 {
22 * fractional_part = num - floor ( num ) ; // Dereferencing the address allows me you to
23 // change the variable directly .
24 return ( floor ( num ) ) ;
25 }
If the function’s name was “find_border” with a return type double, expecting a two dimensional double
array named “mama_mia” of size 200. Then follow the code below.
double find_border ( double mama_mia [][200])
36
11 Recursion
Recursion is a bit finicky but useful. Especially if you want to backtrack in programs. Recursion in the
simplest terms is a process which calls itself to solve a smaller problems of itself (weird). In this course we
have simple applications such as finding a factorial or subtracting a number constantly.
As an example, to find a factorial of any number input you can use the following code.
1 # include < stdio .h >
2
The example below is another use of recursion. We find the greatest common factor.
1 # include < stdio .h >
2
3 int gcd ( int x , int y )
4 {
5 if ( y == 0 )
6 {
7 return x;
8 }
9 else
10 {
11 gcd (y , x %y );
12 }
13 }
14
15 int main ( void )
16 {
17 int g ,r , ans ;
18
37
21
22 ans = gcd (g , r) ;
23 printf ( " The greatest common demoninator is : %d " , ans ) ;
24
25 return (0) ;
26 }
To make sure you do not get lost when deal with these recursive functions. Always develop a mathematical
way of looking at your recursive function. For example, in the code above we have the following function
for gcd.
{
x if y = 0
gcd(x, y) = (7)
gcd(x, remainder(x, y)) if y > 0
You can compute the output without rereading the code multiple times. For more complex examples, try
solving the “N Queens Problem”.
38
12 Dynamic Memory Allocation
For dynamic memory allocation we will be using functions from the standard library.
# include < stdlib .h >
Dynamic memory allocation is used when we don’t know how much memory we are going to be using.
Remember when I said that an array could be thought of as a pointer. Now we are going to create an
array using a pointer.
This may look confusing. But let me help digest this new code.
int * array = ( int *) malloc ( amount * sizeof ( int ) ) ;
amount is the number to be stored in an array. So the total size the array will use is amount multiplied by
the size of an integer.
( int *) malloc ( amount * sizeof ( int ) ) ;
using (int *) is technically not needed but to be verbose we need to change the type to something a
pointer can hold.
int * array = ( int *) malloc ( amount * sizeof ( int ) ) ;
39
So therefore, this piece of code assigns the total amount of memory which is going to be accessed through
this pointer. Notice how the use of accessing data is still the same notation used for arrays
array [ element ]
We need to make sure the memory allocated to the array is deallocated and free to use by the system again
free ( array );
1. malloc
2. calloc
malloc only uses one argument which is the total space to allocate.
malloc ( amount * sizeof ( int ))
But calloc takes two arguments which number of them to allocate and the type respectively
calloc ( amount , sizeof ( int ))
The main advantage of using calloc over malloc is that it allocates space, but also zeros the data spaces
allocated. In doing so, malloc is effectively slower than calloc. In our previous example, we don’t care if
the initialized array is all zeroed.
Note: Two dimensional dynamic arrays are not important for this course. However, you should under-
stand how to use arrays and two dimensional array with functions.
Exam Tip: You have to know how to create a dynamic array; as shown above; by hand.
40
13 Linked Lists
Do you remember those detective shows? There is always one chiché scene in the detectives house where
a wall is filled with red string attached to tacks holding up paper clippings. Each tack contains data, but
it also holds the string to the next tack.
Well, it’s almost like a linked list. In programming terms, each tack would be called a node, and the string
would be the links. Each node is located at some address, and it is joined to other nodes by links. Each
node contains data and the location of the next node. Currently, we can’t represent a node by a variable,
because we can store two data types in one. This means we have to create a composite data type. The
general form for creating a new data type is as follows
typedef struct NODE
{
struct NODE * ptr ;
int data ;
} node ;
Let’s explain some of this code in easier context.
41
Therefore, going back to our initial code,
typedef struct NODE
{
struct NODE * ptr ;
int data ;
} node ;
We have a composite data type called struct NODE which contains a pointer to other struct NODE vari-
ables and data. struct NODE is also renamed to be node for ease of use.
How do you access the data and pointer of a composite data type? You use the dot operator!
< composite data type variable >. < value to access >
We can only use the dot operator when you are accessing the data using the variable. When accessing the
data using a pointer, you use the arrow operator
iaf * t = & var ;
In the code above, note that t -> data is the same as var.data. The difference is because you are using
a pointer to access the data, whereas simply using the variable. This is very useful as shown below.
The first node in a linked list is called a head. The address of the head should be carefully used or you
risk losing the list. The last value in the list should always have it’s pointer set to null.
1 # include < stdio .h >
2
3 typedef struct NODE
4 {
5 struct NODE * ptr ;
6 int data ;
7 } node ;
8
9 int main ( void )
10 {
11 node head ;
12 node node_a ;
13 node node_b ;
14
15 head . ptr = & node_a ;
16 node_a . ptr = & node_b ;
17 node_b . ptr = NULL ;
18
19 head . data = 1;
20 node_a . data = 2;
42
21 node_b . data = 3;
22
23 for ( node * t = & head ; t != NULL ; t -> ptr ) // Transverse the list using a pointer
24 {
25 printf ( " % d " , t -> data ) ;
26 }
27
28 return (0) ;
29 }
This code should output: “1 2 3 ”. Using linked lists can be very tricky. This is a topic where a lack of
practice leads to a lack of understanding. I encourage you to make a linked list on your own. Maybe even
try doubly linked lists (you keep track of the previous element and the next element using their addresses).
Additionally, please play around and see if you can create functions to add links, delete links, and find
specific values in the linked list.
And we are finally done the main portion of this guide. I wrote this in 3 days so please excuse any mistakes.
43
14 Labs
14.1 Lab 1
1 # include < stdio .h >
2
3 int main ()
4 {
5 // You should use the function printf ("") . Anything inside the quotations will be
printed .
6 printf ( " This \ nIs \ nMy \ Second \ nC \ nProgram \n " )
7 // the "\ n " makes the printf function print a newline on the screen .
8 printf ( " X O X \ nO O X\ nO X O " );
9
10 return 0;
11 }
44
14.2 Lab 2
For this lab, you have to understand syntax and arithmetic. Additionally, you should also try to compute
each the value of c.
1 # include < stdio .h >
2
3 int main ( void )
4 {
5 int a = 3, b = 4 , e ;
6 double f = 4 , c , d ;
7
8 d = a + b;
9 c = a/ f - b;
10 printf ( " The value of d is % lf \n " , d ) ;
11 return (0) ;
12 }
45
14.3 Lab 3
1 # include < stdio .h >
2 # include < math .h >
3
4 int main ( void )
5 {
6 int num1 , num2 , num3 , num4 , sumTotal , sumDifference , sumSquares ;
7 double sumSqrt ;
8
9 printf ( " Please input values for num 1 -4: \ n" );
10 scanf ( " % d % d %d %d " , & num1 , & num2 , & num3 , & num4 ) ;
11
12 sumTotal = num1 + num2 + num3 + num4 ;
13 sumDifference = ( num1 + num2 ) -( num3 + num4 ) ;
14
15 // Instead of using the math function to square variables ,
16 // it would be easier to multiply them by themselves .
17 sumSquares = num1 * num1 + num2 * num2 + num3 * num3 + num4 * num4 ;
18
19 // sumSqrt should be a double value , therefore you should cast any ints into doubles .
20 // This is not needed because integer and floats always convert to floats
21 // But you should try and stay consistent
22 sumSqrt = sqrt ( sumSquares ) /( double ) ( sumTotal ) ;
23
24 // Printing values using placeholders such as % d and % lf
25 printf ( " The sum total is : % d \n " , sumTotal ) ;
26 printf ( " The difference between the first two and last two integers %d \ n" , sumDifference )
;
27 printf ( " The sum of the squares is : % d\ n " , sumSquares ) ;
28 printf ( " The square root of the sum of squares divided by the sum totoal is : %.2 lf \n " ,
sumSqrt ) ;
29
30 return 0;
31 }
46
For the code below, you will notice the use of loops and arrays. This is a faster and more simpler method,
but not expected for you to do. Instead of using a loop, you would have to input each value. In the section
covering loops, we noted that whenever you have to repeat an action numerous times it’s simpler to use a
loop.
1 # include < stdio .h >
2
3 int main ()
4 {
5 // Creating required variables .
6 double convertedYards , convertedMiles , toConvert ;
7 // Using an arrat to store values of the data
8 int values [4] = {100 ,200 ,400 ,800};
9
10 printf ( " --- - -- - -- -- -- -- -- -- - - - - - - - - - - - - - - - -\ n" ) ;
11 printf ( " | Meters | Yards | Miles |\ n" ) ;
12 printf ( " --- - -- - -- -- -- -- -- -- - - - - - - - - - - - - - - - -\ n" ) ;
13
38 return 0;
39 }
47
14.4 Lab 4
1 # include < stdio .h >
2
3 int main ()
4 {
5 int a1 , a2 , t1 , t2 , sum ;
6 double avg ;
7 char grade ;
8
9
10 printf ( " Input 2 assignment marks : " ) ;
11
12 // This is yet another method of input validation
13 while ( scanf ( " %d %d " , & a1 ,& a2 ) == EOF || a1 > 100 || a2 > 100)
14 {
15 printf ( " \ nPlease enter valid integer values \ n ") ;
16 printf ( " Input 2 assignment marks : ") ;
17 }
18 printf ( " Input 2 test marks : ") ;
19
20 // Another use of input validation
21 while ( scanf ( " %d %d " , & t1 ,& t2 ) == EOF || t1 > 100 || t2 > 100)
22 {
23 printf ( " Please enter valid integer values \ n" ) ;
24 printf ( " Input 2 test marks : ") ;
25 }
26
27 sum = ( a1 + a2 + t1 + t2 ) ;
28
48
14.5 Lab 5
1 # include < stdio .h >
2
3 int main ()
4 {
5 // Set up variables and file pointer
6 int num_samples , beach_num , num_orgs_per_100 , total ;
7 FILE * data = fopen ( " data . txt " , " r" ) ;
8 double sample_avg = 0;
9
10 // Make sure the file exists
11 if ( data )
12 {
13
14 printf ( " Beach | Sample Num | Samples | Samples Average | Safe or Not Safe \n " );
15
16 // Statement used to read to the end of file
17 while (! feof ( data ) )
18 {
19 // Read the data from the file and store in vars
20 fscanf ( data , "% d % d " , & beach_num , & num_samples ) ;
21
22 printf ( " %3 d |%7 d | " , beach_num , num_samples ) ;
23
24 total = 0;
25
26 for ( int i = 0; i < num_samples ; i ++)
27 {
28
49
56 else
57 printf ( " Unable to open file " ) ;
58 }
Note: The code feof(<file_name>) returns true if the file pointer is at the end of the file. Therefore, the
code below will simply run until it reaches the end of the file.
while (! feof ( file_name ) )
{
// code
}
50
14.6 Lab 6
1 # include < stdio .h >
2
3 // Forward Declaration of 3 functions expecting 3 integer arguments
4 int max_of_3 ( int , int , int );
5 int min_of_3 ( int , int , int );
6 int mid_of_3 ( int , int , int );
7
8
9 int main ()
10 {
11
12 // Our variables are declared here
13 int a ,b ,c;
14 int max , min , mid ;
15
16 // Ask the user for input
17 printf ( " Please enter a value for a ,b ,c : " );
18 scanf ( " % d % d %d " ,&a ,& b ,& c ) ;
19
20 // Functions are used to dertermine the max , min , and mid values
21 max = max_of_3 (a ,b , c ) ;
22 min = min_of_3 (a ,b , c ) ;
23 mid = mid_of_3 (a ,b , c ) ;
24
25 printf ( " The value from least to greatest are : % d % d % d" , min , mid , max ) ;
26
27 return 0;
28 }
29
30
31 int max_of_3 ( int a , int b , int c)
32 {
33 // Check if a is bigger than the rest
34 if ( a > b && a > c )
35 {
36 return a; // Return a as it is bigger than the rest
37 }
38 // Check if b is bigger than the rest
39 else if (b > a && b > c )
40 {
41 return b;
42 }
43 // Therefore , if a and b are not the biggest . The biggest will therefore be c
44 else
45 {
46 return c;
47 }
48 }
49
50 int min_of_3 ( int a , int b , int c )
51 {
52 if ( a < b && a < c ) // Find the smallest using comparitors
53 return a;
54 else if (b < a && b < c )
55 return b;
51
56 else
57 return c;
58 }
59
60
61 int mid_of_3 ( int a , int b , int c )
62 {
63 int max , min ; // Check what number has not been used from the 3
64 max = max_of_3 (a ,b , c ) ;
65 min = min_of_3 (a ,b , c ) ;
66
67 if ( a != max && a != min )
68 return a ;
69 else if (b != max && b != min )
70 return b ;
71 else
72 return c ;
73 }
52
14.7 Lab 8
This was a more dynamic approach to the problem. The way you would be expected to setup your array
and pass it through functions is covered in section 3.5.4 and 10.3. Other than the set up of the array,
everything is the same. If you have time, try and understand the setup of the dynamic two dimensional
array below.
1 # include < stdio .h >
2 # include < stdlib .h >
3
4 void print_matrix ( int ** a , int matrix_size ) ;
5
6 int main ()
7 {
8
21 int ** a = malloc ( matrix_size * sizeof ( int )) ; // Dynamic array based on the size
22 for ( int j = 0; j < matrix_size ; j ++)
23 {
24 a[j ] = malloc ( matrix_size * sizeof ( int ) ) ;
25 }
26
53
51 for ( int d = 0; d < matrix_size ; d ++) // Empty dymanic array
52 {
53 a[d ] = NULL ;
54 }
55 free (a ); // Deallocate memory
56
57 fclose ( data_file );
58 }
59 }
60
61 // Function that prints the matrix
62 void print_matrix ( int ** a , int matrix_size )
63 {
64 for ( int x = 0; x < matrix_size ; x ++)
65 {
66 for ( int y = 0; y < matrix_size ; y ++)
67 {
68 printf ( "% d\ t " , a [ x ][ y ]) ;
69 }
70 printf ( " \ n" );
71 }
72 }
54
15 Assignment 1
1 # include < stdio .h >
2 # include < math .h >
3
4 int main ()
5 {
6 // Counters to develop the fibonacci sequence
7 int a = 0, a_1 = 1, a_2 = 0;
8
9 int amountSqrt = 0;
10
11 // Keep a counter to how many numbers were calculated
12 int amountNums = 1;
13
14 // 31 st element
15 int num31 = 0;
16
17 double goldenRatio = 0;
18
19 while (a <= sequenceMax )
20 {
21
22 printf ( " % d " , a );
23
24 if ( a_1 != 0)
25 {
26 goldenRatio = ( float )a / a_1 ;
27 printf ( " %.3 lf \ n " , goldenRatio ) ;
28 }
29 else
30 printf ( " Skip \ n ") ;
31
32 // The second last element is equal to the last element
33 a_2 = a_1 ;
34 // The last element is equal to the current element
35 a_1 = a;
36 // The new current element is a sum of the two previous elements
37 a = a_1 + a_2 ;
38
39 // check if the integer has a perfect integer squareroot
40 if ( sqrt (( float ) a) == floor ( sqrt (( float )a ) ) )
41 {
42 amountSqrt ++;
43 printf ( "\ t perfect square " )
44 }
45
46 amountNums ++;
47 // Save the 31 element in the sequence and will print it out later
48 if ( amountNums == 31)
49 {
50 num31 = a ;
51 }
52
53 }
54 printf ( " \n \ nThe amount of numbers displayed is %d " , amountNums -1) ;
55
55
56 printf ( " \n \ nThe number of perfectly sqrt root integers are : % d" , amountSqrt ) ;
57
58 if ( num31 )
59 printf ( "\ nThe 31 st number in the sequence is % d" , num31 ) ;
60 else
61 printf ( " \ nThere was not 31 elements in the fibonacci sequence up to % d " , sequenceMax );
62
63 return 0;
64 }
56
16 Assignment 2
The code below is left as snippets for the reader. Using this guide, go through each function and understand
how they work. You should redo assignment 2 a few times before going to the exam.
1 # include < stdio .h >
2
3
4 double average ( double a [][200] , int row , int col )
5 {
6 double avg = 0;
7
32 }
33 row_avg /= col ;
34 }
35
36 double calc_border ( double a [][200] , int row , int col )
37 {
38 double avg = 0;
39
40 for ( int k = 0; k < col ; k ++)
41 {
42 avg = avg + a [0][ k] + a [ row -1][ k ];
43 }
44 for ( int r = 0; r < row ; r ++)
45 {
46 avg = avg + a[ r ][0] + a [ r ][ col -1];
47 }
48 avg -= corner (a , row , col ) ;
49
50 }
51
52 double diag ( double a [][200] , int row )
57
53 {
54 double avg = 0;
55
56 for ( int i =0 ;i < row ; i ++ )
57 {
58 avg += a[ i ][ i ];
59 }
60 avg /= row ;
61 return avg ;
62 }
63
64
65 int main ( void )
66 {
67 FILE * data = fopen ( " data . dat " , " r" ) ;
68 int row , col ;
69 int r_c , c_c ;
70
71 fscanf ( data , "% d % d " , & row , & col ) ;
72
97 fclose ( data ) ;
98
99 }
58
17 Ending Comments
If you understand the material discussed in this overview, have ample practice by programming daily, and
can easily solve the lab problem, then there is no reason to ever show up to class. I will tell you straight
to your face: if you do not practice, then you will fail.
59