記憶體 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(),否則電腦會以記憶體位置解讀
三、複製字串內"值"的方法
- 直觀的做法
#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);
- 每次
malloc()
都要free()
,否則會造成memory leak(內存洩漏) - 每次
malloc()
檢查是否有足夠空間,若無則會回傳Null
- 只有
malloc()
的空間可以free()
- 一個
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