This lesson introduces C# operators, types, and
variables. Its goal is to meet the following objectives:
- Understand what a variable is.
- Familiarization with C# built-in types.
- Get an introduction to C# operators.
- Learn how to use Arrays.
Variables and Types
"Variables" are simply storage locations for data. You can place
data into them and retrieve their contents as part of a C# expression.
The interpretation of the data in a variable is controlled through
"Types".
C# is a strongly "Typed" language. Thus all operations on variables
are performed with consideration of what the variable's "Type" is.
There are rules that define what operations are legal in order to
maintain the integrity of the data you put in a variable.
The C# simple types consist of the Boolean type and three numeric
types - Integrals, Floating Point, Decimal and String. The term
"Integrals" refers to the classification of types that include sbyte,
byte, short, ushort, int, uint, long, ulong, and char. More details
are available in the Integral Types section later in this lesson. The
term "Floating Point" refers to the float and double types, which are
discussed, along with the decimal type, in more detail in the Floating
Point and Decimal Types section later in this lesson. The string type
represents a string of characters and is discussed in The String Type
section, later in this lesson. The next section introduces the boolean
type.
The Boolean Type
Boolean types are declared using the keyword, bool. They
have two values: true or false. In other languages,
such as C and C++, boolean conditions can be satisfied where 0 means
false and anything else means true. However, in C# the only values
that satisfy a boolean condition is true and false,
which are official keywords. Listing 2-1 shows one of many ways that
boolean types can be used in a program.
Listing 2-1. Displaying Boolean Values: Boolean.cs
- using
System;
class Booleans
{
public
static
void
Main()
{
bool
content = true;
bool
noContent = false;
Console.WriteLine("It is {0} that C# Station provides C#
programming language content.", content);
Console.WriteLine("The statement above is not {0}.",
noContent);
}
}
Get Setup Instructions For How to Run this Program
In Listing 2-1, the boolean values are written to the console as a
part of a sentence. The only legal values for the bool type
are either true or false, as shown by the assignment
of true to content and false to
noContent. When run, this program produces the following output:
It is True that C# Station provides C# programming language content.
The statement above is not False.
Integral Types
In C#, an integral is a category of types. They are whole numbers,
either signed or unsigned, and the char type. The char type is a
Unicode character, as defined by the Unicode Standard. For more
information, visit
The Unicode Home Page. Table 2-1 shows the integral types, their
size, and range.
Table 2-1. The Size and Range of C# Integral Types
Type |
Size (in bits) |
Range |
sbyte |
8 |
-128 to 127 |
byte |
8 |
0 to 255 |
short |
16 |
-32768 to 32767 |
ushort |
16 |
0 to 65535 |
int |
32 |
-2147483648 to 2147483647 |
uint |
32 |
0 to 4294967295 |
long |
64 |
-9223372036854775808 to 9223372036854775807 |
ulong |
64 |
0 to 18446744073709551615 |
char |
16 |
0 to 65535 |
Integral types are well suited for those operations involving whole
number calculations. The char type is the exception,
representing a single Unicode character. As you can see from the table
above, you have a wide range of options to choose from, depending on
your requirements.
Floating Point and Decimal Types
A C# floating point type is either a float or double. They are used
any time you need to represent a real number, as defined by IEEE 754.
For more information on IEEE 754, visit the
IEEE Web Site. Decimal types should be used when representing
financial or money values. Table 2-2 shows the floating point and
decimal types, their size, precision, and range.
Table 2-2. The Floating Point and Decimal Types with Size,
Precision, and Range
Type |
Size (in bits) |
Precision |
Range |
float |
32 |
7 digits |
1.5 x 10-45 to 3.4 x 1038 |
double |
64 |
15-16 digits |
5.0 x 10-324 to 1.7 x 10308 |
decimal |
128 |
28-29 decimal places |
1.0 x 10-28 to 7.9 x 1028 |
Floating point types are used when you need to perform operations
requiring fractional representations. However, for financial
calculations, the decimal type is the best choice because you
can avoid rounding errors.
The string Type
A string is a string of text characters. You typically create a
string with a string literal, enclosed in quotes: "This is an example
of a string." You've seen strings being used since Lesson 1, where we
used the Console.WriteLine method to send output to the
console.
Some characters aren't printable, but you still need to use them in
strings. Therefore, C# has a special syntax where characters can be
escaped to represent non-printable characters. For example, it is
common to use newlines in text, which is represented by the '\n' char.
The backslash, '\', represents the escape. When preceded by the escape
character, the 'n' is no longer interpreted as an alphabetical
character, but now represents a newline.
You may be now wondering how you could represent a backslash
character in your code. We have to escape that too by typing two
backslashes, as in '\\'. Table 2-3 shows a list of common escape
sequences.
Table 2-3. C# Character Escape Sequences
Escape Sequence |
Meaning |
\' |
Single Quote |
\" |
Double Quote |
\\ |
Backslash |
\0 |
Null, not the same as the C# null value |
\a |
Bell |
\b |
Backspace |
\f |
Form Feed |
\n |
Newline |
\r |
Carriage Return |
\t |
Horizontal Tab |
\v |
Vertical Tab |
Another useful feature of C# strings is the verbatim literal, which
is a string with a @ symbol prefix, as in @"Some string".
Verbatim literals make escape sequences translate as normal characters
to enhance readability. To appreciate the value of verbatim literals,
consider a path statement such as
"c:\\topdir\\subdir\\subdir\\myapp.exe". As you can see, the
backslashes are escaped, causing the string to be less readable. You
can improve the string with a verbatim literal, like this:
@"c:\topdir\subdir\subdir\myapp.exe".
That is fine, but now you have the problem where quoting text is
not as easy. In that case, you would specify double double quotes. For
example, the string "copy \"c:\\source file name with spaces.txt\"
c:\\newfilename.txt" would be written as the verbatim literal
@"copy ""c:\source file name with spaces.txt"" c:\newfilename.txt".
C# Operators
Results are computed by building expressions. These expressions
are built by combining variables and operators together into
statements. The following table describes the allowable operators,
their precedence, and associativity.
Table 2-4. Operators with their Precedence and Associativity
Category (by precedence) |
Operator(s) |
Associativity |
Primary |
(x) x.y f(x) a[x] x++ x-- new typeof
sizeof checked unchecked |
left |
Unary |
+ - ! ~ ++x --x (T)x |
left |
Multiplicative |
* / % |
left |
Additive |
+ - |
left |
Shift |
<< >> |
left |
Relational |
< > <= >= is |
left |
Equality |
== != |
right |
Logical AND |
& |
left |
Logical XOR |
^ |
left |
Logical OR |
| |
left |
Conditional AND |
&& |
left |
Conditional OR |
|| |
left |
Conditional> |
?: |
right |
Assignment |
= *= /= %= += -= <<= >>= &= ^= |= |
right |
Left associativity means that operations are evaluated from left to
right. Right associativity mean all operations occur from right to
left, such as assignment operators where everything to the right is
evaluated before the result is placed into the variable on the left.
Most operators are either unary or binary. Unary operators form
expressions on a single variable, but binary operators form
expressions with two variables. Listing 2-2 demonstrates how unary
operators are used.
Listing 2-2. Unary Operators: Unary.cs
- using
System;
class
Unary
{
public
static
void
Main()
{
int
unary = 0;
int
preIncrement;
int
preDecrement;
int
postIncrement;
int
postDecrement;
int
positive;
int
negative;
sbyte
bitNot;
bool
logNot;
preIncrement = ++unary;
Console.WriteLine("Pre-Increment: {0}", preIncrement);
preDecrement = --unary;
Console.WriteLine("Pre-Decrement: {0}", preDecrement);
postDecrement = unary--;
Console.WriteLine("Post-Decrement: {0}", postDecrement);
postIncrement = unary++;
Console.WriteLine("Post-Increment: {0}", postIncrement);
Console.WriteLine("Final Value of Unary: {0}", unary);
positive = -postIncrement;
Console.WriteLine("Positive: {0}", positive);
negative = +postIncrement;
Console.WriteLine("Negative: {0}", negative);
bitNot = 0;
bitNot = (sbyte)(~bitNot);
Console.WriteLine("Bitwise Not: {0}", bitNot);
logNot = false;
logNot = !logNot;
Console.WriteLine("Logical Not: {0}", logNot);
}
}
Get Setup Instructions For How to Run this Program
When evaluating expressions, post-increment (x++) and
post-decrement (x--) operators return their current value and then
apply the operators. However, when using pre-increment (++x) and
pre-decrement (--x) operators, the operator is applied to the variable
prior to returning the final value.
In Listing 2-2, the unary variable is initialized to zero.
When the pre-increment (++x) operator is used, unary is
incremented to 1 and the value 1 is assigned to the preIncrement
variable. The pre-decrement (--x) operator turns unary back
to a 0 and then assigns the value to the preDecrement
variable.
When the post-decrement (x--) operator is used, the value of
unary, 0, is placed into the postDecrement variable and
then unary is decremented to -1. Next the post-increment
(x++) operator moves the current value of unary, -1, to the
postIncrement variable and then increments unary to
0.
The variable bitNot is initialized to zero and the bitwise
not (~) operator is applied. The bitwise not (~) operator flips the
bits in the variable. In this case, the binary representation of 0,
"00000000", was transformed into -1, "11111111".
Notice the expression (sbyte)(~bitNot). Any operation
performed on types sbyte, byte, short, or
ushort return int values. To assign the result into
the bitNot variable we had to use a cast (Type) operator,
where Type is the type you wish to convert to (in this case -
sbyte). The cast operator is shown as the Unary operator "(T)x"
in Table 2-4. Cast operators must be performed explicity when you go
from a larger type to a smaller type because of the potential for lost
data. Generally speaking, assigning a smaller type to a larger type is
no problem, since the larger type has room to hold the entire value.
Also be aware of the dangers of casting between signed and unsigned
types. You want to be sure to preserve the integrity of your data.
Many basic programming texts contain good descriptions of bit
representations of variables and the dangers of explicit casting.
The logical not (!) operator allows you to toggle the value of a
boolean variable. In the example, the logNot variable is
changed from false to true. You can expect the
following output from the above program.
Pre-Increment: 1
Pre-Decrement 0
Post-Decrement: 0
Post-Increment: -1
Final Value of Unary: 0
Positive: 1
Negative: -1
Bitwise Not: -1
Logical Not: True
In addition to unary operators, C# has binary operators that form
expressions of two variables. Listing 2-3 shows how to use the binary
operators.
Listing 2-3. Binary Operators: Binary.cs
- using
System;
class
Binary
{
public
static
void
Main()
{
int x,
y, result;
float
floatResult;
x = 7;
y = 5;
result = x+y;
Console.WriteLine("x+y: {0}", result);
result = x-y;
Console.WriteLine("x-y: {0}", result);
result = x*y;
Console.WriteLine("x*y: {0}", result);
result = x/y;
Console.WriteLine("x/y: {0}", result);
floatResult = (float)x/(float)y;
Console.WriteLine("x/y: {0}", floatResult);
result = x%y;
Console.WriteLine("x%y: {0}", result);
result += x;
Console.WriteLine("result+=x: {0}", result);
}
}
And here's the output:
x+y: 12
x-y: 2
x*y: 35
x/y: 1
x/y: 1.4
x%y: 2
result+=x: 9
Get Setup Instructions For How to Run this Program
Listing 2-3 shows several examples of binary operators. As you
might expect, the results of addition (+), subtraction (-),
multiplication (*), and division (/) produce the expected mathematical
results.
The floatResult variable is a floating point type. We
explicitly cast the integer variables x and y to
calculate a floating point value.
There is also an example of the remainder(%) operator. It performs
a division operation on two values and returns the remainder.
The last statement shows another form of the assignment with
operation (+=) operator. Any time you use the assignment with
operation operator, it is the same as applying the binary operator to
both the left hand and right hand sides of the operator and putting
the results into the left hand side. The example could have been
written as result = result + x; and returned the same value.
The Array Type
Another data type is the Array, which can be thought of as a
container that has a list of storage locations for a specified type.
When declaring an Array, specify the type, name, dimensions, and size.
Listing 2-4. Array Operations: Array.cs
- using
System;
class
Array
{
public
static
void
Main()
{
int[]
myInts = { 5, 10, 15 };
bool[][]
myBools = new
bool[2][];
myBools[0] = new
bool[2];
myBools[1] = new
bool[1];
double[,]
myDoubles = new
double[2,
2];
string[]
myStrings = new
string[3];
Console.WriteLine("myInts[0]: {0}, myInts[1]: {1},
myInts[2]: {2}", myInts[0], myInts[1], myInts[2]);
myBools[0][0] = true;
myBools[0][1] = false;
myBools[1][0] = true;
Console.WriteLine("myBools[0][0]: {0}, myBools[1][0]: {1}",
myBools[0][0], myBools[1][0]);
myDoubles[0, 0] = 3.147;
myDoubles[0, 1] = 7.157;
myDoubles[1, 1] = 2.117;
myDoubles[1, 0] = 56.00138917;
Console.WriteLine("myDoubles[0, 0]: {0}, myDoubles[1, 0]:
{1}", myDoubles[0, 0], myDoubles[1, 0]);
myStrings[0] = "Joe";
myStrings[1] = "Matt";
myStrings[2] = "Robert";
Console.WriteLine("myStrings[0]: {0}, myStrings[1]: {1},
myStrings[2]: {2}", myStrings[0], myStrings[1], myStrings[2]);
}
}
And here's the output:
myInts[0]: 5, myInts[1]: 10, myInts[2]: 15
myBools[0][0]: True, myBools[1][0]: True
myDoubles[0, 0]: 3.147, myDoubles[1, 0]: 56.00138917
myStrings[0]: Joe, myStrings[1]: Matt, myStrings[2]: Robert
Get Setup Instructions For How to Run this Program
Listing 2-4 shows different implementations of Arrays. The first
example is the myInts Array. It is initialized at declaration
time with explicit values.
Next is a jagged array. It is essentially an array of arrays. We
needed to use the new operator to instantiate the size of the
primary array and then use the new operator again for each
sub-array.
The third example is a two dimensional array. Arrays can be
multi-dimensional, with each dimension separated by a comma. It must
also be instantiated with the new operator.
Finally, we have the one dimensional array of string
types.
In each case, you can see that array elements are accessed by
identifying the integer index for the item you wish to refer to.
Arrays sizes can be any int type value. Their indexes begin
at 0.
Summary
|