260 likes | 403 Views
2. Language Basics. Names Variables and types Typecasting and conversion Constants Expressions and statements Stack and heap Reference types Strings. Names.
E N D
2. Language Basics • Names • Variables and types • Typecasting and conversion • Constants • Expressions and statements • Stack and heap • Reference types • Strings
Names Identifiers (words or names) used in a program can be defined by the language, by the programming environment, or by the programmer. In the case of C#, the language is comparatively small and includes a limited number of pre-defined words. .NET, however, provides an large number of identifiers. These are not part of the language definition itself, but are part of the .NET environment, which is closely coupled with the language. C# is a case-sensitive language. This may cause confusion, since words that look the same can mean different things. When defining names, it is important to be very careful when using two names with different casing. For a discussion on why C# is case sensitive: Ask a Language Designer.
Keywords Keywords are names that defined by the language. In C#, keywords are also reserved words, that is, they cannot be redefined in your program (unless you precede them with @). For example, this code: namespace new { … } Will not compile and will cause an error because “new” is a C# keyword. Examples: if, class, new, int C# Keywords
Operators Operators are also defined by the language, and define operations that can be performed on data. In C#, they can be modified in some situations. For example, “+” usually means add two numbers, but it can be modified to mean add days to a date, join two lines, etc. Operators are usually symbols, but some keywords are also operators. Examples: +, &&, -, / C# Operators
Other Names C# also defines attributes, which are a way of inserting information (metadata) into the intermediate language code that can be retrieved at run-time. These are not necessary for routine C# programming. Example: [Serializable] Preprocessor directives are instructions put in the code to determine how the code is compiled, or how it is to be treated before it is compiled. Example: #if, #region C# Preprocessor directives
Variables and Types Types, or data types, are an important category of keyword that determines how information in memory is treated. Variables are programmer-defined (or environment-defined) names that identify and reserve a location in memory. In C#, variables always have a type which determines what the variable represents. This means that C# is typed, or type-safe. That is, it guarantees that when you access information in memory, it contains the kind of data that you expect. Some languages, like VBScript, are untyped. The specific type is inferred by the data it contains. While superficially simpler because a variable can be used without bothering to determine its type, it can be error-prone and confusing, because what a variable actually represents can be unclear.
Variables and Types Declaring a variable sets aside the memory it needs. Initializing a variable sets its starting value. In C#, all variables must be declared and initialized before they are used. In some languages, un-initialized variables contain whatever value happened to be in that location in memory before it was used, which can lead to program errors.
Variables and Types Declaring and initializing a variable: int i = 25; In this case, int is the type of variable we are declaring, “i” is a programmer-defined name, which can be any valid sequence of characters (e.g., no spaces), such as: int myVariable = 25; int this_is_my_long_variable_name = 25 The equals sign is the assignment operator, assigning the value 25 to i, or setting the memory at the location represented by i to the binary representation of the number 25. The assignment operator is very different from the mathematical equals sign.
Variables and Types Memory is organized like a sequential series of mailboxes, each of which can contain a value:
Variables and Types Variables allow us to specify what these numbers mean. int a = 25; char c = “X”; float f = 1.432; Boolean status = true;
Variables and Types C# types consists of built-in types, and programmer-defined types. Many of the built-in types are simple or scalar types (also called “primitives”), that is, types that represent a single, atomic piece of information. Examples are: bool Can be true or false. Used in logical if-then operations (more on these later) int An integer float A floating-point number char A character Complex types, or Objects, consist of multiple internal pieces of information bound to the functions that operate on them, and are often programmer-defined. (We will get much more into objects later.) C# is unusual in that all scalars can be treated as objects, and the environment provides methods to automatically convert from one representation to another (i.e. X.ToString()). Conceptually, however, it is useful to think of them as simple, scalar types. C# Types
Variables and Types An important thing to note about some simple types is that they closely correspond to mathematical concepts. However, they have one key difference: Data types specify the contents of finite locations in memory. This means, for example, that: Integers are finite. There are different kinds of integers, and each corresponds to a different maximum size: C# Integer types Floating point numbers have limited accuracy (see next slide for details). Even though floating point numbers can be very large or very small, and have a symbol for positive and negative infinity (and “not a number”), they cannot represent every possible number. To do that, they would have to be infinitely large! C# Floating-point types
Variables and Types Here is Microsoft’s description of floating point limitations. For these reasons it is usually best to use double, the larger type, or, for very precise calculations, the decimal type. “The Single and Double data types are very precise - that is, they make it possible for you to specify extremely small or large numbers. However, these data types are not very accurate because they use floating-point mathematics. Floating-point mathematics has an inherent limitation in that it uses binary digits to represent decimals. Not all the numbers within the range available to the Single or Double data type can be represented exactly in binary form, so they are rounded. Also, some numbers cannot be represented exactly with any finite number of digits - pi, for example, or the decimal resulting from 1/3. Because of these limitations to floating-point mathematics, you might encounter rounding errors when you perform operations on floating-point numbers. Compared to the size of the value you are working with, the rounding error will be very small. If you do not require absolute accuracy and can afford relatively small rounding errors, the floating-point data types are ideal for representing very small or very large values. On the other hand, if your values must be accurate - for example, if you are working with money values - you should consider one of the scaled integer data types.”
Type Conversions Types usually retain their declared value throughout the execution of a program. However, there are times when types are treated as compatible and converted automatically. For example, this code is valid because C# can automatically convert from int to double: int i = 25; double d = i; The code below is not valid, and will generate a compiler error. C# requires us to be aware that we are loosing precision in the conversion: double d = 25.0; int i = d; C# Implicit conversions
Typecasting In the previous example, we can get around this by casting the variable. This will force one type to be treated as another, but will do so in the simplest possible way. In this example, it will truncate instead of rounding, so i will equal 25: double d = 25.75; int i = (int)d; Generally, conversions that could result in a loss of data require a cast. .NET also includes methods to convert types explicitly using conversion functions. In this example, d is rounded and i is assigned the value 26: double d = 25.75; int i = Convert.ToInt32(d); Like System.Console, System.Convert is a built-in class in the .NET framework.
Constants Not all programmer-defined elements are variables. They may also be constants, that is, values that will not change. Literals are specific values in code. In this statement, for example, “Hello world” is a string literal: System.Console.WriteLine(“Hello world”); Symbolicconstants are declared with the “const” keyword, which prevent them from being changed later in the program: const double freezingPoint = 32.0;
Constants Enumerations are symbolic representations of groups of values, which you will encounter frequently in the .NET framework: enum UnitsOfMeasurement { meters = 0, kilometers = 1, feet = 2, miles = 3 } These help ensure that the correct values are used, and will, for example, show up in Intellisense listings when typing in the IDE. They are accessed using this syntax: UnitsOfMeasurement.meters
Expressions and Statements Keywords, operators and variables can be assembled into expressions and statements. Expressions evaluate to a specific value, and statements are any complete program instruction. When constructing arithmetic expressions it is important to be mindful of operator precedence. When in doubt, use parentheses to enforce the desired sequence of evaluation: 25 + 32 (height * width) / 2 (((a * b) + w) / (c * MyFunction(z))) + 1 C# Operator Precedence
Expressions and Statements Statements are complete program instructions. Examples of statements are: int height = 25; int width = 400; double myVar = (height * width) / 2; myVar += ((a * b) + w) / (c * MyFunction(z)); Note in the last line +=. Like C and C++, C# includes shortcuts like ++ (increment by 1), -- (decrement by 1) and += (add this number to itself, plus): myVar += 2; is the same as myVar = myVar + 2;
The Stack and the Heap An important thing to understand about variable storage is the difference between the program stack and the heap. Memory in the stack is of a fixed size. Each function has its own set of variables that reside in the stack storage, which are pushed on and popped off the program stack as the program moves in and out of functions. When you declare a simple variable, you are making room for it on the program stack. int myInteger = 10; int myResult = myInteger * 100; This is possible because we know the exact amount of memory each of these variables require. (These variables can also reside in registers, so simple arithmetic operations can be executed very quickly.)
The Stack and the Heap Memory in the heap must be allocated, that is, it must be requested and assigned by the operating system. This is a slower operation because it typically requires more operations than simply writing or reading a single value from a memory location. The amount allocated can be determined at run time. For example, creating a variable that holds a string, the size of which we can’t know before hand, requires an allocation from the heap: string s = Console.ReadLine(); Instead of storing the entire string on the stack, a reference to the string is stored on the stack, and the string itself is stored on the heap.
The Stack and the Heap int a = 25; char c = ‘X’; float f = 1.432; Boolean status = true; string s = Console.ReadLine(); If you were to type in “a string”, room for those characters would be allocated in the heap. This is because, in C#, strings are reference types. That is, they consist of a reference to a storage location rather than the data itself.
Reference Types In earlier languages such as C, pointers were used to access memory locations directly. (A pointer is very similar to a reference, in that it refers to a location in memory, but references are typed, and there are restrictions in their use.) This was efficient but error prone. In other languages, memory allocated on the heap often has to be explicitly freed. Programs that neglect to free memory have memory “leaks” and often run out of memory. In C#, allocated memory does not need to be freed explicitly. The .NET system takes care of this by a process called garbage collection. The Java virtual machine has a similar feature. In the .NET environment, the exact character and contents of references are not available to the programmer, and not used directly. It is likely they are some form of pointer to a pointer, a structure which allows the operating system to move objects around in memory as needed without invalidating the original reference.
Reference Types Reference types are the basis for user-defined types in C#. Objects are all reference types allocated on the heap. This allocation typically requires the keyword new. For example: MyObject ObjectName = new MyObject(); When building a windows application, you can see the generated code creating objects (forms, labels, etc.) using this syntax.
Strings Strings are a special reference type provided by C# and the .NET framework. Traditionally strings were encoded as ASCII characters. This is a 7-bit encoding, and is limited to only 128 characters (0 to 127). This made it suitable for English, and additional characters in the 8 bit range (up to 255) made it possible to add extra characters from some European languages. ASCII Table Unicode solves this problem by adoption a 16-bit character size, and encoding many more characters from different languages. The first 127 characters are the same as ASCII, but the rest are allocated to symbols from different languages. Unicode Table C# uses Unicode internally to represent string data.
Strings Strings can be concatenated using an overloaded version of the “+” operator: String sMyAge = “My age is “ + iAge.ToString(); Before including the value of a variable in a string, it must be converted to a string itself. The built-in primitive types include a ToString() method that does a simple conversion. Some characters cause problems in strings. For example, attempting to include a double-quote character in a string will make the compiler think it has reached the end of the string, even if it appears in the middle of the intended string. C# provides a way to deal with this using escape characters (\): System.Console.Write( “Porky Pig said \”That’s all, folks!\””);