{%hackmd @themes/orangeheart %} # The C Programming Language ### Author's Note: The notes on this page will not only include current lecture's, but also other resources to give a more comprehensive study on C. Some examples will be compared with similar code but written in Python as well. ## Setting Up a C/C++ Compiler Before going to the actual part of writing code, C is very different compared to Python, u cannot run programs as straight-forward as Python. Hence, take note on this section how to set up a compiler for C/C++. Here author will be using vscode to compile. The C/C++ extension doesn't include a compiler or debugger tool. Thus, u will have to install these tools to ur computer ([GCC](https://en.wikipedia.org/wiki/GNU_Compiler_Collection) or [Clang](https://en.wikipedia.org/wiki/Clang) specifically). There may already be a C/C++ compiler and debugger provided by ur academic instructor. Check with ur instructors for guidance on how to install and use those compilers instead. Otherwise, refer to [this complete guide on how to install and use C/C++ compiler on vscode](https://code.visualstudio.com/docs/languages/cpp) instead. ## Compiling and Executing C Programs To make sure u have installed the compiler, execute this command line in the terminal: - GCC: ``` g++ --version ``` - Clang: ``` clang --version ``` Follow these steps to know how to compile, we will be using the `Hello World` example mentioned above: - open a text editor like vscode and add the example code - save the file as `hello.c` - open the terminal and type `gcc hello.c` and enter to compile the code - if there are no errors in the output, terminal will generate an `a.out` executable file - type `a.out` to execute the program - `Hello, World!` expected to be in output [Reference](https://www.tutorialspoint.com/cprogramming/c_program_structure.htm) There are more commands to control workflow and file directories, see [here](https://ftp.kh.edu.tw/Linux/Redhat/en_6.2/doc/gsg/ch-doslinux.htm#:~:text=Many%20Linux%20commands%20you%20type,fact%2C%20some%20commands%20are%20identical.) ## Commands Commands are used in terminal, powershell or command prompt to configure file directories and edit files in your computer: | Commands | Usage | | - | - | | `dir` | Directory listing | `ren` | Rename a file | `copy` | Copying a file | `move` | Moving a file | `cls` | Clear screen | `del` | Delete file | `find` | Search for a string in file | `time` | Displays time | `cd` | Change the current directory | `md` | Create a new directory/folder | `echo` | Print | `rmdir` | Delete a directory For more commands, see this [reference](https://www.geeksforgeeks.org/linux-vs-windows-commands/) ## Basic Syntax ### `printf` Printing a string in C will look like this: ```C printf("hello world"); ``` The `f` in `printf` refers to a formatted string. ### Identifiers C identifier is a name to identify a variable, function, or any other user-defined item. Note that a C identifier: - doesn't allow punctuation characters (@,$,etc) - is **case-sensitive** - can include underscores This is why it's good programming practice to name human-readable variables and functions to briefly specify the purpose of the indentifiers. A readable variable looks like this: ``` Calculator_helper ``` Do not take shortcuts like this: ``` calc_help ``` ### Keywords Keywords are reserved words in C, these special words must not be used as constants or variables or any other identifier names. Refer to [here](https://www.ibm.com/docs/en/developer-for-zos/14.2.0?topic=programs-c-reserved-keywords) ## Data Types Data types are indicators of what kind of data they represent when we program our code: ### Basic Data Types | Type | Usage | | - | - | | `bool` | boolean values, `true` or `false` | `char` | single character | `float` | real numbers | `int` | integers | `string` | string of characters [More references](https://www.tutorialspoint.com/cprogramming/c_data_types.htm) ### Integer Types *Note: Bit sizes vary for different computer architectures* | Type | Value Range | | - | - | | `char` | -128 to 127 or 0 to 255 | `unsigned char` | 0 to 255 | `signed char` | -128 to 127 | `int` | -32,768 to 32,767 or -2,147,483,648 to 2,147,483,647 | `unsigned int` | 0 to 65,535 or 0 to 4,294,967,295 | `short` | -32,768 to 32,767 | `unsigned short` | 0 to 65,535 | `long` | -9223372036854775808 to 9223372036854775807 | `unsigned long` | 0 to 18446744073709551615 - `unsigned` values start from 0 - `signed` values (`signed char`) start from -128 ### Floating-Point Types Different float values have different precisions, in which they have more decimal places: | Type | Percision | Value Range | | - | - | - | | `float` | 6 decimal places | 1.2E-38 to 3.4E+38 | `double` | 15 decimal places | 2.3E-308 to 1.7E+308 | `long double` | 19 decimal places | 3.4E-4932 to 1.1E+4932 ### Void Types Similar to `None` in python, `void` is a special value that represents the absence of a value. This is used in 3 different situations: - function returns as void - no value is returned will return `void` - function arguments as void - function with no parameters, exp: `int rand(void);` - pointers to void - represents the address of an object but not it's type - memory allocation function returns a pointer to void so it can be casted to any data type ## Program Structure A C program consists of the following parts: - Preprocessor Commands - Functions - Variables - Statements & Expressions - Comments ### Example We will be using a `Hello World` example to explain the program structure written in C: ```C #include <stdio.h> int main() { /* my first program in C */ printf("Hello, World! \n"); return 0; } ``` ### Preprocessor Command `#include <stdio.h>` is a preprocessor command, also called as a **header file**, it tells the C compiler to include stdio.h libraries before going to the actual compilation. - `#define` - definition of a constant (can be strings or ints) - can take arguments and be treated like a function - **parentheses ensure order of operations** - **not suitable for recursion** ```C #define msgs "test" int main(){ printf(msgs) } ``` - `#if`, `#ifdef`, `#ifndef`, `#else`, `#elif` , `#endif` - control which lines are compiled - `#pragma` - preprocessor directive - `#error`, `#warning` - trigger a custom compiler error warning - exception handling - `#undef` - remove definition of a variable at compile time ### Function Similar to python `def` functions, C uses the `int main` function where the program execution begins. ### Comments `/*` and `*/` are used as additional comments to explain what the program does, similar to python's docstring. Whatever is in the comment lines will be ignored by the compiler. ### Statements & Expressions `printf` is a method to print `Hello World!` in the terminal. **The** `/n` **at the end of the string tells the compiler to get a new line after printing.** Compared to python, semicolon `;` must be at **the end of every operation to indicate that this is the end of statement.** ### Return Values `return 0` terminates the `main()` function and returns the value 0. This is useful to indicate that the program has executed successfully, it is good practice to include this at the end of the function. ## Format Specifiers As previously discussed, `printf` is a method to print formatted strings. Format specifiers define what kind of data to be printed on output. It is **mandatory** to include this with `printf` or `scanf` inputs. | Specifier | Data Type | | - | - | | `%c` | `char` | `%s` | `string` | `%f` | `float` | `%n` | prints nothing | `%i` | decimal integer (assumes base 10) | `%d` | decimal integer (auto-detects) | `%p` | pointer | `%u` | int unsigned decimal | `%e` or `%E` | float values with scientific notation | `%%` | % symbol | `%hi` | short (signed) | `%hu` | short (unsigned) | `%Lf` | `long double` [More specifiers](https://www.freecodecamp.org/news/format-specifiers-in-c/) ## About Data Size (Practices) ### Manipulating Out of Range Data Sizes ```C #include <stdio.h> int main(){ char c = 125; c = c+10; //notice for data type signed char the range is 0-127 printf("%d", c); } ``` Since by default, declared `char` variables are `signed char`. The range for `signed char` is -128 to 127, `c` for `135` here is out of this range: - `125`'s binary counterpart is `01111101` - `10`'s binary counterpart is `1010` - adding `125` and `10` together we get `10000111` - get the most significant bit of `10000111` which is `1`, **this represents a negative number** - finding 2's complement of `10000111`: `01111000` + `1` = `01111001`: `121` in decimal system - considering the most significant bit, `-121` is returned ### `sizeof()` and Signed Values `sizeof()` is a function that computes the size of the operand: ```C printf("%d\n",sizeof(char)); //prints 1 printf("%d\n",sizeof(int)); //prints 4 int a = 20; char b = 'b'; printf("%d\n%d\n",sizeof(a),sizeof(b)); //prints 4 and 1 ``` Comparing `sizeof()` values with unsigned values and prioritizing the order of evaluations: ```C #include <stdio.h> int main(){ if (sizeof(int) > -1) printf("Yes"); else printf("No"); //desired output return 0; } ``` - `sizeof(int)` is 4 which is an `unsigned int` - `-1` here is an `signed int` From the order of evaluations in C, **when integer values are compared with unsigned values, the int is promoted to unsigned.** In this case, when `-1` is promoting to `unsigned`, **negative numbers are stored in 2's complement form,** so the unsigned value of `-1` is significantly higher than `sizeof(int)`, which in result prints `No`. ### Dividing between Ints ```C #include <stdio.h> int main(){ float c = 5.0; printf ("Temperature in Fahrenheit is %.2f", (9/5)*c + 32); return 0; } ``` Since `9/5` is expressed as int divided by int, it will be expressed as `9//5`. A fix for this can be expressed as `9.0/5.0` or `1.0*9/5` (floating point precedence). ### Using *Inaccurate* Format Specifiers Be careful when printing formatted strings, using `printf` with incorrect specifiers will return incorrect values: ```C #include <stdio.h> int main(){ char a = '1'; printf("%d", a); //prints 49 return 0; } ``` ## Binding Variables Unlike in python where data types are automatically detected when assigning values to variables like: ```python counter = 5 service_payment = 12.39 service_type = 'a' service_code = 'A25MiR' service_name = 'John' ``` However, in C, u will need to tell the program which data type the variable ur going to assign the value. ## Variable Definition and Declaration ### Declaration and Initialization Variable declaring takes more steps than the conventional approach used in python. If u want to use variables u will have to define them first: ```C int n; float phi; ``` Ensure that the variables defined are linked correctly to their respective data types. However, u may also initialize a variable declaration like: ```C float phi = 1.6180339887; int a = 0; ``` For handling multiple declarations u can do: ```C int a, b, c = 2, d = 5; ``` This is to say that `a` and `b` are declared as integer variables, while `c` and `d` are declared with **integer values assigned.** ## Arithmetic Expressions Binary arithmetics using the four basic principles of calculations are allowed in C: ```C x+y //x += y x-y //x -= y x*y // x *= y x/y // x %= y ``` U could do simple expressions and statements using this example: ```C y = (x+3)/2; ``` ### Example Assume that $x = 2.0$ and $y = 3.0$, evaluate the statement: $$m = \frac {x+2y} {2x+3 \frac{3x}{5y}}$$ ```C float m = (x+2*y)/(2*x+3*((3*x)/(5*y))) ``` ## Function prototypes Declarations are also called function prototypes, it is a must to declare functions first before using: ```C int multiplication (int); ``` or ```C int multiplication (int n); ``` - `<stblib.h>` has many common functions for prototypes as well - [Library for functions in C](https://www.ibm.com/docs/en/i/7.3?topic=extensions-standard-c-library-functions-table-by-name) ## About `main` ### `int main()` or `int main(void)` - simplest version - no inputs, outputs `0` when successful - non-zero to signal error ``` Function declaration { declare variables; program statements; } ``` ### `int main(int argc, char **argv)` - two-argument form of `main()` ## Printing ### Printing with `puts()` ```C int main(){ puts("hello!"); return 0; } ``` The difference between `printf()` and `puts()` is that `puts()` output text to console and **ends the line. This is done without** `\n`**.** A more specified output formatting guide can be found in [this section of the notes.](/KfvXkM4ZTxGjMdqLgZAWZw) ### Printing String Variables Alternatively, string variables can be assigned using `const char`. - `const`: qualifies variable as constant - `char`: data type representing a single character Together, `const char msg[]` will be a constant array of characters. ## Console I/O `stdout` and `stdin` are streams for console input and output. - `puts(string)`: prints string - `putchar(char)`: print character - `char = getchar()`: return character input from `stdin` - `string = gets(string)`: return string input from `stdin` ## C Preprocessor Preprocessors are not included in the compiler, they're used solely for a text substitution tool to reduce repetitive code. It instructs the compiler pre-process before compilation. ![c preprocessors](https://media.geeksforgeeks.org/wp-content/cdn-uploads/Preprocessor-In-C.png) ### Types of Preprocessors | Preprocessor | Description | | - | - | | `#define` | substitutes macro | `#include` | inserts header files | `#undef` | undefines macro | `#ifdef` | returns true if macro is **defined** | `#ifndef` | return true if macro is **not defined** | `#if` | tests if compile time condition is true | `#else` | alternative for `#if` | `#elif` | `#if` and `#else` in one statement | `#endif` | ends conditional macro | `#error` | prints error message on stderr | `#pragma` | standardized method to issue special commands to compiler ### Macros for `#define`, `#undef` and `#include` `#define` **can replace certain variables that are used often:** ```C #include <stdio.h> // macro definition #define LIMIT 5 int main() { for (int i = 0; i < LIMIT; i++) { printf("%d \n",i); } return 0; } ``` Output: ``` 0 1 2 3 4 ``` You could use `#undef` to undefine the macro. **Macro for simple function:** ```C #include <stdio.h> // macro with parameter #define AREA(l, b) (l * b) int main() { int l1 = 10, l2 = 5, area; area = AREA(l1, l2); printf("Area of rectangle is: %d", area); return 0; } ``` Similar to functions, the macro find for `AREA(l, b)` and passes `l` and `b` values to the macro and replace with `(l * b)`. **Include either header files or files from system libraries:** - program to calculate factorial: ```C #include <stdio.h> int fact(int a){ double mult = 1; for (int i = 1; i <= a; i++){ mult *= i; } return mult; } int fact_without_value(){ int a; scanf("%d",&a); double mult = 1; for (int i = 1; i <= a; i++){ mult *= i; } return mult; } ``` - program to calculate basic arithmetic operations: ```C #include <stdio.h> int addition(int a, int b){ return a+b; } int subtraction(int a, int b){ return a-b; } int multiplication(int a, int b){ return a*b; } float division(int a, int b){ if (b == 0){ return 0; } float c = a/(b*1.0); return c; } int remainders(int a, int b){ if (b == 0){ return 0; } int c = a % b; return c; } int arithmetics(int a){ for (int i = 0; i <= a; i++){ printf("sum: %d subtract: %d multiplication: %d division: %f remainder: %d\n",addition(a,i), subtraction(a,i), multiplication(a,i), division(a,i), remainders(a,i)); } } ``` - using `#include` to include the previous two files from system: ```C #include <stdio.h> #include "factorial.c" #include "arithmetic.c" int main(){ int n1; scanf("%d",&n1); printf("arithmetics of %d\n", arithmetics(n1)); arithmetics(n1); printf("Factorial of %d is %d\n", n1, fact(n1)); return 0; } ``` Output: ``` 5 sum: 5 subtract: 5 multiplication: 0 division: 0.000000 remainder: 0 sum: 6 subtract: 4 multiplication: 5 division: 5.000000 remainder: 0 sum: 7 subtract: 3 multiplication: 10 division: 2.500000 remainder: 1 sum: 8 subtract: 2 multiplication: 15 division: 1.666667 remainder: 2 sum: 9 subtract: 1 multiplication: 20 division: 1.250000 remainder: 1 sum: 10 subtract: 0 multiplication: 25 division: 1.000000 remainder: 0 arithmetics of 6 sum: 5 subtract: 5 multiplication: 0 division: 0.000000 remainder: 0 sum: 6 subtract: 4 multiplication: 5 division: 5.000000 remainder: 0 sum: 7 subtract: 3 multiplication: 10 division: 2.500000 remainder: 1 sum: 8 subtract: 2 multiplication: 15 division: 1.666667 remainder: 2 sum: 9 subtract: 1 multiplication: 20 division: 1.250000 remainder: 1 sum: 10 subtract: 0 multiplication: 25 division: 1.000000 remainder: 0 Factorial of 5 is 120 ``` ### Conditional Directives Conditional directives are a type of macros that helps to compile specific portions of the program based on some conditions: ```c #ifdef macro_name statement1; statement2; statement3; . . . statementN; #endif ``` **Using** `#if` **and** `#endif`: ```C #include <stdio.h> #if !defined (MESSAGE) #define MESSAGE "You wish!" #endif int main(){ printf("Here is the message: %s\n", MESSAGE); return 0; } ``` `!defined (MESSAGE)` here means that when `MESSAGE` is not defined, `#define MESSAGE "You wish!"` will be executed. ### Macro Continuation `\` and Stringize `#` Operator ```C #include <stdio.h> #define message_for(a, b) \ printf(#a " and " #b ": We love you!\n") int main(){ message_for(Alpha, Delta); return 0; } ``` Output: ``` Alpha and Delta: We love you! ``` `\` operator is used as an indicator that the macro is continued. This is done so to provide better readability for long macros. `#` operator replaces `a` and `b` with the strings `Alpha` and `Delta` to the `printf` macro ***enclosed with double quotes.* Note that all other strings have to be enclosed with double quotes when using this type of macro.** ### Token Pasting `##` `##` allows two separate tokens in the macro definition to be joined (concatenated) into a single token: ```C #include <stdio.h> #define tokenpaster(n) printf("token" #n " = %d", token##n) int main(){ int token34 = 40; tokenpaster(34); return 0; } ``` `##n` substitutes 34 to `token` as `token34` which is the same as the variable initialized in `main` function. **Since they're the same variables, the output can be printed out correctly:** ``` token34 = 40 ```