楊宗儒@Sprout 2023
改寫自Sprout 2022講義
10010 ->
10010
2⁰
2¹
2²
2³
2⁴
48763 ->
48763
10⁰
10¹
10²
10³
10⁴
4 * 10⁴ + 8 * 10³ + 7 * 10² + 6 * 10¹ + 3 * 10⁰
16 + 0 + 0 + 2 + 0 = 18
0x00AF8 ->
00AF8
16⁰
16¹
16²
16³
16⁴
0 * 16⁴ + 0 * 16³ + A(10) * 16² + F(15) * 16¹ + 8 * 16⁰ = 2808
cout << sizeof(int) << endl; // 4
char c = 'C';
cout << sizeof(c) << endl; // 1
cout << &a << endl;
char a
'A'
0xFFF00A40
變數名
變數值
變數地址
int *ptr = &a;
int a
30
0xFFF00A40
int *ptr
0xFFF00A40
0xFFF00A44
指標自己也會有地址!
int a = 0;
char *ptr = &a; // ERROR
int a = 0;
int *ptr = &a;
(*ptr)++;
cout << *ptr << endl;
cout << a << endl;
宣告時的*是代表是指標變數
取值時的*代表操作指到的數值
別搞混!
*ptr = 10
int *ptr
0xFFF00A40
0xFFF00A44
int a
30 -> 10
0xFFF00A40
int *ptr = &a;
ptr = &b;
int *ptr = &a;
ptr = &b;
int a
30
0xFFF00A40
int *ptr
0xFFF00A40
-> 0xFFF00A36
0xFFF00A44
int b
30
0xFFF00A36
int a = 2023
int b = 3
int *ptr1 = &a;
int *ptr2 = &b;
*ptr2 = *ptr1;
ptr1 = ptr2;
a, b 最後是多少?
ptr1, ptr2 指向誰?
int a = 2023
int b = 3
int *ptr1 = &a;
int *ptr2 = &b;
*ptr2 = *ptr1;
ptr1 = ptr2;
a, b 最後是多少?
ptr1, ptr2 指向誰?
a = 2023, b = 2023
ptr1 = &b, ptr2 = &b
int *ptr
*ptr
ptr
int *ptr = NULL;
int *ptr = nullptr;
if (ptr != nullptr)
int arr[5];
int arr[0]
1
0xFFF00A40
int arr[1]
2
0xFFF00A44
int arr[2]
3
0xFFF00A48
int arr[3]
4
0xFFF00A4C
int arr[4]
5
0xFFF00A50
int *ptr = &arr[0]
int arr[0]
1
0xFFF00A40
int arr[1]
2
0xFFF00A44
int arr[2]
3
0xFFF00A48
int arr[3]
4
0xFFF00A4C
int arr[4]
5
0xFFF00A50
int *ptr
0xFFF00A40
0xFFF00A38
(A) 指標指到的位址+1
(B) 指標指到的數值+1
(C) 指標指向下一個數值
(D) Syntax Error
ptr++
int *ptr = &arr[0];
int arr[0]
1
0xFFF00A40
int arr[1]
2
0xFFF00A44
int arr[2]
3
0xFFF00A48
int arr[3]
4
0xFFF00A4C
int arr[4]
5
0xFFF00A50
int *ptr
0xFFF00A40
0xFFF00A38
ptr++
int arr[0]
1
0xFFF00A40
int arr[1]
2
0xFFF00A44
int arr[2]
3
0xFFF00A48
int arr[3]
4
0xFFF00A4C
int arr[4]
5
0xFFF00A50
int *ptr
0xFFF00A44
0xFFF00A38
(C) 指標指向下一個數值
指標所指的地址 += sizeof(指標指到的型別)
ptr++
(A) 指標指到的數值+1
(B) 取值後指標指向下一個數值
*ptr++;
*ptr++;
(*ptr)++;
*(ptr++);
詳細的優先序 (不用記)
int arr[5];
int *ptr = arr;
char arr[4];
char *ptr;
char c;
arr
0xFFF00A40
0xFFF00A36
char arr[0]
'A'
0xFFF00A40
'B'
0xFFF00A41
'C'
0xFFF00A42
'D'
0xFFF00A43
char arr[1]
char arr[2]
char arr[3]
ptr[idx]
ptr = &arr[2]
char *ptr
0xFFF00A42
0xFFF00A36
char arr[0]
'A'
0xFFF00A40
'B'
0xFFF00A41
'C'
0xFFF00A42
'D'
0xFFF00A43
char arr[1]
char arr[2]
char arr[3]
ptr[1] = 'E'
char *ptr
0xFFF00A42
0xFFF00A36
char arr[0]
'A'
0xFFF00A40
'B'
0xFFF00A41
'C'
0xFFF00A42
'D' -> 'E'
0xFFF00A43
char arr[1]
char arr[2]
char arr[3]
ptr[1]
int *ptr;
int arr[5];
int arr[10];
int *ptr = arr;
後面的code都延續這個宣告
arr = ptr;
Error
陣列不能指向其他地方
ptr[10] = 2;
Runtime Error
ptr 一開始指向 arr 的頭
但 arr 只有 10 個元素
arr[10] 是越界存取 arr 的第 11 個元素
會出現不可預期的行為
*ptr += 1;
AC
ptr 指到的數值 + 1
ptr = arr[1];
Error
ptr 是 (int *)
arr[1] 是 int
不同型別不能直接賦值
*(arr + 1) = 3;
AC
先把 arr 當作指到陣列頭的指標
+1 代表所指之處後一個數值的地址
再對這個地址進行取值
等同於 arr[1] = 3
9[arr] = 3;
AC !!!!
先把 arr 當作指標
前面說過 a[b] 可以當成 *(a + b)
等同於 arr[9] = 3
ptr = arr + 10;
AC
先把 arr 當作指標
+ 10 代表把所指的地址後 10 個數值的位址
再把這個位址存入 ptr
等同 ptr = &arr[10]
但要注意 ptr 指向一個未知的記憶體位址
指向未知記憶體不會有錯誤,但對未知記憶體取值就會有錯誤
ptr = *arr + 10
Error
先把 arr 當作指標指向 arr[0]
對這個指標取值後 + 10 (型別:int, 值:a[0] + 10)
不同型別不能直接賦值 (int *)
*ptr = *arr
AC
先把 arr 當作指標指向 arr[0]
對這個指標取值後,賦值給 ptr 指到的數值
等號兩邊都是 int
分解動作:
int *ptr
ptr++ (操作指標->沒有*)
*ptr > *max_ptr(比較數值->*)
max_ptr = ptr (操作指標->沒有*)
ptr == end (比較指標->沒有*)
注意 max_ptr 一開始是 nullptr
int *ptr; // 星號跟著變數名
int* a, b;
int *ptr = &a;
int *nothing = nullptr;
if (ptr != nullptr) {
*ptr = 123;
}
ptr[idx]
int *ptr = nullptr;
for (int i = 0; i < 2; i++) {
ptr = &i;
}
cout << *ptr << endl; // RE
0x00000000
0xFFFFFFFF
Windows
Linux
int a = 0;
int &ref = a;
ref++;
cout << ref << endl; // 1
cout << a << endl; // 1
參照:
幫變數取別名
操作參照就等於在操作變數本身
不能中途參照其他變數
語法與直接使用變數相同
記憶體裡(通常)不會佔空間
int a = 0;
int &ref = a;
ref++;
cout << ref << endl; // 1
cout << a << endl; // 1
指標:
操作指標指到的數值就等於在操作變數本身
可以指向其他變數
語法與直接使用變數不同(*, &)
記憶體裡會佔空間
int a = 0;
int *ref = &a;
(*ref)++;
cout << ref << endl; // 1
cout << a << endl; // 1
int a = 3;
int b = 1;
int *ptr1 = &a;
int *ptr2 = &b;
int **ptr2ptr = &b;
cout << **ptr2ptr << endl;
const 指標有分以下幾種:
如果覺得記不起來的話...
const int a = 3; // a 是 const int,所以不能修改a的值
int b = 4; // b 是正常的 int ,可以隨意修改 b 的值
int d = 6;
const int *ptr1 = &a; // ptr1 是指到 const int 的指標,可以指向別人,但不能修改指到的值
int* const ptr2 = &b; // ptr2 是指到 int 的 const 指標,不能指向別人,但可以修改別人
const int* const ptr3 = &a; // ptr3 是指向 const int 的 const 指標,不能指向別人,也不能修改指到的值
ptr1 = &d; // ok
*ptr1 = 5; // Error
ptr2 = &d; //Error
*ptr2 = 6; // ok
ptr3 = &d; //Error
*ptr3 = 6; // Error
big-endian: 最大的 byte 的記憶體位址最大
little-endian: 最大的 byte 記憶體位址最小
int a = 3;
char c = 'C';
void *vptr = &a;
cout << *(int*) vptr << endl;
vptr = &c;
cout << *(char *)vptr << endl;
cout << *ptr << endl; //ERROR