# W6 ~ W11 Memory
##### `Cs50`
## Link : [Memory](https://youtu.be/AcWIE9qazLI?list=PLhQjrBD2T380F_inVRXMIHCqLaNUd7bN4&t=2099)
# Notes
::: spoiler tomas
decimal system = 十進制
hexadecimal system = 16 進制
ambiguity = 崎意
`0 ~ F`
16 進制 :
為了更簡潔的表示數字,並且可以和固定數量的二進制位對上,最大差異在於基數的不同。
用途:
常用於表示記憶體位置。
ambiguity :
10 會被認為是十,所以在十六進制中會在第一個數字前使用 0x 表示正在使用十六進制。
ex :
```
01 => 0x01
```
**demo** :
- 在大多數現代的操作系統中,一個整數(int)占用 4 個字節(bytes)。
```c
#include <stdio.h>
int main(void)
{
int n = 50;
printf("%i\n",n)
}
```
在上面這段 code 被執行後,n 將會被存放於某處記憶體中進行儲存。
### 運算符 `&*` :
`&`這個運算符可以獲取記憶體中的一段數據的位址,只要在變量名稱前加上`&`, c 就可以獲得這個變量的位址。
`*`解引用運算符,這個運算符表示將目標變數轉至特定位址。
**demo** :
- 使用 `%p`可以印出記憶體位址。
- 這時候印出的將會是 n 的位址。
```c
#include <stdio.h>
int main(void)
{
int n = 50;
printf("%p\n",n)
}
//0xffcc784a04c
```
### pointer in c
本質上為一個儲存位址的變量。
**demo**:
宣告的時候在該變數前方加上 `*`表示這個變數是一個指針(pointer)
````c
int n = 50;
int *p = &n; //p 是一個 pointer 並且 value 為透過 ```&``` 所獲取之 n 的位址
````
````c
#include <stdio.h>
int main(void)
{
int n = 50;
int *p = &n;
//p 是一個 pointer 並且 value 為透過 ```&``` 所獲取之 n 的位址, pointer 通常占用 8 個字節。
printf("%p\n",p)
}
````
pointer 可視作一個指向其他東西的變量。

### pointer with string
**demo** :
```c
string s = "HI!";
```

單 & 雙引號的差異:
`''` : 單引號只儲存一個字符
`""` : 雙引號會自動在最後方加上一個 \0
**string s** :


- 為什麼 string 只需儲存 第一個 char 的位址? - 因為 string 總是以 \0 做結尾,所以只需要從第一個位址開始尋找,直到\0 為止


