class: center, middle ### COMP26020 Programming Languages and Paradigms -- Part 1 *** # Variables, Types, Printing to the Console ??? - Hello everyone. - In this video we are going to talk about variables, types, and printing to the console in C. --- class: middle, center, inverse # Variables ??? - Let's start with variables --- name: variables # Variables ```c #include
int main() { int a; // declare local variable a of type int (signed integer) a = 12; // set the value of a to 12 printf("a's value: %d\n", a); // print the value of a return 0; } ``` .codelink[
`04-c-variables-types-printf/variables-1.c`
] - Variable: **name**, **type**, **value** - Must be **declared** before being used - Declare with `
;` ??? - Here is an example of C code with a main function using a local variable named `a`. - The variable is set to 12 and then printed to the standard output. - Don't worry about `printf` parameters yet, you'll understand it clearly by the end of this video. - Variables have a name -- here it's `a`. - Variables also have a type, here it's `int` corresponding to a signed integer. - Finally, variables have a value, which can generally evolve as the program executes. - Before being able to use a variable, it must first be declared. - Declaration defines the name and type of the variable. - Here we declare `a` in the first line of code of the main function. --- template: variables ```c int _x; // variable names should start with a letter or underscore int sum; int final_balance2; // it can contain a combination of letters/numbers/underscores int a_long_variable_name_is_also_possible_but_not_very_practical; ``` ??? - In C a variable name should start with a letter or underscore and contain a combination of letters, underscores, numbers. - These are a few example of variable names. - Try to be descriptive, for example here sum or final_balance2 are much more meaningful than just a. --- template: variables .leftcol[ ```c int a; int b; int c; int d = 12; // declare and set int x, y = 10, z = 11; // declare x, y and z, // set y and z a = 12; // set a to 12 ``` ] .rightcol[ ```c b = 20; // set b to 20 c = 10 + 10; // set c to 20 a = b; // a = 20 d++; // d = d + 1 y *= 2 // y = y * 2; // ``` .codelink[
`04-c-variables-types-printf/variables-2.c`
] ] ??? - Here are a few examples of variables usage. - We first declare 3 integers a, b and c. - A variable can be declared and set in one statement, this is what happens to d. - On the third line we declare x, y and z and we also set the value of y to be 10 and the value of z to be 11. - On the code on the right we have an example of arithmetic operation, setting the value of C to ten plus 10. - We also set the value of a to be the value of b. - And we also have some nice shortcuts for commonly used operations. - For example by using d++ we effectively increment d by 1. - Also, y multiplied by equal 2 corresponds to multiplying y by two and storing the result in y. - Note that you have a similar construct for addition, subtraction and division. --- class: middle, inverse, center # Types ??? - Now let's talk a bit about types. --- # Types Types are used by the compiler for 2 things: - The type define the **amount of space in memory** allocated for a variable by the compiler - At build time, the compiler **checks the validity of operations** on the variable based on its type ??? - Each variable must have a type. - Types are used by the compiler to do two things. - First, allocate the memory space for the variable. - Each type defines a given size in bytes for this. - Second, the compiler performs some checks on the operations realised on the variable. - For example in some cases it is able to warn about overflows when you try to store a number larger than the size of the target variable type. -- .center[**3 basic types categories: integers, floating-point numbers, characters**] ??? - There are 3 basic types categories: integers, floating-point numbers, characters --- # Types ```c int a; // signed integer takes 4 bytes in memory on the Intel x86-64 architecture a = -12345; ``` At runtime:
??? - Here is an illustration. - We declare an integer variable a and sets its value. - At runtime you can see the program's memory as a gigantic array of bytes. - The int type, on the x86-64 architecture that most of our laptop/desktop computers are using, int is 4 bytes long. - So the compiler reserves 4 bytes in memory for a, that will be used to store its value at runtime. --- # Types Characters and floats: ```c char my_char_variable; float my_float_variable; my_char_variable = 'x'; // use single quotes for characters my_float_variable = 12.4; ``` ??? - Other types include characters and floating point numbers. - We use the char type for characters and we can describe a character, here x, with single quotes. --- # Types Arithmetics mixing integers and floats: ```c int int1 = 2, int2 = 4; float float1 = 2.8; /* when mixed with floats in arithmetics, integers are promoted to floats */ float float_res = int1 + float1; // float_res: 4.8 float float_res2 = int1 * (float1 + int2); // float_res2: 13.6 /* when stored in an integer variable, floats are _truncated_ */ int int_res = int1 * (float1 + int2); // int_res: 13 printf("float result: %f\n", float_res); printf("float result2: %f\n", float_res2); printf("integer result: %d\n", int_res); ``` .codelink[
`04-c-variables-types-printf/types.c`
] ??? - When performing an arithmetic operation on an integer and a float, the compiler will promote the result to a float. - For example here float_res will include a decimal part. - I give a second example with float_res2 to illustrate the use of the parentheses to set the order of evaluation. - Finally, even if the right hand side is promoted to a float in the assignment of int_res, because of its type -- int --, it will the result will be truncated. --- # More Types, Qualifiers - Types: `char`, `int`, `float` (single precision), `double` (double precision) - Integer qualifiers: `signed` (positive and negative integers), `unsigned` (only positive integers), `short` (smaller), `long` (larger) - Determines the **storage size in memory** ```c short int a; // signed, at least 16 bits: [−32,767, +32,767] int b; // signed, at least 16 bits: [−32,767, +32,767] unsigned int c; // unsigned: [0, +65,535] long int d; // at least 32 bits: [−2,147,483,647, +2,147,483,647] unsigned long int e; // unsigned: [0, +4,294,967,295] long long int f; // at least 64 bits: [-9x10^18, +9x10^18] long long unsigned int g; // unsigned: [0, +18x10^18] float h; // storage size unspecified, generally 32 bits double i; // storage size unspecified, generally 64 bits ``` - Exact implementation is **architecture dependent** - Complete list here: https://en.wikipedia.org/wiki/C_data_types ??? - When declaring a variable, we use a combination of a type and optional qualifiers, that will define what the variable can hold and how much space is reserved. - It is very important to be aware of the storage size of your variables, as things like overflows can have very nasty consequences. - Here are a few examples with the information that the C standard gives you about the corresponding storage sizes. - For example int is signed and should be at least 2 bytes so it can store numbers from minus 32 thousands to plus thirty two thousands. - Unsigned int has the same size and is unsigned so it can store more positive numbers. - You'll note that the storage size information coming from the standard are rather imprecise. - The actual sizes depend on the architecture of the CPU you are compiling to execute upon. --- # Types - The function `sizeof` can be used to get the exact size of a type on a given machine ```c int so_short = sizeof(short int); int so_int = sizeof(int); int so_uint = sizeof(unsigned int); int so_long = sizeof(long int); int so_longlong = sizeof(long long int); int so_float = sizeof(float); int so_double = sizeof(double); printf("size of short: %d bytes\n", so_short); printf("size of int: %d bytes\n", so_int); printf("size of unsigned int: %d bytes\n", so_uint); printf("size of long int: %d bytes\n", so_long); printf("size of long long int: %d bytes\n", so_longlong); printf("size of float: %d bytes\n", so_float); printf("size of double: %d bytes\n", so_double); ``` .codelink[
`04-c-variables-types-printf/sizeof.c`
]
??? - To get the exact storage size we can use the sizeof function, that takes a type as parameter. - We can compile and run it like this, and we see that: - the size of short is 2 bytes - the sizes int, unsigned int as well as float are 4 bytes - the sizes of long, long long int, and double is 8 bytes. - So in memory these variables will look somehow like this. - 2 bytes for the short, 4 for the int, and so on. --- class: center, middle, inverse # Printing to the Console: printf ??? - We have been using printf to print a lot of things to the console, let's see how it works more in details. --- # Printing to the Console - `printf` accepts **one or more arguments**: - Format string (mandatory) - Optionally a list of variables which values should be printed, replacing markers (e.g. `%d` in the format string) .leftcol[ ```c int int_var = -1; unsigned int uint_var = 12; long int lint_var = 10; float float_var = 2.5; double double_var = 2.5; char char_var = 'a'; char string_var[] = "hello"; // ``` ] .rightcol[ ```c printf("Integer: %d\n", int_var); printf("Unsigned integer: %u\n", uint_var); printf("Long integer: %ld\n", lint_var); printf("Float: %f\n", float_var); printf("Double: %lf\n", double_var); printf("Characters: %c\n", char_var); printf("String: %s\n", string_var); printf("Several variables: %d, %lf, %s\n", int_var, double_var, string_var); // ``` .codelink[
`04-c-variables-types-printf/printf.c`
] ] - Format string accepts escaped characters such as `\n` for line break - See [here](https://linux.die.net/man/3/printf) for a list of all markers/modifiers ??? - It takes one or more arguments. - The first argument is the format string containing the text to print as well as optional markers that will be replaced with variables' values - The next arguments are optional and it is the list of variables which value needs to be printed, 1 variable per argument - The format string marker to use depends on the corresponding variable type. - You can see a few examples on the slide. - percentage d is used for signed integers, percentage u for unsigned ones. - You use percentage l to indicate the long qualifiers, for example we have percentage ld for a signed long int. - You can use percentage f for floats and percentage lf for doubles. - Finally, notice the declaration of a string with the brackets for the variable name and the double quotes for the string itself. - We can print it with percentage s. --- # Printing to the Console (2) - Make sure to use the right marker! - In most situations the compiler won't tell you if you make a mistake and incorrect values will be displayed at runtime ```c int my_variable = -42; printf("-42 printed with %%d: %d\n", my_variable); printf("-42 printed with %%u: %u\n", my_variable); // -42 interpreted as an unsigned integer unsigned long long int ull = 5467513055454315; printf("5467513055454315 printed with %%llu: %llu\n", ull); printf("5467513055454315 printed with %%u: %u\n", ull);// interprets only 4 bytes vs. 8 for llu printf("5467513055454315 printed with %%d: %d\n", ull);// first 4 bytes, as unsigned // ``` .codelink[
`04-c-variables-types-printf/printf-bugs.c`
] --- # Summary - Variables - Types - `printf` ---- .center[Feedback form: https://bit.ly/2VslNaB]
??? - So let's recap. - We have seen how to declare and use variables. - Variables can be of different types that will define the size of their storage location in memory, something that is important to keep in mind. - Finally, we saw how printf can be used to print to the standard output. - In the next video, we will talk about arrays, strings, and the program command line arguments.