An Introduction to Programming (in C#)
An Introduction to Programming (in C#)
NAME
2016-07-15
1 Preface
1.1 Caveats
2 Programming: from moving bits around memory (nearly) to software engineering
2.1 The role of the programming language
2.2 Variables: named memory locations
2.3 Managing complexity: statements, functions & methods, objects
3 C#, a modern programming language
3.1 What is a language? What is a programming language?
3.2 Syntactic and Semantic Errors
3.3 A simplified software development life cycle: build-and-fix
3.4 Some elements of the C# language
3.5 A simple C# program
4 Declaring and working with value data types
4.1 Programs model something real
4.2 Statements and Expressions
4.3 C# value types we can use to model the real world
4.3.1 Value literals
4.4 Strings (text)
4.5 Variable declaration
4.5.1 Rules and guidelines for identifiers
4.5.2 Scope
4.6 Variable assignment
4.7 Constants
4.8 Arithmetic Expressions
4.8.1 Integer division and numerical type conversion
4.8.2 Operator Precedence
4.9 Type conversion and strings
5 Creating and interacting with objects
5.1 Why objects?
5.2 What is an object?
5.3 Classes
5.4 Creating objects
5.5 Namespaces
5.6 Calling methods
5.7 Properties
5.7.1 Discovering what a method needs as input & what it returns
6 Making decisions in your code
6.1 Conditional statements
6.2 Making Decisions
6.2.1 Comparison Operators
6.2.2 Comparing value types
6.2.3 Comparing objects: Equals() and CompareTo()
6.3 Boolean Operators
6.4 Full operator precedence list
6.5 if, if with else, and switch
6.5.1 if
6.5.2 if-else
6.5.3 Nesting ifs (an example)
6.5.4 Sequences of ifs
6.5.5 Guidelines for nesting or having a sequence of ifs
6.5.6 switch
6.5.7 enumerated types
7 Repeating actions with loops
7.1 Repetition statements
7.2 Pre- and post-tested loops
7.3 Loop Components (IBUT)
7.4 Loop Constructs in C#
7.4.1 while
7.4.2 do-while
7.4.3 for
7.4.4 foreach
8 Writing basic methods
9 Arrays: the first data structure
9.1 Syntax for declaring an array
9.2 Allocating space for an array
9.3 Accessing a single value in an array
9.3.1 Discovering the length of an array later
9.4 Arrays and objects are references
9.4.1 Passing arrays to methods
9.4.2 Arrays of objects
9.5 Multi-dimensional arrays
10 A final word
[ ↔ Expand↶ Close all sections ] Only visible sections will be included when printing this document.
1 Preface
Programming is a skill that no one can learn without practice. This document will not, on its own, teach you how to program—its purpose is to introduce some of the core concepts and the broader context in which programming takes place. Some details of the programming language C# are covered, but many of the finer details are not.
A good series of videos that has you, the novice programmer, doing programming is available at the Microsoft Virtual Academy: C# Fundamentals for Absolute Beginners. The first 12 modules are probably sufficient at this stage of the unit. It will probably be helpful to read this document in parallel with those video tutorials.
It’s also a good idea to keep the C# Reference on hand as you start exploring the features of the language.
1.1 Caveats
This document is a condensed form of the notes for about eight weeks of an introductory programming unit (taught using Java). While there are a number of small examples included, it is not a tutorial (the videos linked to above and lab classes you attend fulfil that purpose). That said, as soon as you have created a Hello World application you can replace the code inside it with the small pieces of code that appear in examples to see how they work. “Playing” with code is a good way to learn how it behaves.
To try any of the examples you will need to install Visual Studio. See the Software document under Essential Information in the MyLO site.
If you find this (rather long) document useful, let me know. If you find it useless, let me know, and provide some description of what you would like different. There are also some topics that are not really covered: the creation of your own classes and methods (terms which will make sense soon). This is in part to keep this document focused on the basics and in part because we will get to such topics around Week 5 of the unit. If you would like material on them then let me know.
Finally, if you would prefer to look over the slides and additional textual notes for the most recent KIT101 Programming Fundamentals unit, which taught Java, then let me know and I’ll assemble them into an emailable package.
2 Programming: from moving bits around memory (nearly) to software engineering
Without programs computers are neither intelligent nor useful. They are machines that must be instructed what to do. At the lowest level a program is a set of instructions that are processed by a computer’s central processing unit (CPU) and which affect binary information stored in its volatile memory (memory that is fast to access but is not persistent if power is lost). The instructions may also affect other hardware devices, such as the display, persistent storage, a printer or a network connection.
For a typical user a program performs some function or set of functions they need to complete a task; many users are unaware of how the program or the computer actually works, and nor should they be. The task of a software developer/engineer is to translate (via many and varied processes) the needs of a user into the machine-executable instructions a computer will follow.
2.1 The role of the programming language
Programming is designing a sequence of simple steps that can be used by a computer to solve some problem. The sequence of steps describes an algorithm.
At the lowest level a program really is just a series of instructions for modifying data stored in memory and interacting with hardware. Machine code and assembly code are instructions that operate at this level. But even simple tasks take many such instructions to perform—the overall task is difficult to see or understand when reading such instructions and programmer productivity (let alone sanity!) would be very low if all programming had to be done this way.
To assist productivity and reduce the likelihood of errors being made we write programs in ‘high-level’ languages, of which there is a very large number. (The usual gag is that there are as many programming languages as students who have taken compiler courses at university, plus one.) A high-level language is easier to read, more expressive (shorter statements in the language can describe more actions) and supports the creation of more complex applications than the languages understood directly by the CPU. A compiler is an application that takes a program written in a high-level language and translates it into machine-executable instructions.
2.2 Variables: named memory locations
Each piece of data stored in a computer has a numerical location or address. It’s inconvenient and error-prone to refer to individual pieces of data directly by their address, so within a program each is given a name. Since their values can be changed they are called variables (just like the symbols in algebra).
Each variable also has a type. For instance, real numbers are different from integers, which are different from pieces of text (called strings), and so on. This is in part because different types of data are represented differently in the binary data stored in memory, and in part it is because they support differing operators that can be applied to change their values. More below.
2.3 Managing complexity: statements, functions & methods, objects
On a small scale a program is a collection of statements. Each statement is a single instruction to the computer. For instance, a statement could be to write some text to the console (command window), or to disable a button, or add 1 to some variable, and so on. Some real examples are given later.
Software is possibly the most complex “thing” ever produced by humans, and also the least forgiving of errors. The earliest programs were monolithic, being nothing but a collection of statements. As a monolithic program grows it becomes harder to understand and to maintain (and keep free of errors): the same statements would need to be repeated in many places and there would be no easy way to see the overall structure of the program.
An improvement over the monolithic approach is procedural programming, where common and reusable sections of code are packaged up in procedures (als called functions and methods). In procedural programming, data and the operations on it are kept quite separate, but data is often quite widely accessible. (Many procedures that don’t need to be able to modify certain data still have access to it.)
A further refinement of procedural programming is object-oriented programming, where the different parts of a software solution are modelled as different classes of objects. Each object (hence, each class) knows how to do a few things really well, and takes responsibility for keeping track of the relevant information and modifying it as needed. The overall program arises from the interactions of the objects in it.
Object-oriented programming, currently the dominant software design paradigm, is a way of managing the complexity of a software system as well as providing a way of modelling the real-world ‘things’ that the system is about.
An additional level of organisation imposed on software artefacts are namespaces or packages, which group logically related classes together.
Of course, now the problem becomes deciding what kinds of objects are needed and how they should interact: that’s the topic of the KIT506 unit.
3 C#, a modern programming language
3.1 What is a language? What is a programming language?
A language has syntax and semantics. The syntax defines what words and symbols are allowed and the valid ways of arranging them (into sentences, paragraphs, etc.). The semantics define what different arrangements of the symbols mean.
A programming language also has syntax and semantics. Its syntax defines valid predefined ‘words’ (see the list of C# Keywords) and rules for defining new words, identifiers, that allow the programmer to refer to new types of data (classes) or variables that hold data. Like human languages, its syntax also defines the valid ways of arranging these ‘words’, but it is much stricter than natural language.
The semantics of a programming language define what the statements do, such as changing data in memory, or interacting with the outside world through a display device or network connection.
3.2 Syntactic and Semantic Errors
Computers are not intelligent; a program will only run if it follows exactly the rules of the language (syntax). A program will always do what we tell it to do, not what we intended it to do (semantics).
A program that is syntactically correct is not necessarily logically (semantically) correct.
Three types of errors:
Problems with syntax (compiler errors)
No executable program produced
Problems during program execution (run-time errors)
e.g. divide by zero, wrong sort of input
program terminates abnormally
Problem with semantics (logical errors)
program runs, but produces incorrect results or behaviour
3.3 A simplified software development life cycle: build-and-fix
Edit the source code in your text editor of choice.
Compile program.
If there are syntax errors then goto 1.
Execute program and evaluate results.
If there are run time errors (it ‘crashes’) or semantic errors (wrong behaviour) goto 1.
Note: This is obviously only good enough while learning to program or while implementing a small part of a program.
3.4 Some elements of the C# language
Identifiers: names for variables and classes (new data types) defined by programmers
Rules: letters, numbers or underscore (_) only; cannot start with a number
Conventions: start with a lower case letter (a–z) if a variable, upper case letter (A-Z) if a class name or method (i.e., function) name. In both cases camel case is used: since identifiers cannot contain spaces, if the identifier is made up of multiple words then each word begins with a capital letter.
For example, employeeSalary could be the name for an employee’s salary in dollars and cents, while Employee could be the name for class that defines common characteristics of employees as modelled by an application, and ProcessPayRun could be the be the name of a method that determines what all employees will be paid this week.
Comments: provide inline documentation for a program but do not affect its behaviour
//single line comment, up to end of the line
/* bounded comment, can span lines, terminated by a matching closing sequence like */
Whitespace (space, tab, blank lines): Helps readability, but does not affect the program’s behaviour
Statements: program instructions terminated by a semicolon (;)
Blocks: wrap one or more statements; define scope (covered later)
{ }
3.5 A simple C# program
See https://msdn.microsoft.com/en-us/library/k1sx6ed2.aspx for an example of the first program most people try in a new programming language (or their first programming language). It is reproduced here, with no commentary on how it was created in Visual Studio, the development environment typically used for C#.
using System;
namespace HelloWorld
{
class Hello
{
static void Main()
{
Console.WriteLine(“Hello World!”);
// Keep the console window open in debug mode.
Console.WriteLine(“Press any key to exit.”);
Console.ReadKey();
}
}
}
This shows the basic structure of a simple C# program. C# uses namespaces to group related pieces of code and to separate them from other parts of the application or system. This is because the number of names can grow very large: namespaces mean that only some names are visible within a single source file.
Every program exists within a class definition. A class is most frequently used as the pattern upon which objects of that class are based, a topic which this unit will come to in a few weeks and so is not dealt with in much detail in this introduction. In this example, the class is not a pattern for objects, but just a necessary part of the structure of the C# program.
Every executable program has a method called Main(), which is the entry point for a program. The code inside Main() is executed from top to bottom and then the program ends.
The Console class is part of the standard library of classes available to C# programs. It is defined in the System namespace. To use it, one can either refer to it using its fully-qualified name, System.Console, or by indicating that the program uses the System namespace, which makes everything within that namespace directly accessible. This is the purpose of the using System; statement at the top.
4 Declaring and working with value data types
4.1 Programs model something real
In a program we use data to model real-world things. Objects in the real world can be described by numbers, letters, text, and statements that are true or false. These different kinds of data have different types.
A data type determines what values can be represented (numbers, integers, truth statements [Boolean values], text, etc.) and what operators can be used to change it. For example, numbers support arithmetic operators, strings (of text) can be joined together or split apart, truth values can be combined and tested.
4.2 Statements and Expressions
A statement is a single instruction to the computer, e.g.:
Console.WriteLine(“Hello”);
Console.ReadKey();
An expression is anything that can be evaluated to produce a single value
1 + 1 evaluates to the integer 2
“Hello” evaluates to the String Hello
2 evaluates to the integer 2 (obvious though that is)
4.3 C# value types we can use to model the real world
C# (and other languages like Java) distinguish between basic or value types and more complex reference types, so called because a variable of a reference type refers to that complex structure residing in a different location in memory. All reference types are, ultimately, built up from combinations of the value types.
There are many value data types in C#, four of which you’ll use frequently:
int represents an integer
double represents a high-precision floating point (real/decimal) number
char represents a single character
bool represents a Boolean (i.e., logical true or false) value
The value of a ‘value’ type is stored directly in the variable. We’ll see later how objects are stored in memory differently.
4.3.1 Value literals
Value literals are expressions that literally represent a single value:
int literals are represented by digits with no decimal point, such as 1 or 1024
double literals are represented by digits that include a decimal point, such as 1., 1.0 or 1.5
char literal values are represented by a character in single quotes, such as ‘a’, ‘Z’ or ‘1’ (which is the character that looks like the digit 1, but is not the value 1).
Some special characters, like newline and tab have escape sequences: ‘\n’ and ‘\t’ each represent one character.
bool literals are true and false (all lower case with no quote marks)
4.4 Strings (text)
The string type, which represents a string of characters, is not a value type but a reference type, because strings are objects. But they are used so frequently that they also have a literal representation: “text within double quotes represents a String object”.
4.5 Variable declaration
Remember: a variable is a name that refers to a location in memory
A variable must be declared before use by specifying the variable’s name (identifier) and the type of information that will be held in it
Syntax:
type identifier ;
e.g.: int age;
or with initialisation
type identifier = expression ;
e.g.: int height = 175;
4.5.1 Rules and guidelines for identifiers
The name of a variable is
Called an identifier
Chosen by the programmer (you)
Syntax: can contain only letters, digits, underscore (_) or dollar sign ($), but cannot begin with a digit.
So no spaces are allowed
4.5.2 Scope
Scope is the set of locations in a program where an identifier is visible.
In general, a variable is visible within its enclosing block (pair of braces {}) and below/after its declaration.
4.6 Variable assignment
Assignment changes the value of a variable by assigning it the value of an expression.
Syntax:
identifier = expression ;
e.g.: myAge = 18;
The type of the expression and type of the variable must be compatible. That is, they must either be the same or the variable type must be a superset of the expression. For instance, you can assign an int value to a double because the set of real numbers includes all integers.
4.7 Constants
A constant is a named value (i.e., a variable) whose value is assigned when it is declared and which cannot be changed during program execution.
Syntax: const type Identifer = expression ;
Naming convention is to write the identifier in camel case
Examples:
const double WorkHousePerDay = 7.6;
const bool DebugMode = true;
Advantages:
Gives names to otherwise unclear literal values, so makes code more readable
Facilitates simple changes to the code; the value may be used in many places but only needs to be changed in one
Prevents inadvertent errors from mistyping a literal value in some places or forgetting to update it in all places
Note: There is also a readonly modifier that is similar to const, but it is only used when defining your own classes, which will be covered properly later in the unit.
4.8 Arithmetic Expressions
An expression is a combination of operators and operands.
Arithmetic expressions compute numeric results and make use of the arithmetic operators:
Addition + (e.g., 13 + 4 is 17)
Subtraction – (e.g., 13 – 4 is 9)
Multiplication * (e.g., 13 * 4 is 52)
Division / (e.g., 13 / 4 is 3)
Remainder (modulo) % (e.g., 13 % 4 is 1)
4.8.1 Integer division and numerical type conversion
If either or both operands to an arithmetic operator are floating-point (double), the result is a floating-point (double).
If both operands to division (/) have type int then the operation is integer division and the result is also an int. So, 3 / 4 evaluates to 0, but 3.0 / 4 evaluates to 0.75.
4.8.2 Operator Precedence
Operators can be combined into complex expressions. Precedence determines the order in which they are evaluated. Precedence is:
Parentheses ()
Multiplication, division, and remainder
Addition, subtraction
(operators with the same precedence are evaluated from left to right)
4.9 Type conversion and strings
Every value type has a corresponding string representation, e.g.:
int 1 is represented by the string “1”
double 1.0 is represented by the string “1.0”
char ‘a’ is represented by the string “a”
bool true is represented by the string “True”
An expression mixing value type data and strings will convert the value type data to its corresponding string. For example, “Adam ” + 12 results in “Adam 12”.
5 Creating and interacting with objects
5.1 Why objects?
Value types allow us to model simple things: numbers, characters and Boolean values. As soon as a problem becomes more complex they don’t provide enough power to solve it.
Objects allow us to:
model complex real-world (and imaginary) things that are described by many pieces of data; and
organise the code that will manipulate and process that data
5.2 What is an object?
An object (in programming) has:
Identity: it’s not just a value.
State: It can contain many variables (both value and reference types [other objects]). Their value at any given time represents the object’s state. These are referred to as its attributes or members.
Behaviour: an object’s methods provide ways to modify its state or have it perform some other action. Calling a method is sometimes referred to as ‘sending a message’ to the object.
A formal definition:
An object is a collection of services that we can tell it to perform for us
The services are defined by methods in a class that defines the object
The services may change the state of the object
The state of an object is recorded in instance variables
5.3 Classes
A class is a ‘blueprint’ (pattern) for an object
It is the model or pattern from which objects are created. For instance, the string class is used to define string objects
Can have many objects of the same class
Will each have a different identity
Will each have the same behaviours
Will probably each have different states
5.4 Creating objects
A variable either holds a value type, or it holds a reference to, i.e. the memory address of, an object
An object reference is defined with the same pattern as a value type variable:
ClassName identifier ;
a fictitious example: Book myBook;
The actual object is created (instantiated) with the new keyword:
myBook = new Book(“The Princess Bride”);
C# provides other ways of initialising objects, which we’ll look at later in the unit.
The new keyword is followed by a special method, called a constructor, that has the same name as the object’s class. Because a constructor is a method, it may accept additional information (see Methods below).
5.5 Namespaces
The many classes of objects are organised into namespaces (which may be nested). Each namespace name begins with an upper case letter, by convention, and a dot . is used to separate higher level namespaces from their nested namespaces.
So the compiler knows which class, in which namespace, you wish to use you must either:
use its fully-qualified name, including its namespace, as in System.Console (because the Console class is in the System namespace); or
indicate at the top of your code that it is using the classes defined in a particular namespace, e.g., using System;
5.6 Calling methods
Syntax
objectName . MethodName (arguments);
Arguments
information passed to the method that it needs to complete its task
known as parameters in the method definition; arguments are the actual values passed when the method is called
Different methods accept zero or more arguments (it depends on what the method needs to do its work).
Some methods return a value (much like a mathematical function). If your program needs this value, it must be assigned to a variable (otherwise it will be forgotten), as in:
int positionOfA = someString.IndexOf(‘a’);
5.7 Properties
Object properties are a convenient way of reading and modifying the data stored in an object. Behind the scenes there are special get and set methods called to read or modify the value, but what you write in your code looks like you are accessing a plain old variable directly. For example,
int origLength = someString.Length; //reads the length of someString
5.7.1 Discovering what a method needs as input & what it returns
The method header is the first line of its declaration and indicates:
the level of access (how visible the method outside of the class where it is declared); the methods you will interact with are all public (can be seen and used from outside an object);
the return type, if any
void indicates that the method does not return a value
the name of a value type or reference type indicates that the method returns a value of that type
Form of a method header:
access return_type MethodName (parameter list)
as in
public int IndexOf(char c)
and where a parameter list is an ordered list types and identifiers, as in this different example:
int height, int depth, double density
When calling a method it is only essential to pass data of the correct type for each position.
5.7.1.1 Named arguments
C# also allows arguments to be passed using the parameter’s name, so the order can be changed, or the code’s meaning made more explicit by having the values labelled in the call. This gives the author of the calling code more flexibility, but also adds complexity for the beginner programmer. If you want, read this article on the topic.
6 Making decisions in your code
The default order of statement execution through a method is sequential: each statement one after the other in the order they are written.
Programming statements (constructs) can modify that order, to:
decide whether or not to execute a particular statement; or
perform a statement over and over repeatedly
The order of statement execution is called the flow of control.
6.1 Conditional statements
A conditional statement lets us choose which statement (or block of statements) will be executed next. They’re also called selection or branching statements, and give us the power to make basic decisions.
C#’s conditional statements:
if Do some action only if some condition is true
if-else Do one action if the condition is true, do a different action if the condition is false
switch Choose an action based on matching a value (each alternative is “labelled” by a different value)
6.2 Making Decisions
Decisions are made based on the value of Boolean expressions (i.e., expressions that can be evaluated to true or false). At the lowest level, almost every Boolean value is the result of comparing one thing with another, so it’s worth a quick diversion to see how that works. Or you can skip to the details of if, else and switch statements.
6.2.1 Comparison Operators
Equality operators Meaning Example
== equal to 7 == 5 is false
!= not equal to 7 != 5 is true
Relational operators Meaning Example
< less than 7 < 5 is false
> greater than 7 > 5 is true
<= less than or equal to 7 <= 7 is true
>= greater than or equal to 7 >= 5 is true
6.2.2 Comparing value types
Comparing int values is easy: all the equality and relational operators work exactly as defined.
char values are compared based on a character’s position in the Unicode table of characters, so
‘a’ < 'z' is true, but
'A' < 'a' is true, because the capital letters come before lower case ones in the table, and so 'Z' < 'a' is also true
double values are not stored precisely, so == will not always work as expected; two values that look the same to us may not look exactly the same to the computer.
Rather than ==, check if the difference is ‘sufficiently small’
e.g., Math.Abs(d1 – d2) < 0.00001 (where 0.00001 is the degree of difference you are willing to accept given the application area of your program)
6.2.3 Comparing objects: Equals() and CompareTo()
The comparison operators really only work on value types: integers, characters, floating-point numbers and…
…object references (because behind the scenes these are integer-valued memory addresses). Why should we care? Because we usually want to know if two values are equivalent, not necessarily the same object in memory.
6.2.3.1 The Equals() method
All objects have the method bool Equals(object o) that can be used to test if two objects represent the same value (i.e., all their internal data has the same value). Given two object variables called one and another:
Console.WriteLine( one.Equals(another) ); //prints True
But: in some classes, Equals() is no better than == (the default implementation is very simple) so check the documentation for a class before assuming it will work.
6.2.3.2 The CompareTo() method
Many classes, like strings, have the method int CompareTo(string o). This returns:
a value less than zero if the first string belongs before the second (based on a character-by-character comparison);
a value greater than zero if the first string belongs after the second; or
0 (zero) if they are identical.
Note that comparisons are case-sensitive. Performing other kinds of comparison is beyond the scope of this introduction.
6.2.3.3 Comparing strings for equality (and inequality)
Although they are reference types, strings in C# may be compared for equality using == and inequality using !=. Behind the scenes these operators use the Equals() method.
6.3 Boolean Operators
Individual comparisons are useful, but what if we need to know that two or more things are all true, or we’re satisfied if any of a number of comparisons is true? Boolean operators combine individual boolean expressions.
Operator English name C# symbol Meaning (Highly artificial) examples
And && Requires that both operands are true true && true is true
true && false is false
Or || Requires that either operand is true true || false is true
false || false is false
Not ! Negates (flips) the operand !true is false
!false is true
6.4 Full operator precedence list
From highest to lowest…
! negate
* / % multiply, divide, remainder (modulo)
+ - add, subtract
== != is equal to, is not equal to
< <= > >= less than, less than or equal to, greater than, greater than or equal to
&& logical and
|| logical or
Parentheses () can always be used to override the default precedence or to make clear what is intended.
6.5 if, if with else, and switch
6.5.1 if
Selects whether or not to execute a block of statements.
if ( boolean expression )
{
statement(s)
}
A real-life example: You’re in a car and would like the window open. Do you wind down the window? Only if it is not already open.
6.5.2 if-else
Selects between two alternative blocks of statements.
if ( boolean expression )
{
statement(s)
}
else
{
statement(s)
}
A real-life example: You need to get to work and you can drive or walk, depending on the weather. If it’s raining you decide to take the car, otherwise (else) you walk.
6.5.3 Nesting ifs (an example)
The statements inside an if or else block can be anything, including more ifs. If the logic of your program is complicated, it may be simpler to break it down by nesting decisions. For example, given three numbers n1, n2 and n3, which is the smallest?
//Assume n1, n2 and n3 already declared and assigned
if (n1 < n2)
{
if (n1 < n3)
{
//n1 is smallest
}
else
{
//n3 is smallest
}
}
else
{
if (n2 < n3)
{
//n2 is smallest
}
else
{
//n3 is smallest
}
}
6.5.4 Sequences of ifs
Sometimes, rather than doing one thing or another thing, there may be multiple alternative paths, based on a series of tests. The structure of an if statement for this is:
if ( boolean expression 1 )
{
statement(s)
}
else if ( boolean expression 2 )
{
statement(s)
}
else if ( boolean expression 3 )
{
statement(s)
}
else
{
statement(s)
}
6.5.4.1 Example
Each subsequent if is only checked if all preceding ones were false. An example, assigning a grade label based on a score between 0 and 100.
int score; //assigned some value before...
string grade;
if (score >= 80)
{
grade = “HD”;
}
else if (score >= 70)
{
grade = “DN”;
}
else if (score >= 60)
{
grade = “CR”;
}
else if (score >= 50)
{
grade = “PP”;
}
else
{
grade = “NN”;
}
6.5.5 Guidelines for nesting or having a sequence of ifs
Decide on the ‘set up’ before the branch
what variables are needed to inform the decision?
where will there values come from?
Work out the logic: what decisions need to be made and in what order?
Then, when finally implementing (coding) the solution:
Use incremental development
start with the outermost if
always use blocks around the statements controlled by the if
test at each step (does the algorithm correctly distinguish between each alternative?)
Use comments to keep track of what is happening or known at various points in the code
6.5.6 switch
Selects between many alternative sequences of statements by comparing a given value with the value for each case.
switch ( expression )
{
case value 1 : statement(s)
break;
case value 2 : statement(s)
break;
.
.
.
case value n : statement(s)
break;
default: statement(s)
break;
}
The break jumps to the end of the switch block, and is required to mark the end of each case. The final branch, if included, can be labelled default and is executed if none of the other values matched the expression.
The expression can be represent an integer value, character value, enum value or string. The switch statement is very versatile.
6.5.7 enumerated types
Some constants naturally form groups (e.g., days of the week). In these cases the identity of each constant matters more than its value. For example, to represent days of the week we could define a number of constants, as in
const int Sunday = 0;
const int Monday = 1;
…
const int Saturday = 6;
but we probably don’t care about the values assigned, only whether some variable represents Sunday or Monday, or Tuesday, etc. To define an enumerated type to represent days:
enum Day { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
To refer to one of these values we can use Day.Sunday. To declare a variable of an enum type we do the same as for other types:
Day dayOfWeek;
Enum type variables can be used in switch statements, as in:
//Assign the correct name to dayName given Day enum defined earlier
Day today = Day.Friday; //would be set elsewhere in a real program
string dayName;
switch (dayName)
{
case Day.Sunday: dayName = “Sunday”;
break;
case Day.Monday: dayName = “Monday”;
break;
case Day.Tuesday: dayName = “Tuesday”;
break;
case Day.Wednesday: dayName = “Wednesday”;
break;
case Day.Thursday: dayName = “Thursday”;
break;
case Day.Friday: dayName = “Friday”;
break;
default: dayName = “Saturday”;
break;
}
7 Repeating actions with loops
7.1 Repetition statements
Repetition statements (like conditional statements) change the flow of execution by allowing us to repeat a set of statements multiple times. They are often just called loops.
Whether or not the statements are executed (or executed again) is controlled by a boolean expression (just like a conditional statement uses a boolean expression to determine whether or not to execute a block of statements at all).
7.2 Pre- and post-tested loops
Loops can be pre-tested or post-tested:
Pre-tested: The boolean expression is evaluated at the beginning, so the loop body may never be executed. This kind of loop will repeat zero or more times.
Post-tested: The boolean expression is evaluated at the end of the loop. This look will be executed one or more times.
7.3 Loop Components (IBUT)
All loops have four components:
Initialisation:
Preparing for the first step of repetition
May declare additional variables to control loop
Body:
The work done inside the loop
Same kind of action every time, but applied to different data or in a different state (of variable values)
Update:
Something must change as a result of the loop (a counter, position in a list, etc.)
Test:
Should we continue to repeat, or even start?
The update affects the test
7.4 Loop Constructs in C#
7.4.1 while
Executes some statements while something is true.
Pre-tested
Syntax:
while ( boolean expression )
{
statement(s)
}
Initialisation must be done outside the loop (before the while)
Update must be done inside the loop
7.4.1.1 Real-life example: cleaning the dishes
Initialisation: Walk to the sink
Test: Are there any dirty dishes left? Washing dishes is a pre-tested loop because there may not be any dishes to wash
Body: Take next dish and wash it (this is also the Update because it affects the thing we test)
7.4.2 do-while
Executes some statements at least once and then continues to repeats them while something is true.
Post-tested
Syntax:
do
{
statement(s)
} while ( boolean expression );
Initialisation must be done outside the loop (before the do)
Update must be done inside the loop
7.4.2.1 Real-life (and computer) example: guess a number
In this game the player must always make at least one guess.
Initialisation: Game selects a secret number
Body: Ask player for their next guess.
Give them some feedback if it’s wrong (“higher”, “lower”). This is also the Update because…
Test: Is their guess incorrect? If it is then repeat the body of the loop.
7.4.3 for
Useful for executing some statements a fixed number of times.
Pre-tested
Syntax:
for ( initialisation ; boolean expression ; increment )
{
statement(s)
}
Initialisation done inside the for statement.
Can only be an assignment or declaration and assignment (e.g., int i = 0)
The Update is done in increment (e.g., i = i + 1)
for loops are used most commonly to perform actions a fixed number of times. For instance, to repeat some statements 10 times, we would write:
for (int i = 0; i < 10; i = i + 1) { /* statements to execute */ } 7.4.3.1 Real-life example: lifting weights The task is to lift a weight 15 times. Initialisation: Set counter to 0 Test: Is counter still less than 15? Body: Lift weight once Update: Increment counter 7.4.4 foreach There is also a foreach statement, but it requires knowledge of collection data types, which are covered later. 8 Writing basic methods See the Defining and Calling Methods video in C# Fundamentals for Absolute Beginners for a gentle introduction to defining methods, or named blocks of code. This introduction document won’t go into any more detail on methods since this will be learned through both the modelling and later implementation parts of the unit. 9 Arrays: the first data structure An array is a fixed-length, ordered (and so, indexed) list of data of one type. Each element of an array is located at a position between 0 (zero) and the length of the array minus 1, just like the characters of a string are indexed from 0. Below is a diagrammatic representation of an array of 10 ints. Index 0 1 2 3 4 5 6 7 8 9 Value 23 6 90 19 27 1 0 59 2 5 There are other ways of storing collections of data, but we’ll look at them later in the unit. 9.1 Syntax for declaring an array An array variable is declared by appending square brackets [] to the name of the data type you want it to hold: int[] ages; declares a reference to an array of ints, called ages string[] names; declares a reference to an array of strings, called names double[] heights; declares a reference to an array of doubles, called heights 9.2 Allocating space for an array Arrays are a special kind of object, so merely declaring an array variable doesn’t allocate any space for the array. Space is allocated using the new keyword, using the following syntax: new type[size]; So, given the declarations above, we can allocate space for 10 ints and 20 Strings with: ages = new int[10]; names = new string[20]; The initial value of each element is set to a default when the array is created, according to the following table General type Example(s) Default value numerical values, including characters int, double, char 0 (or 0.0) boolean bool false objects string null 9.3 Accessing a single value in an array Array elements are like any other individual variables. To use or modify a particular value in an array, use its index in square brackets after the array variable’s name, as in: ages[2] refers to the value at the third position in the ages array, so ages[2] = 50; writes the value 50 to that position; and int aValue = ages[2]; reads the value at position 2 and assigns it to the variable aValue names[0] refers to the first value in the names array, so names[0] = "Fred" assigns the value "Fred" to the first position in the array names; and string someName = names[0]; assigns the value in the first position in names to someName The index can be any integer expression, so integer literals like 0 and 2 are allowed, as are expressions like 10/2 and i or i/2(assuming i was declared as an int at some point before). 9.3.1 Discovering the length of an array later Every array has a Length property that holds the value of its length. This means we can discover an array’s length after space for it has been allocated elsewhere in the program. ages.Length is 10 (given how space was allocated above) names.Length is 20 Trying to access an element at an index below 0 or the array’s length and above results in a runtime error that will generally halt your program. 9.4 Arrays and objects are references 9.4.1 Passing arrays to methods Array variables are like objects in that they are references to the actual array in memory. This means that when they are passed to a method as an argument the reference is copied into the parameter that the method will use internally. And that means that the method has direct access to the data in the array. The practical upshot of this is that any changes to the elements of an array made by a method persist after the method has finished. 9.4.2 Arrays of objects As described above, when space for an array is allocated the elements are set to a default value based on their type. Reference types are set to null, meaning they refer to nothing at all. So, string[] words = new string[10]; allocates space for 10 string references, but doesn’t create them. The elements only become non-null when values are assigned, as in words[0] = "alpha"; words[1] = "beta"; At this point the array is similar to this picture (only ‘similar’ because the values in positions 0 and 1 are actually references to the strings “alpha” and “beta”): Index 0 1 2 3 4 5 6 7 8 9 Value “alpha” “beta” null null null null null null null null 9.5 Multi-dimensional arrays Arrays can be multi-dimensional, similar to mathematical matrices or tables. Two-dimensional arrays are quite common and are declared with type[,] identifier; and allocated with new type[rows,columns]; For instance, if we wanted to represent the number of different species of animals observed in different adjacent regions on a map, divided into 10 rows and 15 columns, we could declare and allocate the array with int[,] speciesCounts = new int[10,15]; To refer to the value at a particular position, simply refer to it by its row and column, so the species count at row 1, column 4 would be speciesCounts[1,4]. Note: C# also supports ragged (pronounced ‘raggid’) arrays, which are actually arrays of arrays and so each ‘row’ may not have the same number of ‘columns’. A two-dimensional ragged array of integers is declared as int[][]. It is unlikely you will need to deal with these in this unit. 10 A final word There are many more specific details about the C# language that you will pick up as you start creating applications in it (and topics such as declaring your own classes were not covered at all by this introduction). Let me know if there’s anything you want more detail on or if you find any errors or parts that were overly confusing.