實際上這邊的 s 就是做為指向 string 中的第一個 char 位址的 pointer
* **example**:
```c
#include <cs50.h>
#include <stdio.h>
int main(void)
{
string s = "HI!"; //c 實際上沒有 string 這個關鍵字 應該是 char *s = "HI!"
printf("%s\n",s)
}
//HI!
```
上面這段 code 實際上做的事情,就是透過 pointer \*s 儲存第一個 char 的位址。
```c
typedef char *string
```
### 宣告型別的方式
```c
typedef int integer //這邊的 integer 為自訂名稱 表示 integer 的型別是 int
```
### 另一個訪問位址的方式
```c
#include <stdio.h>
int main(void)
{
int n = 50;
int *p = &n; //這個情境下這條無用
printf("%i\n",*p);
//改成 i 表示現在要 print 的不是一個位址 而是一個 value, 並且加上 * 表示前往 p 所儲存的位址,並且會獲得該位址的 value。
}
```
### `%p`表示 print pointer value, `%s` 表示前往該位址
```c
#include <stdio.h>
int main(main)
{
// string s = "HI!"; can't without CS50 library
char *s = "HI!"; // 表示字串 s
printf("%p\n",s) //s 的 memory address
printf("%s\n",s) // HI!
// 前往 s 的位址並往後遍歷直到空字符\n
// 若是使用 *s 則會獲得該位址的第一個字符
printf("%p\n",&s) //print s 的 memory address
printf("%p\n",&s[0]) //print s 中第一個字元的 memory ~~address~~
printf("%p\n",&s[1]) //print s 中第二個字元的 memory address === 第一個字元 + 1
}
```
### pointer 運算
### string 比對
```c
#include <cs50.h>
#include <stdio.h>
int main(void)
{
string s = get_string ("s: ");
string t = get_string ("t: ");
if(s == t) //這邊比對的是記憶體位址
{
printf("Same\n")
}
else
{
printf("Diff\n")
}
}
```
#### 為什麼需要使用`strcmp`
- 透過 strcmp 實際上是使用兩個指針 分別從被比較的字串最左邊開始比較
```c
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
string s = get_string ("s: ");
string t = get_string ("t: ");
if(strcmp(s,t) == 0)
{
printf("Same\n")
}
else
{
printf("Diff\n")
}
}
```
- 不使用的情況下
```c
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
string s = get_string ("s: ");
string t = get_string ("t: ");
char *s = get_string ("s: ");
char *t = get_string ("t: ");
printf("%s\n, s"); //查看變量
printf("%s\n, t");
printf("%p\n, s"); //查看位址
printf("%p\n, t");
}
```
## 複製字串
### 新增兩種 library
- malloc : 用於記憶體分配 return 一個 value ,會找到閒置記憶體的第一個位址
- free : 用於釋放記憶體 傳遞一個 pointer 表示釋放這個位址的記憶體
```c
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
string s = get_string ("s: ");
string t = s; //這邊複製的是位址
t[0] = toupper(t[0]);
if (strlen(t) > 0) // strlen(t) => t的長度 > 0 - fixed
{
t[0] = toupper(t[0]); // 轉為大寫
}
printf("s: %s\n, s");
printf("t: %s\n, t");
}
```
fixed:
```c
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
char *s = get_string ("s: "); //origin
if(s == NULL) // handle error
{
return 1; //表示 error
}
char *t = malloc(strlen(s) + 1); //請求記憶體 = s的長度 - malloc
//+1 是為了終止符號(/0)的空間
char *t = s; //t的位址 = s的位址 所以s的變動會影響t - origin
if(t == NULL)
{
return 1;
for(int i = 0; n = strlen(s) + 1; i < sLength; i++) // fixed : 增加 n 避免條件中有函式
{
t[i] = s[i]
}
//等同於
strcpy(t,s);
if( strlen(t) > 0 ) // or t[0] !== NULL //(0)
{
t[0] = toupper(t[0]); // 轉為大寫
}
printf("s: %s\n, s");
printf("t: %s\n, t");
// 使用 malloc 時 函數結尾需要釋放記憶體
free(t);
return 0
}
```
### check memory error
valgrind :
```c
valgrind ./fileName
```
### inilize value
不重置的話會導致其中包含無效value
### point & pointee
point
```c
int *x;
```
pointee //需要獨立步驟
```c
x = malloc(sizeof(int))
*x = 13
```
### 記憶體順序
machine code
galbals
heap > 記憶體堆 malloc就是從這邊分割出請求的記憶體空間 並且 malloc 會追蹤被分配的字節
//當這個區塊被佔滿就會導致crash
//heap overflow & stack overflow
//
stack 從最下方開始往上使用記憶體空間 //function 被宣告的時候會佔用這個區塊
### swap value
c 中 想調換資料的時候不能直接透過 ```=```
需要透過位址進行資料替換
當透過 function 在進行替換的時候 會因為遇到作用域的問題 導致結果不如預期
### 操作
```&```表示取得記憶體位址
```*```表示前往目標位址
### 還原 cs50 library
get_int
```c
int x;
printf("x: ");
scanf("%i", &x);
printf("x: %i\n", x);
//hanndle error
```
get_string
```c
// char *s = NULL; // inilize value
chat s[4];
printf("s: ");
scanf("%s", s); // string always was a address
printf("s: %s", s)
```
:::
::: spoiler KellyLee
**十進制:**
1111 (二進制表15)轉成十進制的算法
$$(1 \times 2^3) + (1 \times 2^2) + (1 \times 2^1) + (1 \times 2^0)$$
=8+4+2+1=15
1001 (二進制表)轉成十進制的算法
$$(1 \times 2^3) + (1 \times 2^0)$$
=8+1=9

**十六進制 hexadecimal (base-16):**
0123456789ABCDEF
( 00 ~ FF )
11111111(二進制) 代表 FF (16進制)
一個十六進制數在電腦始終表示4 bits
11111111 在十進制表示 255
在photoshop,0000FF意味著沒有紅色,沒有綠色,藍色有255個.
**copy.c:**
```c
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
string s = get_string("s: ");
string t = s;
t[0] = toupper(t[0]);
printf("%s\n", s);
printf("%s\n", t);
}
```
在這段程式碼中,s 和 t 是指向不同內存位置的指標。當 string t = s; 被執行時,t 指向了 s 所指向的內存位置,因此它們兩者指向的是同一個字串的內容。當你更改 t 中的內容時,實際上也會改變 s 指向的內容,因為它們指向相同的記憶體位置。