CSE 206 Course Review
Conditions Switch If/else-if/else When: all conditions depend on a single value Example: switch (var1) { case 1: …; break; default: …; } If/else-if/else When: Any other case Example: if (var1 == 1 || var1 == 2) {...} else if (var > 0) {...} else {...} Evaluated in order, if first if is not true, then it checks the second “else if” If more than one condition: check first condition, if true, checks the second
Conditions if (a == 1) { if (b == 2) { // … if (a == 1 && b == 2) // ALWAYS true } if (a == 1 && b == 2) { // … }
Binary and logical operators Can be used in any condition (if, loops, …) Binary &: and bit by bit |: or bit by bit =: assignment, if (a = 1) is ALWAYS true and WILL make a=1, whatever the previous value ... Logical &&: and ||: or ==: equal !=: different … if (a == b && b != 0)
Loops For While Do-while When: you know the number of iterations Example: for (i = 0; i < n; i++) {...} // initialization; condition; increment While When: you DON’T know the number of iterations Example: while(n > 0) {...} // n must change its value inside the loop! Do-while When: you DON’T know the number of iterations but want to execute at least ONCE Example: do { … } while(n > 0);
Functions Function name Declare before (outside) main(): int function(int parameter1, int parameter2); Define (outside main): int function(int p1, int p2) { return p1+p2; } Call (inside main or other functions): int c = function(a, b); Why: encapsulate parts of the code that solves one problem for readability and to avoid code duplication Good example in HW5_Q1, “isdigit(), “isvowel()”, … (My rule of thumb: any function, including main(), should not be more than ~20 lines of code) return type Returns an int
Fibonacci: loops vs recursion Each function call reserves some space in the stack: for each parameter, where to return after the function, function variables. The stack keeps filling until the recursion finishes! Too many function calls could cause a stack overflow. fib(5) fib(4) fib(3) fib(3) fib(2) fib(2) fib(1) fib(2) fib(1) fib(1) fib(1) fib(1)
Fibonacci Recursive is more readable and intuitive, but it is not the best algorithm to use in this case: 1- It can cause a stack overflow 2- It calculates several times the same result (5 times fib(1), 3 times fib(2), …) If you are interested: One optimization for the recursion version could be: You know the number of Fibonacci numbers you want to print, so you can create an array with those number of positions and initialize all to -1. Instead of using the base case as n < 2 you could replace it with: if that array position index is different than -1, return the value that it contains. That way you would only call each function number just ONCE! Less recursive calls and still more readable. This technique is called Memoization.
Increment and Decrement Operators What is the value when i=5 ++i vs i++ in: a = ++i; a = i++; What is the difference between: for (i = 0; i < n; i++) for (i = 0; i < n; ++i) What position is accessed in each case: array[i++] array [++i]
Conditions if (expression1) if (expression2) Statement; else What could be wrong here?
What is the output int main() { int i = 0; for(i = 0; i < 3; i++); { printf("we are in the loop "); continue; } printf("i=%d\n", i); return 0; }
Where is the bug? int arr[20]; for (i = 0; i <= 20; i++){ arr[i] = 0; } int count; while (count < 50){ count++; } char z = ‘p’; while (z = ‘p’){ z = ‘b’; } char* s1 = “string”; char* s2 = “string”; if (s1==s2){ printf(“We’re equal!\n”); }
Pointers in arrays: consecutive in memory int *end int *start int *current current++ while (current < end) {...}
Pointers in LinkedList a = 1; next a = 4; next a = 21; next a = 8; next NULL Node *head Second in the list (a=4): head->next->a = 3;
Accessing structs Student s; Student *ptr = &s; ptr->grades.test1 = 84.1; // through a pointer s.grades.test2 = 96.2; // through the student (*ptr).uin = 123456789; // beware of the parenthesis!