[cs50x - 2022] week4 記憶體


Posted by pei_______ on 2022-05-07

記憶體 Memory

十六進位儲存

0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08
0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10
0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18
0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F 0x20

RGB亦使用16進位儲存 => FFFFFF、FF0000、00FF00、0000FF


指標 pointer

一、指出變數所在記憶體位置

int a = 20;
int* ptr = &a; => 指出a所在記憶體位置
int** p = &ptr; => 指出ptr(指標)所在記憶體位置

變數名稱 a ptr p
儲存值 20 0x40 0x52
儲存位置 0x40 0x52 0x82

print("%p",&a) => 0x52 (a的位置)
print("%p",ptr) => 0x52 (儲存在ptr變數中的,a的位置)
print("%d",*ptr) => 20 (ptr指標所指位置 = a)


二、字串的本質即是指標,指向字元陣列第一個字元的位置

string s = "Hi!"
char *s = "Hi!"

#include <stdio.h>
#include <cs50.h>

int main(void)
{
string s = "HI!";
char* p = &s[0];

printf("%p\n",p);
printf("%p\n",s);
}

// 0x402004
// 0x402004
#include <stdio.h>


int main(void)
{
char* s = "Hi!";

printf("%p\n",s);
printf("%p\n",s[0]);
printf("%p\n",s[1]);
printf("%p\n",s[2]);
printf("%p\n",s[3]);
}

// 0x402004 //=> 指向 H 的位置
// 0x402004 //=> 儲存 H
// 0x402005 //=> 儲存 I
// 0x402006 //=> 儲存 !
// 0x402007 //=> 儲存 \0

故比較兩string是否相同時,需用strcmp(),否則電腦會以記憶體位置解讀


三、複製字串內"值"的方法

  1. 直觀的做法
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
string s = get_string("s: "); // s = 0x0123
string t = s; // t = 0x0123

t[0] = toupper(t[0]); // 0x0123第一個字母轉成大寫

printf("s: %s\n",s); 
printf("t: %s\n",t);
}

// s: hi!
// s: Hi! // s = 0x0123 h轉成大寫
// t: Hi! // t = 0x0123 h轉成大寫

若直接使用賦值s給t,則會賦予t該字串地址,故修改內容會同步更改

指標 指向位置
s h (0x0123) i (0x0124) ! (0x0125) /0(0x126)
t 指向上方

2.修正作法
(1) 利用malloc為t變數所要複製之字串創造空間(動態內存),並在完成後以free釋放該空間
(2) 利用strcpy 或 for loop複製字串內容(而非複製座標指向位置)

#include <cs50.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
string s = get_string("s: "); // s = 0x0123
string t = malloc(strlen(s) + 1 ); // 為t創造新的儲存空間

if (t == NULL)  // 避免系統已經沒有空間賦予t (NULL = /0)
{
    return 1; 
}


strcpy(t, s); // 將s指向空間的內存數值複製至t指向的空間

if (strlen(t) > 0) // 避免使用者未輸入任何數值
{
    t[0] = toupper(t[0]); 
}

printf("s: %s\n",s); 
printf("t: %s\n",t);

free(t);
return 0;
}

// s: hi!
// s: hi! // s = 0x0123 h不受影響
// t: Hi! // t = 0x0456 H轉成大寫
指標 指向位置
s h (0x0123) i (0x0124) ! (0x0125) /0(0x126)
t h (0x0456) i (0x0457) ! (0x0458) /0(0x459) (malloc 動態內存)

四、兩個變數"值"的交換

#include <stdio.h>
#include <stdlib.h>

void swap(int* a, int* b);

int main(void)
{
    int x = 1;
    int y = 5;
    printf("x = %i, y = %i", x, y);
    swap(&x, &y);
    printf("x = %i, y = %i", x, y);
}

void swap(int* a, int* b)
{
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

五、Scanf 儲存使用者輸入的"值"

#include <stdio.h>

int main(void)
{
    int x;
    printf("x: ");
    scanf("%i", &x);
    printf("x = %i\n", x);
}
#include <stdio.h>

int main(void)
{
    char s[4]; // 須先賦與記憶體空間及大小
    printf("s: ");
    scanf("%s", s); // s本身即是空間,不須加&
    printf("s: %s\n", s);
}

靜態內存 stack & 動態內存 heap

------------------
|<read only text>|
------------------
| <已初始化 data> |
-----------------
| <未初始化 data> |
------------------
| <動態內存 heap> |
|   由上往下分配  |
------------------
|          |
|           |
|            |
------------------
|   由下往上分配   |
|  使用完自動釋放  |
|    function()   |
|     printf()    |
|      main()     |
| <靜態內存 stack> | 
------------------

malloc & free 創建動態內存
#include <stdlib.h>

int* number = malloc(sizeof(int));
free(number);

  1. 每次malloc()都要free(),否則會造成memory leak(內存洩漏)
  2. 每次malloc()檢查是否有足夠空間,若無則會回傳Null
  3. 只有malloc()的空間可以free()
  4. 一個malloc()只能free()一次

文件指標 file pointers

使用文件的優點,可保留數據
#include <stdlio.h>

1. fopen() & fclose()

FILE* ptr = fopen("file_name", "operation(r/w/a)")
fclose(<file pointer>)

FILE* ptr1 = fopen(""filez.1", "r")
fclose(ptr1)

2. fgetc() & fputc()

char ch = fgetc(<file pointer>)
fputc(<character>, <file pointer>);

char ch = fgetc(ptr1)
fputc('A', ptr3)

char ch;
while ((ch = fgetc(ptr)) != EOF)
{
    fputc(ch, ptr2);
}

3. fread() & fwrite()

fread(<buffer>, <size>, <qty>, <file pointer>) file => buffer
fwrite(<buffer>, <size>, <qty>, <file pointer>) buffer => file

int arr[10];
fread(arr, sizeof(int), 10, ptr)
// 從ptr指向之文件讀取int大小*10的資料,存入stack中的arr變數

double* arr2 = malloc(sizeof(double) * 80);
fread(arr2, sizeof(double), 80, ptr);
// 從ptr指向之文件讀取double大小*80的資料,存入heak中的arr2變數

char c;
fread(&c, sizeof(char), 1, ptr)
// 也可以存入單一變數之中

// 以上將fread改成fwrite,則是將變數內值寫入file

#cs50x #課堂筆記







Related Posts

【Vue 學習筆記】Pinia 製作購物車

【Vue 學習筆記】Pinia 製作購物車

W18_後端框架 Express + Sequelize

W18_後端框架 Express + Sequelize

關於 CSS 最 Confusing 的位置以及顯示方式

關於 CSS 最 Confusing 的位置以及顯示方式


Comments