SWITCH SLIDE syntax switch (expression) { case constant-integer-valued-expression1: statement[s] ... case constant-integer-valued-expression2: statement[s] [default: statements] } expression is evaluated. if expression matches one of the case labels, then execution starts at that label. execution **will fall through** to the next label unless there is a break. if no case matches, execution will start at the default label. NUMBER TO WORD MAIN here, we are just getting a value from the user and passing it to print_num function NUMBER TO WORD PRINT_NUM if n has thousands in it, calls print_hundreds for the number of thousands that we have, and prints thousand after this. now, takes off everything above hundreds in n with modulo if n is nonzero (wasn't just an even something-thousand), calls print_hundreds with the new n if n does not have thousands and is just zero, print zero if n is not zero but has no thousands, just call print hundreds on n NUMBER TO WORD PRINT_HUNDREDS if n is greater than a hundred, it prints the hundreds digit with print_lownums and then prints hundred then takes off the hundreds now, if n is greater than 20, it prints the tens by taking off the ones digit with the /10*10 and giving this to print_tens (other way to do this n - n % 10 then takes off the tens with modulo if n nonzero, prints the lowest digit if n was less than twenty, just passes it to lownums NUMBER TO WORD PRINT_LOWNUMS just one big switch/case construct note: break after every case except the last NUMBER TO WORD PRINT_TENS again, just one big case/switch in this example, got into calling lots of functions. what if we run into an error and want to stop execution? just using a return statement just returns back to the calling function; does not stop execution. instead, use the fuction exit(). This causes the main function itself to return. the exit function returns void and takes an integer argument. the argument is the exit status with which you want the program to return. C Preprocessor directives Comments /* */ #include <> vs. "" <> -- look for files in standard include path look for files in directories included on CL with -I? "" -- look for files in standard include path look for files in directories included on CL with -I, look for files in local directory #define x y really should use enums or const int #undef #if evaluates a constant integer expression #### #if defined(x) vs #ifdef x #if !defined(x) vs #ifndef #else #endif Macros can take arguments. Must be very careful with side effects because everything is substituted literally. #define FOO(BAR) (BAR) * (BAR) for example, you might get an odd result if you call FOO(++x) Should put parentheses around all macro variables. #define FOO(BAR) BAR*2 // Produces wrong output for FOO(x+1) #define FOO(BAR) (BAR)*2 // This is correct BASIC DATA TYPE SLIDE Go over basic data types. char, short <= int <= long char is 8 bits (one byte) short is at least 16 bits long is at least 32 bits short/long can be modifiers to integers, or can be used alone int is the NATURAL type signed/unsigned are modifiers to char or integers unsigned -- always positive or zero an unsigned char has range 0 to 255 signed -- uses MSB to determine sign of number in two's complement machine, signed char has range -128 to 127 float: single precision floating point double: double precision floating point long double: extended-precision floating point depending on implementation, the above could be 1, 2, or 3 distinct sizes long long (c99 extension that is supported by most compilers today) generally 64 bits void: value of a void object cannot be used in any way a void object cannot be converted to any non-void type a void expression may be used only where the value is not required (left operand of comma operator, expression statement) CONSTANT SLIDE a constant integer number in a program will be considered an int (12, 43) to make a constant a long, put an "l" or "L" at the end (112346780L, 1L) to make a constant unsigned, put a "u" or "U" at the end (32u, 55U) "ul" or "UL" can be used to make a long unsigned constant a constant number with a decimal point or exponent is a double (25.8, 1e-3) an "L" or "l" at the end of such a number will be a long double (58.23L) to force the number to be a float, add "f" or "F" to the end (98.2 f) to specify a hexidecimal number (base 16), prepend "0x" (zero x) hexadecimal uses digits 0-9, a-f each digit can be represented in 4 bits (a nybble) (0x7, 0x1f -- these are 7 and 31 in decimal) for octal (base 8), prepend "0" (zero) octal uses digits 0-7 each digit can be represented in 3 bits (07, 032 -- these are 7 and 26 in decimal) there is no "b" prefix!! if you want to use a binary number, write it in hex or octal a character constant is an integer 'a' + 2 == 'c' would evaluate to true character constants can be specified by a single character in single quotes, an escape sequence, or an arbitrary byte-sized pattern (\nnn (in octal) or \xnn (hexadecimal)) '\0' is a character with value 0; \x30 is the zero character; \060 is also the zero character escape sequences are \a alert \\ backslash \b backspace \? question mark \f formfeed \' single quote \n newline \" double quote \r carriage return \t horizontal tab \v vertical tab a string constant is some zero or more characters in double quotes ("Hello, World!\n", "") strings are concatenated at compile time ("hello" " world" is the same as "hello world") technically, a string is an array of characters ending with '\0', but we won't be talking about arrays until tomorrow putting "const" before a variable declaration says that the variable will not change value const int pi = 3.14159; if an attempt to change that constant is made, the result is implementation dependent TYPE CONVERSION SLIDE Type conversion/argument promotion when operator has operands of different types, they are converted according to specific rules, if possible if the conversion will lose information, this will generally only get a compiler warning arithmetic rules: if either operand is long double, convert other to long double else if either is double, convert other to double else if either is float, convert other to float else convert char and short to int if either is long, convert other to long on some machines, a char with 1 in MSB will be converted to a negative integer things get hairier with signed/unsigned -- machine dependent assignment rule: value of right side is converted to type of left float -> int truncates fractional part double -> float rounds or truncates -- machine dependent you can force a conversion by casting (type_name) expression will cause expression to have type type_name TYPE CONVERSION EXAMPLE SLIDE Answers for type conversion examples 1) both ints 2) 1 promoted to double 3) 76 promoted to float 4) 24.598 promoted to long double 5) 35 promoted to unsigned long 6) 876 promoted to unsigned int 7) 1U promoted to signed long 8) 1L promoted to unsigned long (appears to be large positive number) 9) 'c' converted to int 10) 34 converted to int EXTENDED DATA TYPE SLIDE Extended data types enumeration constant -- a list of constant integer values example: enum numbers {ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN}; each of these variables will now have the value that its english name suggests. enumerations always start assigning values at zero if left unspecified. but you can assign numbers example: enum foo {MEANING_OF_LIFE = 42, BAD_LUCK = 13} you can also specify the starting number and have the rest generated. unspecified values continue incrementing from the last specified value enum days {SUN = 1, MON, TUES, WED, THURS, FRI, SAT} MON is set to 2, TUES to 3, etc. this is like #define, except that values can be generated for you STRUCTURE SLIDE structure -- collection of one or more variables of possibly different types, grouped together under a single name to declare a structure, use keyword struct struct { int foo; float bar; } you can give the structure a tag struct point { int x; int y; } now "struct point" can be used as shorthand for the above structure the variables in the structure are members a member can have the same name as a variable outside the struct, as any variable in any other struct, or as the struct tag a struct declaration defines a type, so struct point { int x; int y; } i, j, k; declares i, j, and k each to be point structures struct point i, j, k; is equivalent if the point structure has already been declared initializing structs follow the declaration of a variable of type structure with a list of constant expressions to which its members should be initialized struct point i = {3, 46}; to refer to a particular member of a struct struct_name.member so i.x would be 3 and i.y would be 46 you can also change the values i.x = 4 setting one structure equal to another makes all of its members equal struct point i = {7, 2}; j = i; now j.x is 7 and j.y is 2 structures cannot be compared as a whole i < j is not allowed i.x < j.y is fine UNION SLIDE union: variable that may hold (at different times) objects of different types and sizes, a way to manipulate different kinds of data in a single area of storage without putting any machine-dependent information in the program the union is a single variable which can hold any *one* of several types syntax is like structures union u_tag { int ival; float fval; char sval; } u; u will be big enough to hold the largest of the three types. u can be declared any of these types and used in expressions, however, the type retrieved must be the type most recently stored the members of the union are accessed like structures union_name.member typedef: used for creating new data type names typedef int integer makes integer a synonym for int integer i, j; is the same as int i, j; we could also do typedef struct point Point; now Point can be used to declare point structures typedefs can make programs more readable, type checking for data abstractions more rigorous, help with portability issues EXTENDED TYPE EXAMPLES FUNCTION SLIDE Function declaration default return type is an int old style k&r argument declaration never use this. new ansi style declaration PASS BY VALUE SLIDE will print out correctly because base and n won't change pass by value -- the called function is given the values of its arguments in temporary variables rather than the originals RECURSIVE FUNCTION EXAMPLE SLIDE RETURN SLIDE return(); may return any basic or extended data type covered so far including unions and structs (not arrays) arguments to main() int argc, char *argv[], char *envp[] argc: number of arguments argv: pointer to array of arguments envp: environment pointer both argv and envp are null-terminated lists these variables can be used to get arguments from the command line SCOPE SLIDE Scope and storage class storage class: automatic and static (local vs global) scope: local to a function, local to a file, global to the application declaration vs definition; may never define a variable twice; global variables always initialized to 0 unless otherwise stated in the program local variables never initialized "static" variables are really global with local scope register is a keyword applied to local variables don't use it lexical scope: Each of the following name spaces can have the same name and not have a collission: objects/functions, typedef names, enum constants, labels, members of structures, members of unions EXAMPLE SLIDE EXAMPLE SLIDE