---
# System prepended metadata

title: '# W6 ~ W11 Memory'

---

# 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.png](https://hackmd.io/_uploads/SJWC90kmp.png)

### pointer with string

**demo** :

```c
string s = "HI!";
```

![image.png](https://hackmd.io/_uploads/HkSi30k7T.png)

單 & 雙引號的差異:
`''` : 單引號只儲存一個字符
`""` : 雙引號會自動在最後方加上一個 \0
**string s** :
![image.png](https://hackmd.io/_uploads/BJWST0176.png)
![image.png](https://hackmd.io/_uploads/ryoO6Ry76.png)

- 為什麼 string 只需儲存 第一個 char 的位址? - 因為 string 總是以 \0 做結尾，所以只需要從第一個位址開始尋找，直到\0 為止
  ![image.png](https://hackmd.io/_uploads/rkh7RCkmT.png)
  ![image.png](https://hackmd.io/_uploads/HyxH0RJm6.png)
  實際上這邊的 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 

![Untitled.png](https://hackmd.io/_uploads/rkrI1tgQa.png)

**十六進制 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 指向的內容，因為它們指向相同的記憶體位置。