*100% Tested with [Dartmouth](https://engineering.dartmouth.edu/community/faculty/petra-bonfert-taylor) x [IMT](https://www.telecom-paris.fr/en/home) Online Judge/[Task Grader](https://www.edx.org/professional-certificate/dartmouth-imtx-c-programming-with-linux)* # 何強豪の C code log and learning journey ![](https://hackmd.io/_uploads/ByNjOcnk6.png) --- # Unit 3.1: Functions and recursion ## Working with functions > %s and %c eventhough it has the same array lenght but maybe the compiler act different, so choose wisely, > > If there are more than one character use %s, but if it is only one character please use %c > [color=#907bf7] **Problem 1** Write a C-program that converts metric measurements to imperial system values. Measurements are provided to your program in meters, grams or degrees Celsius and must be converted to feet, pounds and degrees Fahrenheit, respectively. Here are the conversion rules to use: 1 meter = 3.2808 feet; 1 gram = 0.002205 pounds; temperature in degrees Fahrenheit = 32 + 1.8 × temperature in degrees Celsius. On the first input line you are given the number of conversions to be made. Each of the following lines contains a value to be converted as well as its unit: m, g or c There will be a space between the number and the unit. You should print your output value for each input line immediately after calculating it (ie, you do not have to wait until you have read all inputs). Display the converted values with 6 decimal places, followed by a space and their unit: ft, lbs or f. Each conversion result should be printed on its own line, and you should store and display all decimal values as doubles. You may use functions to complete this exercise, but that is not required. However, you will need to use a comparison operation with characters, for example: char letter = 'a'; if(letter == 'a') {...} Example The following entry indicates that there are four values to be converted. The first is 10 meters, which, when converted, gives approximately 32.808 feet. The second is 1245.243 grams, or about 2.745761 pounds, the third is 37.2 degrees Celsius, or 98.96 degrees Farenheit, and the fourth is 23 grams, or 0.050715 pounds. > Input > 4 > 10 m > 1245.243 g > 37.2 c > 23 g > > Output > 32.808000 ft > 2.745761 lbs > 98.960000 f > 0.050715 lbs > [color=#907bf7] ```clike= //Metric to Imperial Program #include <stdio.h> //Function Prototype double feet(double); double pounds(double); double fahrenheit(double); //Main Function int main(void){ int iter; scanf("%d", &iter); double input; char last[1]; for(int i = 0; i<iter; i++){ scanf("%lf %c", &input, last); char unit = last[0]; if(unit == 'm'){ printf("%.6lf ft\n", feet(input)); } else if(unit == 'g'){ printf("%.6lf lbs\n", pounds(input)); } else if(unit == 'c'){ printf("%.6lf f\n", fahrenheit(input)); } } return 0; } //Function Definition double feet(double meter){ double ft = meter * 3.2808; return ft; } double pounds(double gram){ double g = gram * 0.002205; return g; } double fahrenheit(double celcius){ double c = 32 + 1.8 * celcius; return c; } ``` **Problem 2** The goal of this problem is to find the smallest integer in a list of numbers. To help you with this task, please write a function called min() that finds and returns the smallest amongst two integers (be sure to also write a prototype for this function). The function thus takes two integers as input and returns the smallest of the two. This function will use an if statement with a condition that contains either "less than" or "greater than". Next, please use min() in your main function to work your way through an entire list of numbers in order to find its minimum. The first number you read gives the number of elements in the list of integers under consideration. You will then read the integer values, using min() to keep only the smallest integer read at each step. In the end, please print out the smallest integer in the list. > Example [color=#907bf7] > Input > 10 > 4 3 6 2 6 8 9 8 5 4 > > Output > 2 ```clike= #include <stdio.h> int min(int, int); int main(void){ int num_list; scanf("%d", &num_list); int smallest; int test; scanf("%d", &smallest); for(int i = 1; i<num_list; i++){ scanf("%d", &test); smallest = min(smallest, test); } printf("%d", smallest); return 0; } int min(int x, int y){ if(x<y){ return x; }else{ return y; } } ``` ## Using Recursion: one func calls itself *keyword:* not using ~~**for loop**~~ **Factorial** ```clike= #include <stdio.h> // 5! = 1*2*3*4*5 // n! = 1*2*3*...*(n-1)*n int main(void) { int n, facto, i; printf("Please enter a positive integer: "); scanf("%d",&n); facto = 1; for(i=1 ; i<=n ; i++){ facto = i*facto; } if(n<0){ printf("%d is negative! Aborting..\n", n); }else{ printf("%d! = %d.\n", n , facto); } return 0; } ``` > Factorial of a number in mathematics is the product of all the positive numbers less than or equal to a number. > > Example: Factorial of n is n! and the value of n! is n!=n×(n−1)×(n−2)×………×1 > The value of n! from the above can be also written as > n×(n−1)! > ⇒n!=n×(n−1)! > > Considering the value of n equal to 1, > ⇒1!=1!×(1−1)! > ⇒1!=1!×(0)! > The value of LHS should be equal to RHS as 1! is always equal to 1! > For the above condition to be true, > The value of 0! must be equal to 1. > The value of 0! =1. > [color=#907bf7] **Recursive Factorial** ```clike= #include <stdio.h> // 5! = 1*2*3*4*5 // n! = 1*2*3*...*(n-1)*n //recursion : one function calls itself int factorial(int); int main(void) { int n, facto; printf("Please enter a positive integer: "); scanf("%d",&n); if(n<0){ printf("%d is negative! Aborting..\n", n); }else{ facto = factorial(n); printf("%d! = %d.\n", n , facto); } return 0; } int factorial(int n){ int result; if(n==0){ result=1; }else{ result = n * factorial(n-1); //Calling itself } return result; } ``` Recursion is V type, so it's calling itself until it exhausted the variable, then after getting the bottom truth it calculate itself **Fibonacci** ```clike= // Fibonacci numbers: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ... int fibonacci(int); #include <stdio.h> int main(void) { //! showMemory(start=65520) int N, fib; printf("Which Fibonacci number would you like: "); scanf("%d", &N); if (N<=0) { printf("%d is not positive. Aborting!\n", N); } else { fib = fibonacci(N); printf("The %dth Fibonacci number is %d.\n", N, fib); } return 0; } int fibonacci(int n) { if (n==1) { return 0; } else if (n==2) { return 1; } else { return (fibonacci(n-1) + fibonacci(n-2)); } } ``` **Problem 1** Please write a C-program that uses a recursive function called "sumOfDigits()" to compute the sum of the digits of a number. To do so, your main function should first read an integer number as input and then call sumOfDigits(), which should in turn call itself until there are no digits left to sum, at which point the final sum should display to the user. Here is the main idea of how the recursion in sumOfDigits() should work: sumOfDigits(6452) = 2 + sumOfDigits(645) sumOfDigits(645) = 5 + sumOfDigits(64) ... sumOfDigits(6) = 6 > [color=#907bf7] Examples >> Input > 47253 > Output > 21 > >> Input > 643 > Output > 13 ```clike= #include <stdio.h> int sumOfDigits(int); int main(void){ int x; scanf("%d", &x); printf("%d", sumOfDigits(x)); return 0; } int sumOfDigits(int x){ int sum; if(x<10){ sum = x; }else{ sum = (x % 10) + sumOfDigits(x/10); } return sum; } ``` --- # Unit 3.2: Memory and the scope of variables ## Understanding computer memory (Von Neumann) ![](https://hackmd.io/_uploads/SJNitc31p.pnghttps://hackmd.io/wtGWMV64QgKcaTpr4bVHyw?both) **Princeton Architecture** ALU => + - / and or etx Control unit => Data Sequences; timing operation Memory => VM (RAM): Temporary & NVM: Permanent **Computer Memory and Addressing** Storing information NVM: Files VM (RAM): Quick Exe => Program : 0 or 1 => bit WORD: computer unit => 1 byte = 8 bits Why group? memory address (location) for each word ![](https://hackmd.io/_uploads/SJiSi9h1a.png) low-level access => word to word optimization of memory efficiency ## Determining the amount of memory used for different data types **Get the size of data type**: %zu, sizeof(can be the type or the variable) char:1, int:4, double:8 for array: multiple by the array length and type size; exp: list_int[3] = 12 ```clike= #include <stdio.h> int main() { char c; int i; double d; char listChar[3]; int listInt[3]; double listDouble[3]; printf("%zu\n", sizeof(listChar)); printf("%zu\n", sizeof(listInt)); printf("%zu\n", sizeof(listDouble)); return(0); } ``` **Problem 1** Your program should first read an integer number indicating how many tracking codes you plan on entering. Next, for each successive tracking code your program should read in the integer length of code followed by a space and then the type of code ('i' for integer, 'd' for decimal, or 'c' for character). Finally your program should print the total amount of space required to store all of the tracking codes (in bytes). If the user enters an incorrect type for any tracking number, the program should print 'Invalid tracking code type' and exit. > Input: > 3 > 10 i > 7 c > 12 d > > Output: > 143 bytes > [color=#907bf7] ```clike= #include <stdio.h> int memCal(int, char[1]); int main(void){ int iter; scanf("%d", &iter); int total = 0; int mem; char units[1]; for(int i = 0; i<iter;i++){ scanf("%d %c", &mem, units); total = total + memCal(mem, units); } if(total<1000){ printf("%d bytes", total); }else{ printf("Invalid tracking code type"); } return 0; } int memCal(int mem, char units[1]){ char unit = units[0]; if(unit == 'i'){ return sizeof(int) * mem; } else if(unit == 'd'){ return sizeof(double) * mem; } else if(unit == 'c'){ return sizeof(char) * mem; } else{ return 1000; } } ``` **Largest Int**: 2147483645 + 3 ![](https://hackmd.io/_uploads/Sktp7_61T.png) ![](https://hackmd.io/_uploads/rkmSE_pya.png) *The hexa decimal keep being added, but the decimal interpretation is wrong* [Two's Complacement](https://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html#:~:text=Two's%20complement%20is%20the%20way,add%20one%20to%20the%20result.): **Round off numbers and circumvent errors** printf("the number is %.40lf\n", num); => not accurate 0.25 ok vs 0.3 not ok; why? power of 2: 0.25 = 1/4 = (1/2)^2 => accurate binary representation **Problem 2** Your job is to write a program that shows, in human-readable form (see below for specifics), how much memory a set of variables of a certain type will use. Your program should read a character that identifies the data type 'i' for int, 's' for short, 'c' for char, 'd' for double Next it should read an integer that indicates how many variables of the given type you wish to store. Your program should then calculate the amount of memory required to store the given variables. Your program needs to be written in such a way that it would also perform correctly on other computers. In other words, rather than hard-coding specific sizes for the different variable types, your program needs to use the "sizeof()" function to determine how much memory an individual variable of a given type needs. Finally, you need to output the amount of space required by your variables to the screen. You need to make sure you provide this output in a form that is easy to read for humans. The following examples illustrate what this means: Examples If the user input were: i 36794 then the amount of space needed (int 4 bytes) would be 4*36794 = 147176 bytes. This corresponds to 147 kilobytes and 176 bytes, so the output should be: 147 KB and 176 B > Input: > d 654250 > > Output: > 5 MB and 234 KB and 0 B > [color=#907bf7] !!! The kilobyte has different values in binary and in decimal. Please note that for this exercise, we are referring to the kilobyte of value 1000. Although this value is referred to using the symbol kB, please use the symbol KB when coding this exercise. ```clike= #include <stdio.h> int main(void){ int nVar; char units[1]; scanf("%c %d", units, &nVar); long mem = 0; char unit = units[0]; if(unit == 'i'){ mem = nVar * sizeof(int); } if(unit == 's'){ mem = nVar * sizeof(short); } if(unit == 'd'){ mem = nVar * sizeof(double); } if(unit == 'c'){ mem = nVar * sizeof(char); } if(mem<1000){ printf("%ld B\n", mem); }else if(mem<1000000){ printf("%ld KB and %ld B\n", mem/1000, mem%1000); }else{ printf("%ld MB and %ld KB and %ld B\n", mem/1000000, (mem%1000000)/1000, (mem%1000)); } return 0; } ``` *Good Writing method: if by line* ```clike= if (c=='c') spacePer = sizeof(char); else if (c=='s') spacePer = sizeof(short); else if (c=='i') spacePer = sizeof(int); else spacePer = sizeof(double); ``` ## Determining the scope of variables array x[y] = {y0, y1, .., yn-1}; **stack memory system** ![](https://hackmd.io/_uploads/rJF77Ya1a.png) ![](https://hackmd.io/_uploads/Syn27Y6ka.png) ![](https://hackmd.io/_uploads/ByGzVKpkT.png) **Scope and blocks** { this called a block } ![](https://hackmd.io/_uploads/ryGQUF61a.png) *but the memory will be reused by command outside block* out block => destroy variable **Scope and functions** ![](https://hackmd.io/_uploads/S1XuY6Tka.png) as soon as leave function block, variable release but value still there also, how bout argument? ![](https://hackmd.io/_uploads/Hk479p6ya.png) **Logic Problem** ![](https://hackmd.io/_uploads/B10Cq66y6.png) ![](https://hackmd.io/_uploads/H1rN3TaJa.png) --- # Unit 3.3: Pointers ## Defining pointers and dereferencing pointers **pointer = address** type * varAdd = &varTarget; %p ![](https://hackmd.io/_uploads/Hyb-BrllT.png) **dereferencing** ![](https://hackmd.io/_uploads/HkV1vrxlp.png) ![](https://hackmd.io/_uploads/Hy_tvBegp.png) ```clike= /* Input 45 Output The secret address is...fffc Now take three drops of the magic elixir. Did the elixir work? You are 40 years old! */ #include <stdio.h> int main(void) { int age; // add a line here that declares an integer pointer named "ageptr" int * ageptr; scanf("%d", &age); // add a line here that stores the address of age in ageptr ageptr = &age; printf("The secret address is... "); // add a line here that prints out the address stored in ageptr printf("%p\n", ageptr); printf("Now take three drops of the magic elixir. \n"); // add a line that uses only ageptr to lower the age by 5 years * ageptr = * ageptr - 5; printf("Did the elixir work? You are %d years old!", age); return 0; } ``` ## Using pointers with functions **Swap two integer variable values using functions and pointers** ![](https://hackmd.io/_uploads/Hy_a13Fgp.png) Stiil have original a and b => Problematic ```clike= #include <stdio.h> void swap(int *,int *); int main() { //! showMemory(start=65520) int a = 9; int b = 1; swap(&a,&b); // input the address printf("%d %d\n",a,b); return 0; } void swap(int * a, int * b){ //deferencing point to the address int tmp = * a; //what is in a * a = * b; // what is in a = what is in b * b = tmp; } ``` ![](https://hackmd.io/_uploads/HyBW42Yga.png) **Edit Variable Cross Block using Pointer** ```clike= /* The way your elixir works is that anyone who is at least 21 years old becomes ten years younger. However, the elixir does not work on anyone twenty years old or younger - when these people try the elixir, they actually double in age! Input: 55 Output: Your current age is 55. Your new age will be 45! */ #include <stdio.h> //Write your function prototype here void check(int *); int main(void){ int age; int *ageAddr = &age; scanf("%d", ageAddr); printf("Your current age is %d.\n", age); //Write your function call here check(ageAddr); printf("Your new age will be %d!\n", age); return 0; } void check(int * ageAddr){ if(* ageAddr > 21){ * ageAddr -= 10; }else{ * ageAddr *= 2; } } ``` ## Performing simple pointer arithmetic ![](https://hackmd.io/_uploads/ry-1qnFx6.png) **pointer arithmetic** ![](https://hackmd.io/_uploads/rygR5ntxT.png) ```clike= #include <stdio.h> int main() { //! showMemory(start=65520) int arr[3] = {15, 16, 17}; printf("%p\n",arr); int * ptr = arr; * ptr = 2; // * arr 0R arr[0] * (ptr + 1) = 3; // * (arr + 1) OR arr[1] * (ptr + 2) = 5;// * (arr + 2) OR arr[2] return 0; } ``` ![](https://hackmd.io/_uploads/Sy7UzTFgp.png) ## Pass an array to a function ```clike= #include <stdio.h> void reset(int *); int main() { //! showMemory(start=65520) int arr[3] = {15, 16, 17}; reset(arr); return 0; } void reset(int * ptr){ *(ptr + 0) = 0; *(ptr +1) = 0; *(ptr +2) = 0; } // or can #include <stdio.h> void reset(int []); int main() { //! showMemory(start=65520) int arr[3] = {15, 16, 17}; reset(arr); return 0; } void reset(int ptr []){ ptr[0] = 0; ptr[1] = 0; ptr[2] = 0; } ``` **Array Swapping Function** Within this program, we will pass an array with 6 integers to a function, have the function swap the first and last integer, the second and the second to last integer, the third and the third to last integer. The function is called reverseArray and doesn't return anything (void). It should take one parameter, representing the array of integers. The main function first reads 6 integers from the input, and assigns them to the array. The main function then calls reverseArray, passing the array as an argument. The main function then prints the reversed array. > Examples [color=#907bf7] > Input: >> 1 2 3 4 5 6 > > Output: >> 6 5 4 3 2 1 ```clike= #include <stdio.h> void reverseArray(int []); int main(void){ int iter = 6; int arr[5]; for(int i = 0; i<iter; i++){ scanf("%d", &arr[i]); } reverseArray(arr); for(int i = 0; i<iter; i++){ printf("%d", arr[i]); if(i != 5){ printf(" "); } } return 0; } void reverseArray(int arr[]){ int end = 5; for(int i = 0; i<3;){ int temp; temp = arr[i]; arr[i++] = arr[end]; arr[end--] = temp; } } ``` # Final Project Write a function isReverse() that checks whether a given word is the reverse of another given word. More precisely, the function should take as inputs two words (null-terminated arrays of characters) and return an integer. If indeed the second word is the reverse of the first then the function should return the integer 1, otherwise it should return a 0. Your main() function should read two words from the user input (you can assume that neither word has more than 99 characters) and then call the function isReverse, passing both words to this function. The function should return an integer as described above and your main program needs to print out a sentence, indicating whether indeed, the first word is the reverse of the second word (see below examples). Note: The name of the function needs to be isReverse. > Here are two sample runs:[color=#907bf7] > **Input:** >> stressed >> desserts > > **Output:** >> stressed is the reverse of desserts > > **Input:** >> apple >> banana > > **Output:** >> apple is not the reverse of banana ```clike= #include <stdio.h> #include <string.h> int isReverse(char [], char[]); int main(void){ char arr1[100]; char arr2[100]; scanf("%s", arr1); scanf("%s", arr2); int result = isReverse(arr1, arr2); if(result){ printf("%s is the reverse of %s", arr1, arr2); }else{ printf("%s is not the reverse of %s", arr1, arr2); } return 0; } int isReverse(char arr1[], char arr2[]){ int l1 = strlen(arr1); int l2 = strlen(arr2); if(l1 != l2){ //printf("not the same"); return 0; } int end2 = strlen(arr2) -1; int i = 0; while(arr1[i] != '\0'){ if(arr1[i] != arr2[end2]){ //printf("%c %c :not the same", arr1[i], arr2[end2]); return 0; } i++; end2--; } //printf("The same"); return 1; } ```