Update tuto

This commit is contained in:
Miloslav Ciz 2022-04-02 15:24:29 +02:00
parent 4f4dedf443
commit d4d83bf6c1

View file

@ -1,6 +1,6 @@
# C Tutorial
This is a relatively quick [C](c.md) tutorial.
This is a relatively quick WIP [C](c.md) tutorial.
You should probably know at least the completely basic ideas of programming before reading this (what's a [programming language](programming_language.md), [source code](source_code.md), [command line](cli.md) etc.). If you're as far as already knowing another language, this should be pretty easy to understand.
@ -96,8 +96,6 @@ int main(void)
}
```
## TO BE CONTINUED
## Variables, Arithmetic, Data Types
Programming is a lot like mathematics, we compute equations and transform numerical values into other values. You probably know in mathematics we use *variables* such as *x* or *y* to denote numerical values that can change (hence variables). In programming we also use variables -- here **[variable](variable.md) is a place in memory which has a name**.
@ -157,6 +155,14 @@ int main(void)
calculates and prints your BMI (body mass index).
Let's quickly mention how you can read and write values in C so that you can begin to experiment with your own small programs. You don't have to understand the following [syntax](syntax.md) as of yet, it will be explained later, now simply copy-paste the commands:
- `puts("hello");`: Prints a text string with newline.
- `printf("hello");`: Same as above but without newline.
- `printf("%d\n",x);`: Prints the value of variable `x` with newline.
- `printf("%d ");`: Same as above but without a newline.
- `scanf("%d",&x);`: Read a number from input to the variable `x`. Note there has to be `&` in front of `x`.
## Branches and Loops
When creating [algorithms](algorithm.md), it's not enough to just write linear sequences of commands. Two things (called [control structures](control_structure.md)) are very important to have in addition:
@ -194,7 +200,7 @@ X is not greater than 10.
And it is also smaller than 5.
```
A note on **conditions** in C: a condition is just an expression (variables along with arithmetic operators). The expression is evaluated (computed) and the number that is obtained is interpreted as *true* or *false* like this: in C 0 means false and anything non-0 means true. Even comparison operators like `<` and `>` are technically arithmetic, they compare numbers and yield either 1 or 0.
A note on **conditions** in C: a condition is just an expression (variables/functions along with arithmetic operators). The expression is evaluated (computed) and the number that is obtained is interpreted as *true* or *false* like this: in C 0 means false and anything non-0 means true. Even comparison operators like `<` and `>` are technically arithmetic, they compare numbers and yield either 1 or 0.
Next we have **loops**. There are multiple kinds of loops even though in theory it is enough to only have one kind of loop (there are multiple types out of convenience). The loops in C are:
@ -328,6 +334,164 @@ int main(void)
## Functions
Functions are extremely important, no program besides the most primitive ones can be made without them.
**[Function](function.md) is a subprogram** (in other languages functions are also called procedures or subroutines), i.e. it is code that solves some smaller subproblem that you can repeatedly invoke, for instance you may have a function for computing a [square root](sqrt.md), for encrypting data or for playing a sound from speakers. We have already met functions such as `puts`, `printf` or `rand`.
Functions are similar to but **NOT the same as mathematical functions**. Mathematical function (simply put) takes a number as input and outputs another number computed from the input number, and this output number depends only on the input number and nothing else. C functions can do this too but they can also do additional things such as modify variables in other parts of the program or make the computer do something (such as play a sound or display something on the screen) -- these are called **[side effects](side_effect.md)**; things done besides computing and output number from an input number. For distinction mathematical functions are called *pure* functions and functions with side effects are called non-pure.
**Why are function so important?** Firstly they help us divide a big problem into small subproblems and make the code better organized and readable, but mainly they help us respect the [DRY](dry.md) (*Don't Repeat Yourself*) principle -- this is extremely important in programming. Imagine you need to solve a [quadratic equation](quadratic_equation.md) in several parts of your program; you do NOT want to solve it in each place separately, you want to make a function that solves a quadratic equation and then only invoke (call) that function anywhere you need to solve your quadratic equation. This firstly saves space (source code will be shorter and compiled program will be smaller), but it also makes your program manageable and eliminates bugs -- imagine you find a better (e.g. faster) way to solving quadratic equations; without functions you'd have to go through the whole code and change the algorithm in each place separately which is impractical and increases the chance of making errors. With functions you only change the code in one place (in the function) and in any place where your code invokes (calls) this function the new better and updated version of the function will be used.
Besides writing programs that can be directly executed programmers write **[libraries](library.md)** -- collections of functions that can be used in other projects. We have already seen libraries such as *stdio*, *standard input/output library*, a standard (official, bundled with every C compiler) library for input/output (reading and printing values); *stdio* contains functions such as `puts` which is used to printing out text strings. Examples of other libraries are the standard *math* library containing function for e.g. computing [sine](sine.md), or [SDL](sdl.md), a 3rd party multimedia library for such things as drawing to screen, playing sounds and handling keyboard and mouse input.
Let's see a simple example of a function that writes out a temperature in degrees of Celsius and well as in Kelvin:
```
#include <stdio.h>
void writeTemperature(int celsius)
{
int kelvin = celsius + 273;
printf("%d C (%d K)\n",celsius,kelvin);
}
int main(void)
{
writeTemperature(-50);
writeTemperature(0);
writeTemperature(100);
return 0;
}
```
The output is
```
-50 C (223 K)
0 C (273 K)
100 C (373 K)
```
Now imagine we decide we also want our temperatures in Fahrenheit. We can simply edit the code in `writeTemperature` function and the program will automatically be writing temperatures in the new way.
Let's see how to create and invoke functions. Creating a function in code is done between inclusion of libraries and the `main function`, and we formally call this **defining a function**. The function definition format is following:
```
RETURN_TYPE FUNCTION_NAME(FUNCTION_PARAMETERS)
{
FUNCTION_BODY
}
```
- `RETURN_TYPE` is the [data type](data_type.md) the function returns. A function may or may not return a certain value, just as the pure mathematical function do. This may for example be `int`, if the function returns an integer number. If the function doesn't return anything, this type is `void`.
- `FUNCTION_NAME` is the name of the function, it follows the same rules as the names for variables.
- `FUNCTION_PARAMETERS` specifies the input values of the function. The function can take any number of parameters (e.g. a function `playBeep` may take 0 arguments, `sine` function takes 1, `logarithm` may take two etc.). This list is comma-separated and each item consists of the parameter data type and name. If there are 0 parameters, there should be the word `void` inside the brackets, but compilers tolerate just having empty brackets.
- `FUNCTION_BODY` are the commands executed by the function, just as we know them from the *main* function.
Let's see another function:
```
#include <stdio.h>
int power(int x, int n)
{
int result = 1;
for (int i = 0; i < n; ++i) // repeat n times
result = result * x;
return result;
}
int main(void)
{
for (int i = 0; i < 5; ++i)
{
int powerOfTwo = power(2,i);
printf("%d\n",powerOfTwo);
}
return 0;
}
```
The output is:
```
2
4
8
16
```
The function power takes two parameters: `x` and `n`, and returns `x` raised to the `n`s power. Note that unlike the first function we saw here the return type is `int` because this function does return a value. **Notice the command `return`** -- it is a special command that causes the function to terminate and return a specific value. In function that return a value (their return type is not `void`) there has to be a `return` command. In function that return nothing there may or may not be one, and if there is, it has no value after it (`return;`);
Let's focus on how we invoke the function -- in programming we say we **call the function**. The function call in our code is `power(2,i)`. If a function returns a value (return type is not `void`), it function call can be used in any expression, i.e. almost anywhere where we can use a variable or a numerical value -- just imagine the function computes a return value and this value is **substituted to the place where we call the function**. For example we can imagine the expression `power(3,1) + power(3,0)` as simply `3 + 1`.
If a function return nothing (return type is `void`), it can't be used in expressions, it is used "by itself"; e.g. `playBeep();`. (Function that do return a value can also be used like this -- their return value is in this case simply ignored.)
We call a function by writing its name (`power`), then adding brackets (`(` and `)`) and inside them we put **arguments** -- specific values that will substitute the corresponding parameters inside the function (here `x` will take the value `2` and `n` will take the current value of `i`). If the function takes no parameters (the function list is `void`), we simply put nothing inside the brackets (e.g. `playBeep();`);
Here comes the nice thing: **we can nest function calls**. For example we can write `x = power(3,power(2,1));` which will result in assigning the variable `x` the value of 9. **Functions can also call other functions** (even themselves, see [recursion](recursion.md)), but only those that have been defined before them in the source code (this can be fixed with so called [forward declarations](forward_decl.md)).
Notice that the `main` function we always have in our programs is also a function definition. The definition of this function is required for runnable programs, its name has to be `main` and it has to return `int` (an error code where 0 means no error). It can also take parameters but more on that later.
These is the most basic knowledge to have about C functions. Let's see one more example with some pecularities that aren't so important now, but will be later.
```
#include <stdio.h>
void writeFactors(int x) // writes divisord of x
{
printf("factors of %d:\n",x);
while (x > 1) // keep dividing x by its factors
{
for (int i = 2; i <= x; ++i) // search for a factor
if (x % i == 0) // i divides x without remainder?
{
printf(" %d\n",i); // i is a factor, write it
x = x / i; // divide x by i
break; // exit the for loop
}
}
}
int readNumber(void)
{
int number;
puts("Please enter a number to factor (0 to quit).");
scanf("%d",&number);
return number;
}
int main(void)
{
while (1) // infinite loop
{
int number = readNumber(); // <- function call
if (number == 0) // 0 means quit
break;
writeFactors(number); // <- function call
}
return 0;
}
```
We have defined two functions: `writeFactors` and `readNumber`. `writeFactors` return no values but it has side effects (print text to the command line). `readNumber` takes no parameters but return a value; it prompts the user to enter a value and returns the read value.
Notice that inside `writeFactors` we modify its parameter `x` inside the function body -- this is okay, it won't affect the argument that was passed to this function (the `number` variable inside the `main` function won't change after this function call). `x` can be seen as a **[local variable](local_variable.md)** of the function, i.e. a variable that's created inside this function and can only be used inside it -- when `writeFactors` is called inside `main`, a new local variable `x` is created inside `writeFactors` and the value of `number` is copied to it.
Another local variable is `number` -- it is a local variable both in `main` and in `readNumber`. Even though the names are the same, these are two different variables, each one is local to its respective function (modifying `number` inside `readNumber` won't affect `number` inside `main` and vice versa).
And a last thing: keep in mind that not every command you write in C program is a function call. E.g. control structures (`if`, `while`, ...) and special commands (`return`, `break`, ...) are not function calls.
## Header Files, Libraries, Compilation
## Advanced Data Types
@ -336,7 +500,7 @@ int main(void)
## Pointers
## Recursion
## More on Functions
## Dynamic Allocation