Note 01 Prep Work - [Homepage](http://gddh.github.io/)
====================
## Brief introduction to C
Why don’t people settle on the one best programming language and abandon all the others? One reason is that some languages are more “high-level” while others are more “low-level.” \[Note: In some contexts, people use the name “high-level” for everything other than a direct representation of the hardware’s native machine language. But in the present context, high-level and low-level both refer to compiled or interpreted languages.\] “High-level” is not a compliment, and “low-level” is not an insult.
<table>
<tr>
<th>level</th>
<th>language</th>
<th>best for</th>
</tr>
<tr>
<td>High</td>
<td>Scheme</td>
<td>applications and fast development</td>
</tr>
<tr>
<td>Mediuma</td>
<td>Java</td>
<td>applications, more optimization possible by "tuning hardware</td>
</tr>
<tr>
<td>low</td>
<td>C</td>
<td>operating systems and compilers</td>
</tr>
</table>
In a low-level language, the programmer is most aware of how the particular computer being used works; this places more burden on the programmer, but also allows more control over the precise way in which the computer carries out the computation. In a high-level language, the programmer works at a higher level of abstraction (this is where the names come from), with less need to know how this computer, or computers in general, perform tasks, and more able to focus on the problem being solved. This is why high-level languages are best for writing application programs (a word processor, a web browser, etc.), while low-level languages are best for those tasks in which knowledge of the hardware is part of the problem itself: operating systems and compilers.
**My understanding:**
- C allows the programmer to interact directly with the memory. If used properly, this can result in more efficient programs (in terms of memory and speed), but if used inproperly can result in vulnerable programs. (Vulnerable to "hackers")
- Further reading on C http://inst.eecs.berkeley.edu/~cs61c/resources/HarveyNotesC1-3.pdf
### Compilers and how a program is run
- Compilers: program that translates program into machine code (interpreted by machine)
- C program (foo.c) ---> **compiler (gcc)** ---> assembly program ---> **assembler** ---> object files (foo.o) ---> Linker ---> exectutable (a.out)
**Compiler input**: C program (High-Level Language Code)
**Compiler output**: Assembly Language Code (Very low level code - almost literal instructions on how the computer will execute the code)
The assembler and linker will basically process and put everything together (all your .o's and some libraries) and get the .o files ready to be run. They will ultimately output an a.out file, which is executable code that the OS will execute.
## Declarations and Definitions
Is ``int ft_strlen(char *str);`` a declaration or a definition?
Notice that we *declare* the return type of the function. We *declare* the name of the function to be `ft_strlen`. We `declare` the "input"/arguments of the function to take in a character pointer `char *str`. This statement doesn't *define* at all what the function will do.
1. A declaration tells the compiler what kind of thing it is dealing with. In other words, the compiler must figure out HOW to use this. When the compiler is changing the code into assembly, it will act depending on the type.
For example, x + y is code that will be converted to instructions, but the instructions for integer addition is different from the instructions for float addition.
Likewise, consider the declaration of `ft_strlen`. The declaration allows the compiler to understand how we will refer to the function, what the function will "return," and what the function needs for inputs.
The following is a function definition.
```
int ft_strlen(char *str)
{
int i;
i = 0;
while (str[i] != '\0')
i = i + 1;
return (i);
}
```
A **definition** also serves the purpose described above, but it also **allocates space**. Thus definitions actually serve two purposes.
2. In terms of function definition, we are allocating space for the machine instructions. When we do a definition for a variable, we allocate space for the variable. So. Memory! The amount memory required for integer, longs, char,... are all different.
I may be wrong, but I *think*
```
int x; is a definition and declaration.
x = 10; is an executable assignment.
```
It's also important to note that if you do
```
int x;
printf("%d\n", x);
```
The program will go to the memory that has been alotted for the variable `x` and print what is there, even though we've never assigned a value to `x`. In other words, it will print garbage. Be careful! If you don't explicitly initialize the value, your program will use garbage.
***The Take Away***: You need to tell C what types you are working with, so it can compile to the right instructions and allot the proper spaces.
## Data Types
C has some commonly used data types. Geeks for geeks puts it well:
**char:** The most basic data type in C. It stores a single character and requires a single byte of memory in almost all compilers.
**int:** As the name suggests, an int variable is used to store an integer.
**float:** It is used to store decimal numbers (numbers with floating point value) with single precision.
**double:** It is used to store decimal numbers (numbers with floating point value) with double precision.
Each data type will have an amount of space that will be alotted. For C, the amount of memory of each data type may depend on the system that you are using (i.e 64 bit or 32 bit).
Consider a `char` type or a character, which in C is defined to be 1 byte. Notice the difference between `char` type and `unsigned char` type. A quick google search will show the range of `char` type to be -128 to 127. For our purposes we can ignore the negatives. Now if you `man ascii`, you will find that the ascii characters are represented by 0 to 127! Meaning that in 1 byte, we can represent any ascii character. This will be explained in more detail on day03 materials.
## Variable Assignments
A variable is a name for a storage area that we can use. As discussed, each variable has a type, which determines the size and layout of the variable's memory; the range of values that can be stored within that memory; and the set of operations that can be applied to the variable.
https://www.tutorialspoint.com/cprogramming/c_variables.htm
Consider the following:
```
char c; # Alot 1 byte of space for characters and we will call this space c.
int x; # Alot space for integers and call this space x.
c = 'a'; In the space we call c, we will put the value 'a' (which represents 97 - ascii).
x = 0; In the space we call x, we will put the value 0.
```
Notice that the assignment operator is different from the mathematical statement equal sign. In assignment, I like to think about it as the value on the right of the equal sign is going into the value on the left.
## Basic Function Calls.
Go to http://www.pythontutor.com/visualize.html#mode=edit and make sure you are using C in the drop down.
Let's say I have the following functions
```
int ft_add(int a, int b)
{
return (a + b);
}
int main(void)
{
int x;
int y;
int res;
x = 40;
y = 2;
res = ft_add(x, y);
return (0);
}
```
**Things to note**
- At the beginning, we will assign the initial value of `x` and `y`, or *initialize* the values of `x` and `y`.
- Then when we hit the line ```res = ft_add(x, y);```, we will *evaluate* ```ft_add(x, y)``` first because we want to put that value into ```res```. In other words, we want to, assign the value that ```ft_add(x, y)``` returns, to ```res```.
- Another way of saying what's going on is, the `main` made a function call to `ft_add`.
- The value that ```ft_add(x, y)``` returns is the result of what is called a function call. This is why you will see a blue box on the right side. The blue box is another frame that is created so that the computer can do the function ```ft_add```.
- Focusing on the function call. Notice how the values of x and y are copied and assigned to the values of a and b in the new frame.
- a + b is then evaluated and then returned by the function ```ft_add```. The result of a + b, which is 42, is returned to where the function was called in main. We can thus assign 42 to res.
- Notice how the frame that was used to evaluate a + b disappeared after the function call. This will happen to most variables, and can be avoided by allocating memory through ```malloc```.
Now try to think about the following in terms of stack frames. It would be great if you could actually draw out on paper what the visualization would be without actually looking at the visualization.
```
int ft_add(int a, int b)
{
return (a + b);
}
int ft_mult(int c, int d)
{
return (c * d);
}
int ft_mult2(int e, int f)
{
return (e * f);
}
int main(void)
{
int x;
int y;
int res;
x = 3;
y = 7;
res = ft_add(ft_mult(x, y), ft_mult2(x, y));
return (0);
}
```
Make sure you understand what is going on above. If you could teach it to someone it would mean you've mastered the material.
Some more practice.
```
int ft_add(int a, int b)
{
return (a + b);
}
int ft_mult(int c, int d)
{
int i;
int total;
i = 0;
total = 0;
while (i < d)
{
total = ft_add_helper(total, c);
i = i + 1;
}
return (total);
}
int ft_add_helper(int e, int f)
{
return (e + f);
}
int main(void)
{
int x;
int y;
int res;
x = 7;
y = 2;
res = ft_add(ft_mult(x, y), 2);
return (0);
}
```
Notice that I called a ft_add_helper inside another ft_mult. It will be very helpful if you can
# PRACTICE PROBLEMS
SAVE ALL OF YOUR CODE AND SEND IT TO ME.
1. Write a function called ft_swap to swap two integers. It should take in two int pointers and swap the values of the respective pointers.
2. Write ```void ft_putchar(char c)```;
3. Write ```void ft_putstr(char *str)```;
4. Write ```int ft_strlen(char *str)```;
5. Find the similarities between ```ft_putstr``` and ```ft_strlen```.
5. Solve the following problem by writing the following functions: https://github.com/gcamerli/examshell/tree/master/level0/aff_a
```
#include _____________
_______ ft_putchar(________)
{
___________________________;
}
void ft_aff_a(char *str)
{
FILL ME IN;
}
int main(int argc, char **argv)
{
if (argc == _____)
{
ft_aff_a(argv[1]);
}
else
{
ft_putchar(______);
}
ft_putchar('\n');
}
```
7. Solve this problem with the following main. You must also use a while loop and can only use three ft_putchar.
https://github.com/gcamerli/examshell/blob/master/level0/maff_alpha/subject.en.txt
```
int main(void)
{
maff_alpha();
ft_putchar('\n');
}
```
8. Solve this problem with the following main. You must also use a while loop and can only use three ft_putchar.
https://github.com/gcamerli/examshell/blob/master/level0/maff_revalpha/subject.en.txt
```
int main(void)
{
maff_revalpha();
ft_putchar('\n');
}
```
9. Write a program that displays "Hello world!" followed by a new line. The only allowed function is "Write". You can only have a function call in your main. In other words your main must look like:
```
int main(void)
{
hello_world();
}
```
10. Explain how you would solve the following question. Try to find a mathematical relationship. If you cannot. Skip it. But try. https://github.com/gcamerli/examshell/blob/master/level1/rotone/subject.en.txt
11. Solve the problem by filling in the following functions. https://github.com/gcamerli/examshell/blob/master/level1/repeat_alpha/repeat_alpha.c
```
#include _________________
void ft_putchar(char c)
{
_______________________;
}
void ft_repeat_char(char c)
{
int times_repeat;
times_repeat = _______________;
if (c >= 'a' && c <= 'z')
times_repeat = ______________________________;
else if (_____________________)
times_repeat = ______________________________;
while (times_repeat > 0)
{
_______________________________;
times_repeat = times_repeat - 1;
}
}
void ft_repeat_alpha(char *str)
{
int i;
i = 0;
while (str[i] != '\0')
{
_____________________;
i = i + 1;
}
}
int main(int argc, char **argv)
{
if (_____________)
{
____________________________;
}
_______________;
return (0);
}
```
12. Solve this with a while loop. https://github.com/gcamerli/examshell/tree/master/level1/ft_print_numbers
13. Solve with the following main https://github.com/gcamerli/examshell/blob/master/level1/rev_print/rev_print.c
```
int main(int argc, char **argv)
{
if (__________________)
{
____________________________;
}
___________________________________;
}
```
14. Explain what a string is. This includes what an array, a character, and the null terminator. You should be able to illustrate it.
Redo all problems without the skeleton code. Meaning redo all the problems starting from 1 without any of the code I've given you.
By the end of your practicing, you should be able to:
1. Explain how each of your functions work.
2. Solve any of the questions at a moments notice.
3. Teach someone who has **very** basic knowledge of programming what is going on.
--------------------------------------
------------------------------
-------------------------------
--------------------------------
# Solutions
1. Ft_swap
```
void ft_swap(int *x, int *y)
{
int tmp;
tmp = *X;
*x = *y;
*y = tmp;
}
```
2. ft_putchar
```
#include <unistd.h>
void ft_putchar(char c)
{
write(1, &c, 1);
}
```
3. ft_putstr
```
void ft_putstr(char *str)
{
int i;
i = 0;
while (*(str + i) != '\0') <- it is also possible to write as str[i]
{
ft_putchar(*(str + i));
i = i +1;
}
}
```
4. ft_strlen
```
void ft_strlen(char *str)
{
int i;
i = 0;
while (str[i] != '\0')
{
i = i + 1;
}
return (i);
}
```
5. The key thing to notice is the structure between the two functions. They both:
- take in a String in the form of a character pointer
- Iterate through the string. This is a very fundamental technique that you must become familiar with. There isn't an official name, but I call it string traversal. How to traverse a string. Many of the exam questions will ask you to do this, whether it be to rotate each character, to find a letter... You will need to iterate through the string to do it.
- Both initialize an int `i` as the index of the string. We start at 0 in both these cases, but we don't necessarily have to.
6. ft_aff_a. I use *(str + i), but you can use str[i]. *(str + i) means I am going to dereference str + i to get its value. Remember str is an address to the beginning of the string or character array. We add i to the address to offset the address by the element we want. C will figure out that you are manipulating address and offset it according to the size of each element. * means you will "dereference".
**Dereferencing** a pointer means using the * operator (asterisk character) to access the value stored at a pointer: NOTE: The value stored at the address of the pointer must be a value OF THE SAME TYPE as the type of variable the pointer "points" to, but there is **no guarantee** this is the case unless the pointer was set correctly. The type of variable the pointer points to is the type less the outermost asterisk. (stolen from stack overflow)
```
#include <unistd.h>
void ft_putchar(char c)
{
write(1, &c, 1);
}
void ft_aff_a(char *str)
{
int i;
int has_a;
i = 0;
has_a = 0;
while(*(str + i) != '\0') /*
{
if (*(str + i) == 'a')
has_a = 1;
i = i + 1;
}
if (has_a == 1)
ft_putchar('a');
}
int main(int argc, char **argv)
{
if (argc == 2)
{
ft_aff_a(argv[1]);
}
else
{
ft_putchar('a');
}
ft_putchar('\n');
}
```
**Note the string traversal**
7. Maff_alpha
```
#include <unistd.h>
void ft_putchar(char c)
{
write(1, &c, 1);
}
void maff_alpha()
{
char a;
char b;
a = 'a';
b = 'B';
while (a <= 'y' && b <= 'Z')
{
ft_putchar(a);
ft_putchar(b);
a = a + 2;
b = b + 2;
}
}
int main(void)
{
maff_alpha();
ft_putchar('\n');
}
```
8. The following is just as valid.
```
#include <unistd.h>
void ft_putchar(char c)
{
write(1, &c, 1);
}
int main(void)
{
char a;
char b;
a = 'z';
b = 'Y';
while (a >= 'a' && b >= 'A')
{
ft_putchar(a);
ft_putchar(b);
a -= 2;
b -= 2;
}
ft_putchar('\\n');
return (0);
}
```
9. Hello World. Note how we could have easily done this with a write command. Never forget that, because in certain cases that is what you want to do. Here, I've forced you to get familiar with function calls and ft_putstr. Personally I like doing this because it forces me to
- review
- become very familiar with functions that I'll use over and over again. By the exam, I'll be typing these up very naturally and when I'm problem solving, I will always be able to easily (for example) find a the length of a string.
```
#include <unistd.h>
void ft_putchar(char c)
{
write(1, &c, 1);
}
void ft_putstr(char *str)
{
int i;
i = 0;
while(str[i] != '\0')
{
ft_putchar(str[i]);
i = i + 1;
}
}
void hello_world(void)
{
ft_putstr("Hello world!");
}
int main(void)
{
hello_world();
}
```
10. You will notice that I use the function to break down the logical steps I need to do. I believe in doing this, we wil make less mistakes and our logic becomes clearer. We can also reuse certain functions in other scenarios. I will go over in more detail the benefits of using functions.
```
# include <unistd.h>
void ft_putchar(char c)
{
write(1, &c, 1);
}
char calc_rotation(char c, int rotate_by, char start)
{
c = c - start;
c = c + rotate_by;
c = c % 26;
c = c + start;
return (c);
}
void rotate_char(char c, int rotate_by)
{
if (c >= 'A' && c <= 'Z')
c = calc_rotation(c, rotate_by, 'A');
else if (c >= 'a' && c <= 'z')
c = calc_rotation(c, rotate_by, 'a');
ft_putchar(c);
}
void rotate_str(char *str, int rotate_by)
{
int i;
i = 0;
while(str[i] != '\0')
{
rotate_char(str[i], rotate_by);
i = i + 1;
}
}
int main(int argc, char **argv)
{
if (argc == 2)
{
rotate_str(argv[1], 1);
}
ft_putchar('\n');
}
```
Note how rotate_str has the exact same form as ft_strlen and ft_putchar. It's string traversal! I'm going to traverse the string and rotate each character by a certain amount.
In rotate char, I will determine whether a character needs to be rotated and rotate each character if it necessary.
In calc_rotate, I will do the actual calculation required to rotate alphabetical characters.
11.
```
#include <unistd.h>
void ft_putchar(char c)
{
write(1, &c, 1);
}
void ft_repeat_char(char c)
{
int times_repeat;
times_repeat = 1;
if (c >= 'a' && c <= 'z')
times_repeat = c - 'a' + times_repeat;
else if (c >= 'A' && c <= 'Z')
times_repeat = c - 'A' + times_repeat;
while (times_repeat > 0)
{
ft_putchar(c);
times_repeat = times_repeat - 1;
}
}
void ft_repeat_alpha(char *str)
{
int i;
i = 0;
while (str[i] != '\0')
{
ft_repeat_char(str[i]);
i = i + 1;
}
}
int main(int argc, char **argv)
{
if (argc == 2)
{
ft_repeat_alpha(argv[1]);
}
ft_putchar('\n');
return (0);
}
```
Notice that ft_repeat_alpha has the exact form as ft_strlen and ft_putstr. Also note the similarities between this and calc_rotate.
12. ft_print_numbers
```
#include <unistd.h>
void ft_putchar(char c)
{
write(1, &c, 1);
}
void ft_print_numbers()
{
char c;
c = 48
while (c <= 57)
{
ft_putchar(c);
c = c + 1;
}
}
```
Why 48 and 57? Because the character 0 and the character 9 has the ascii value of 48 and 57 respectively. This means that the numerical value 48 in a space for characters will be interpreted to mean 0. Likewise for 57 and 9.
13. rev_print
```
#include <unitstd.h>
void ft_putchar(char c)
{
write(1, &c, 1);
}
void rev_print(char *str)
{
int i;
i = 0;
while (str[i] != '\0')
{
i = i + 1;
}
i = i - 1;
while (i >= 0)
{
ft_putchar(str[i]);
i = i - 1;
}
}
int main(int argc, char **argv)
{
if (argc == 2)
{
rev_print(argv[1]);;
}
ft_putchar('\n');
}
```
14. Refer to day 2 material