int main(int argc, char** argv) {
// Your program goes here.
// Say hello.
printf("Hello world!\n");
// Print out argc, the count of the program arguments
printf("There are %d arguments.\n", argc);
// What's the first argument?
printf("The first argument is %s.\n", argv[0]);
// Return something.
return 123;
}
```
Compile with: `gcc example1.c -o example1`
Run with: ./example1
---
## Formats
* printf uses the % tokens to determine what to print
* See [https://cppreference.com/w/c/io/fprintf.html](https://cppreference.com/w/c/io/fprintf.html)
* `%d` and `%i` print signed integers
* `%ld` and `%li` are `long` versions, holding larger numbers
* `%c` is a single character
* `%s` is a string
* `%f` is a floating point number
* `%.3f` would print with 3 digits of precision
* `%p` is a pointer
---
## More `printf`
```C
/*
* This is an example program!
* To compile code:
* gcc example4.c -o example
*/
#include
int main(int argc, char** argv) {
printf("The name of the program is %s\n", argv[0]);
printf("The first character of the program name is %c\n", argv[0][0]);
printf("The first argument is %s\n", argv[1]);
printf("The first character of the second argument is %c\n", argv[1][0]);
float pi = 3.14159265358979;
printf("Pi is about %f, or simply %.3f\n", pi, pi);
printf("The first and second arguments are at %p and %p\n", argv[0], argv[1]);
return argc;
}
```
-v-
```
$ ./a.out test
The name of the program is ./a.out
The first character of the program name is .
The first argument is test
The first character of the second argument is t
Pi is about 3.141593, or simply 3.142
The first and second arguments are at 0x7fff82006545 and 0x7fff8200654d
```
-v-
```
$ ./././././a.out test
The name of the program is ./././././a.out
The first character of the program name is .
The first argument is test
The first character of the second argument is t
Pi is about 3.141593, or simply 3.142
The first and second arguments are at 0x7ffc49b1952d and 0x7ffc49b1953d
```
* `./` just means `current directory` in your shell
* So you can repeat it as many times as you like
---
## What is a string in C?
* The argument vector is an array of strings
* A string is an array of characters
* Each string ends with a special, null character
* Value of 0
* Written `\0`
* Use `man ascii` on linux to see all ASCII characters
* Or see the [cppreference example](https://cppreference.com/w/c/language/ascii.html)
---
## Array Access
* Pointers are numbers that refer to memory locations
* e.g. 0x7fff82006545
* Those memory locations are arbitrary on your computer
* The OS chooses an arbitrary range for a program
* This allows for virtual memory, swap, virtual machines, etc
* Not an OS course, so we'll leave it at that
* On an embedded device, all memory refers to a physical thing
---
## Diving into arrays
* argv looks something like this:
| index |
0 |
1 |
2 |
... |
| content |
pointer1 |
pointer2 |
pointer3 |
... |
* And `argv[0]` points to something like this:
| index |
0 |
1 |
2 |
3 |
4 |
5 |
| character |
a |
. |
o |
u |
t |
\0 |
---
## Going Past the End
* You can access past the end of an array
* Results are unpredictable
* Often a segfault though
* This something that makes C difficult
---
## The Assembly
> gcc -g -c example4.c -o example4.o\
objdump -d -M intel -S example4.o
```C
example4.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 :
* gcc example4.c -o example
*/
#include
int main(int argc, char** argv) {
0: f3 0f 1e fa endbr64
4: 55 push rbp
5: 48 89 e5 mov rbp,rsp
8: 48 83 ec 20 sub rsp,0x20
c: 89 7d ec mov DWORD PTR [rbp-0x14],edi
f: 48 89 75 e0 mov QWORD PTR [rbp-0x20],rsi
printf("The name of the program is %s\n", argv[0]);
13: 48 8b 45 e0 mov rax,QWORD PTR [rbp-0x20]
17: 48 8b 00 mov rax,QWORD PTR [rax]
1a: 48 89 c6 mov rsi,rax
1d: 48 8d 05 00 00 00 00 lea rax,[rip+0x0] # 24
24: 48 89 c7 mov rdi,rax
27: b8 00 00 00 00 mov eax,0x0
2c: e8 00 00 00 00 call 31
printf("The first character of the program name is %c\n", argv[0][0]);
31: 48 8b 45 e0 mov rax,QWORD PTR [rbp-0x20]
35: 48 8b 00 mov rax,QWORD PTR [rax]
38: 0f b6 00 movzx eax,BYTE PTR [rax]
3b: 0f be c0 movsx eax,al
3e: 89 c6 mov esi,eax
40: 48 8d 05 00 00 00 00 lea rax,[rip+0x0] # 47
47: 48 89 c7 mov rdi,rax
4a: b8 00 00 00 00 mov eax,0x0
4f: e8 00 00 00 00 call 54
printf("The first argument is %s\n", argv[1]);
54: 48 8b 45 e0 mov rax,QWORD PTR [rbp-0x20]
58: 48 83 c0 08 add rax,0x8
5c: 48 8b 00 mov rax,QWORD PTR [rax]
5f: 48 89 c6 mov rsi,rax
62: 48 8d 05 00 00 00 00 lea rax,[rip+0x0] # 69
69: 48 89 c7 mov rdi,rax
6c: b8 00 00 00 00 mov eax,0x0
71: e8 00 00 00 00 call 76
printf("The first character of the second argument is %c\n", argv[1][0]);
76: 48 8b 45 e0 mov rax,QWORD PTR [rbp-0x20]
7a: 48 83 c0 08 add rax,0x8
7e: 48 8b 00 mov rax,QWORD PTR [rax]
81: 0f b6 00 movzx eax,BYTE PTR [rax]
84: 0f be c0 movsx eax,al
87: 89 c6 mov esi,eax
89: 48 8d 05 00 00 00 00 lea rax,[rip+0x0] # 90
90: 48 89 c7 mov rdi,rax
93: b8 00 00 00 00 mov eax,0x0
98: e8 00 00 00 00 call 9d
float pi = 3.14159265358979;
9d: f3 0f 10 05 00 00 00 movss xmm0,DWORD PTR [rip+0x0] # a5
a4: 00
a5: f3 0f 11 45 fc movss DWORD PTR [rbp-0x4],xmm0
printf("Pi is about %f, or simply %.3f\n", pi, pi);
aa: 66 0f ef c0 pxor xmm0,xmm0
ae: f3 0f 5a 45 fc cvtss2sd xmm0,DWORD PTR [rbp-0x4]
b3: 66 0f ef d2 pxor xmm2,xmm2
b7: f3 0f 5a 55 fc cvtss2sd xmm2,DWORD PTR [rbp-0x4]
bc: 66 48 0f 7e d0 movq rax,xmm2
c1: 66 0f 28 c8 movapd xmm1,xmm0
c5: 66 48 0f 6e c0 movq xmm0,rax
ca: 48 8d 05 00 00 00 00 lea rax,[rip+0x0] # d1
d1: 48 89 c7 mov rdi,rax
d4: b8 02 00 00 00 mov eax,0x2
d9: e8 00 00 00 00 call de
printf("The first and second arguments are at %p and %p\n", argv[0], argv[1]);
de: 48 8b 45 e0 mov rax,QWORD PTR [rbp-0x20]
e2: 48 83 c0 08 add rax,0x8
e6: 48 8b 10 mov rdx,QWORD PTR [rax]
e9: 48 8b 45 e0 mov rax,QWORD PTR [rbp-0x20]
ed: 48 8b 00 mov rax,QWORD PTR [rax]
f0: 48 89 c6 mov rsi,rax
f3: 48 8d 05 00 00 00 00 lea rax,[rip+0x0] # fa
fa: 48 89 c7 mov rdi,rax
fd: b8 00 00 00 00 mov eax,0x0
102: e8 00 00 00 00 call 107
return argc;
107: 8b 45 ec mov eax,DWORD PTR [rbp-0x14]
}
10a: c9 leave
10b: c3 ret
```
---
## More Examination
* Let's have the user supply the index to inspect
* But user inputs are strings. We'll have to convert.
* We'll use the `atoi` (ascii to int) function from `stdlib.h`
* `int atoi(const char* nptr);`
* [https://cppreference.com/w/c/string/byte/atoi.html](https://cppreference.com/w/c/string/byte/atoi.html)
* `man atoi`
---
## `atoi` example
```C
/*
* This is an example program!
* To compile code:
* gcc example5.c -o example
*/
#include
#include
int main(int argc, char** argv) {
// Get the index to inspect
int index = atoi(argv[1]);
printf("The character at the desired index is %c\n", argv[0][index]);
return 0;
}
```
---
## Outputs
```
$ ./a.out 0
The character at the desired index is .
$ ./a.out 1
The character at the desired index is /
$ ./a.out 2
The character at the desired index is a
$ ./a.out 3
The character at the desired index is .
$ ./a.out 4
The character at the desired index is o
$ ./a.out 5
The character at the desired index is u
$ ./a.out 6
The character at the desired index is t
$ ./a.out 7
The character at the desired index is
$ ./a.out 8
The character at the desired index is 8
$ ./a.out 9
The character at the desired index is
$ ./a.out 10
The character at the desired index is
$ ./a.out 11
The character at the desired index is S
$ ./a.out 12
The character at the desired index is H
$ ./a.out 13
The character at the desired index is E
$ ./a.out 14
The character at the desired index is L
$ ./a.out 15
The character at the desired index is L
$ ./a.out 16
The character at the desired index is =
$ ./a.out 17
The character at the desired index is /
$ ./a.out 18
The character at the desired index is b
$ ./a.out 19
The character at the desired index is i
$ ./a.out 20
The character at the desired index is n
$ ./a.out 21
The character at the desired index is /
$ ./a.out 22
The character at the desired index is b
$ ./a.out 23
The character at the desired index is a
$ ./a.out 24
The character at the desired index is s
$ ./a.out 25
The character at the desired index is h
$ ./a.out 26
The character at the desired index is
$ ./a.out 27
The character at the desired index is L
$ ./a.out 28
The character at the desired index is A
$ ./a.out 29
The character at the desired index is N
$ ./a.out 30
The character at the desired index is G
$ ./a.out 31
The character at the desired index is U
$ ./a.out 32
The character at the desired index is A
$ ./a.out 33
The character at the desired index is G
$ ./a.out 34
The character at the desired index is E
$ ./a.out 35
The character at the desired index is =
$ ./a.out 36
The character at the desired index is e
$ ./a.out 37
The character at the desired index is n
$ ./a.out 38
The character at the desired index is _
$ ./a.out 39
The character at the desired index is U
$ ./a.out 40
The character at the desired index is S
$ ./a.out 3294862
Segmentation fault (core dumped)
```
---
## What?
* The OS kills your program (Segmentation fault) if you reach outside of your memory
* However, some memory is accessible to you
* In this case, the environment variables
* Other languages are more safe, but not C!
* Remember, it's just a light wrapper over assembly
---
## Pause
* Any questions or confusion so far?
---
## Checks and Safety
* We obviously need to be careful, but how?
* This requires control flow and logic
* More common are:
* `if`
* `while`
* `for`
* `do-while` and `switch` for special cases
* Jumps, including the infamous `goto`
---
## Notes on boolean logic
* C has a type named `bool`
* It has one of two values
* `true`
* `false`
* `true` and `false` can be treated as `1` and `0`
* Until C23, `#include ` was required for the names
* Note: gcc on ilab isn't using C23 by default
* You can enable that standard with `gcc --std=c2x`
* We are sticking with the default compatibility for now
---
## Boolean operators
* A set of logical operators
* `!` (not), `&&` (and), `||` (or)
* [https://cppreference.com/w/c/language/operator_logical.html](https://cppreference.com/w/c/language/operator_logical.html)
* And a set of comparison operators
* [https://cppreference.com/w/c/language/operator_comparison.html](https://cppreference.com/w/c/language/operator_comparison.html)
* `==` (equality) and `!=` (inequality)
* `>` (greater than) and `<` (less than)
* `>=` (greater than or equal) and `<=` (less than or equal)
---
## Logical Operators: Equality
* `==` tests equality
* These expressions evaluate to `true`
* `4 == 4`
* `2.3 == 2.3`
* `'f' == 'f'`
* These expressions evaluate to `false`
* `4 == 3`
* `2.3 == 2.0`
* `'f' == 'q'`
---
## Logical Operators: Inequality
* `!=` is the opposite of `==`
* These expressions evaluate to `false`
* `4 != 4`
* `2.3 != 2.3`
* `'f' != 'f'`
* These expressions evaluate to `true`
* `4 != 3`
* `2.3 != 2.0`
* `'f' != 'q'`
---
## Logical Operators: Comparison
* Less than: `<`
* Greater than: `>`
* Less than or equal: `<=`
* Greater than or equal: `>=`
* Examples
* `4 < 5`
* `4 <= 4`
---
## Negation
* If we want to negate a boolean value we use `!`
* These expressions are all true:
* `true == true`
* `!(false) == true`
* `!(4 == 5) == true`
---
## Using Boolean Values
* Boolean values are used to control the flow of your program
* If X then Y
* Syntax is like this:
```C
if (X) {
//Code that happens when X is true
}
```
---
## `if` syntax
* [https://cppreference.com/w/c/language/if.html](https://cppreference.com/w/c/language/if.html)
* if (expression) statement-true
* if (expression) statement-true else statement-false
* I prefer to always use `{` and `}`
* Even if the statement is a single line
* I personlly think it improves readability
---
## Else
* Doing thing A or thing B is common
```C
if (X) {
//Code that happens when X is true
}
else {
//Code that happens when X is false
}
```
---
## Chaining if...else Statements
```C
if (X) {
//Code that happens when X is true
}
else if (Y) {
//Code that happens when X is false but Y is true
}
else {
//Code that happens when X and Y are both false
}
```
Notice that the second pair of `if ... else` is a single statement, not some new syntax.
---
## Control Flow with `goto`
```C
/*
* To compile this code:
* gcc example6.c -o example6
*/
#include
#include
int main(int argc, char** argv) {
if (argc < 2)
goto abort;
// Get the index to inspect
int index = atoi(argv[1]);
if (index > 6)
goto abort;
printf("The character at the desired index is %c\n", argv[0][index]);
abort:
return 0;
}
```
This is the kind of antiquated code that causes pain and suffering
---
## Use `if` over `goto`
```C
/*
* To compile this code:
* gcc example7.c -o example6
*/
#include
#include
int main(int argc, char** argv) {
if (argc >= 2) {
// Get the index to inspect
int index = atoi(argv[1]);
if (index < 7) {
printf("The character at the desired index is %c\n", argv[0][index]);
}
}
return 0;
}
```
---
## Iterating
* Before, w hard-coded the length of `argv[0]`, which is bad
```C
/*
* To compile this code:
* gcc example8.c -o example8
*/
#include
#include
int getlen(char* arg) {
int index = 0;
while (arg[index] != '\0') {
index += 1;
}
return index;
}
int main(int argc, char** argv) {
if (argc >= 2) {
// Get the index to inspect
int index = atoi(argv[1]);
int len = getlen(argv[0]);
if (index < len) {
printf("The character at the desired index is %c\n", argv[0][index]);
}
}
return 0;
}
```
---
## A Note on Scope
* `index` is declared twice
* But in different `scopes`
* [https://cppreference.com/w/c/language/scope.html](https://cppreference.com/w/c/language/scope.html)
```C[10,20]
/*
* To compile this code:
* gcc example8.c -o example8
*/
#include
#include
int getlen(char* arg) {
int index = 0;
while (arg[index] != '\0') {
index += 1;
}
return index;
}
int main(int argc, char** argv) {
if (argc >= 2) {
// Get the index to inspect
int index = atoi(argv[1]);
int len = getlen(argv[0]);
if (index < len) {
printf("The character at the desired index is %c\n", argv[0][index]);
}
}
return 0;
}
```
---
## More on Scope
* `Scope` refers to the visibility of a name
* One easy trick is to track the `{ }`
* Anything declared inside of a `{ }` pair is only visible inside of that `{ }`
* Not a complete story, but good enough for now
* `#include` statements bring new symbols into `global` scope
* Meaning that everything in the file can now access them
* We could use `atoi` anywhere in our program, for example
---
## Iterating over a string
* Use `putchar` from `stdio` to print in a `while`
```C
/*
* To compile this code:
* gcc example9.c -o example9
*/
#include
#include
int getlen(char* arg) {
int index = 0;
while (arg[index] != '\0') {
index += 1;
}
return index;
}
void print(char* str) {
int index = 0;
int len = getlen(str);
while (index < len) {
putchar(str[index]);
++index;
}
// We don't return anything
// NOTE: Pedantically, there should be error checking
}
int main(int argc, char** argv) {
int index = 0;
while (index < argc) {
// Print out the argument and a new line.
print(argv[index]);
putchar('\n');
++index;
}
return 0;
}
```
---
## Notes
* Before we used the `+=` operator
* Adding the value on the right to the variable on the left
* To increment or decrement by 1, we can use `++` or `--`
* Our function doesn't need to return anything
* So the return type is `void`
---
## Iterating over a string
* `for` version
```C
/*
* To compile this code:
* gcc example10.c -o example10
*/
#include
#include
int getlen(char* arg) {
int index = 0;
while (arg[index] != '\0') {
index += 1;
}
return index;
}
void print(char* str) {
int len = getlen(str);
for (int index = 0; index < len; ++index) {
putchar(str[index]);
}
// We don't return anything
// NOTE: Pedantically, there should be error checking
}
int main(int argc, char** argv) {
int index = 0;
while (index < argc) {
// Print out the argument and a new line.
print(argv[index]);
putchar('\n');
++index;
}
return 0;
}
```
---
## Notes on `for`
* [https://cppreference.com/w/c/language/for.html](https://cppreference.com/w/c/language/for.html)
* Four parts:
1. init clause
2. conditional expression
3. iteration expression
4. loop statement
* The first three are inside of the parenthesis
```C
for (init clause; conditional expression; iteration expression) statement
```
---
## More notes
* Every part of the for loop has its own scope
* This means we could not use it in the `getlen` function
```C
int getlen(char* arg) {
// Empty loop statement is okay
for (int index = 0; arg[index] != '\0'; index += 1);
// But index does not exist here--it is out of scope
return index;
}
```
---
## Even more notes
* You can do weird things, like leave sections empty
```C
int getlen(char* arg) {
int index = 0;
for (; arg[index] != '\0'; index += 1);
return index;
}
```
* Some people write infinite loops with `for` rather than `while`
* `for(;;) { ... }`
* `while (true) { ... }`
* Focus on clarity
---
## Next Class
* Creating our own arrays
* Writing an algorithm