指標(二)
阿新 • • 發佈:2021-09-01
指標(二)
忘記指標,重學指標
指標的型別轉換
型別轉換
- 將一個型別的資料賦值給另一種型別的變數
例:
char x;
int y = 10;
x = y; //這裡是一個省略寫法,完整寫法為 x = (char)y;
- 並不是所有型別都能互相轉換
例:
struct student {
int id;
int grade;
};
student s;
int x;
x = (int)s; //編譯不通過
指標的型別轉換
- 轉換規則(即哪些型別可以互相轉換)是由編譯器決定的
char* x; int* y; x = (char*)10; y = (int*)x; //可以轉換
struct student {
int id;
int grade;
};
student* s;
int* x = (int*)10;
s = (student*)x; //可以轉換
char* x;
char** y;
x = (char*)10;
y = (char**)x; //可以轉換,如果沒有(cha**)強轉則不行
&符號的使用
&
是地址符,型別是其後面的型別加一個*
,任何變數都可以使用&
來獲取地址,但不能用在常量上
char a = 10; short b = 20; int c = 30; char* pa = &a; //&a的型別為char*,就是a的型別加一個* short* pb = &b; //&b的型別為short* int* pc = &c; //&c的型別為int*
char***** a = (char*****)10;
char****** pa = &a; //&a = char******
本質探究
實驗一
CPP程式碼:
#include "stdafx.h"
void Fun()
{
char a = 10;
char* pa = &a;
}
int main(int argc, char* argv[]) {
Fun();
return 0;
}
反彙編:
Fun: 0040D490 push ebp 0040D491 mov ebp,esp 0040D493 sub esp,48h 0040D496 push ebx 0040D497 push esi 0040D498 push edi 0040D499 lea edi,[ebp-48h] 0040D49C mov ecx,12h 0040D4A1 mov eax,0CCCCCCCCh 0040D4A6 rep stos dword ptr [edi] 0040D4A8 mov byte ptr [ebp-4],0Ah ;char* pa = &a; 0040D4AC lea eax,[ebp-4] ;lea取地址,將[ebp-4]的地址放到eax裡 0040D4AF mov dword ptr [ebp-8],eax 0040D4B2 pop edi 0040D4B3 pop esi 0040D4B4 pop ebx 0040D4B5 mov esp,ebp 0040D4B7 pop ebp 0040D4B8 ret
實驗二
CPP程式碼:
#include "stdafx.h"
void Fun()
{
char a = 10;
short b = 20;
int c = 30;
char* pa = &a;
short* pb = &b;
int* pc = &c;
char** ppa = (char**)&pa;
short** ppb = (short**)&pb;
int** ppc = (int**)&pc;
//簡寫為
//char** ppa = &pa;
//short** ppb = &pb;
//int** ppc = &pc;
}
int main(int argc, char* argv[]) {
Fun();
return 0;
}
反彙編:
0040D490 push ebp
0040D491 mov ebp,esp
0040D493 sub esp,64h
0040D496 push ebx
0040D497 push esi
0040D498 push edi
0040D499 lea edi,[ebp-64h]
0040D49C mov ecx,19h
0040D4A1 mov eax,0CCCCCCCCh
0040D4A6 rep stos dword ptr [edi]
4: char a = 10;
0040D4A8 mov byte ptr [ebp-4],0Ah
5: short b = 20;
0040D4AC mov word ptr [ebp-8],offset Fun+20h (0040d4b0)
6: int c = 30;
0040D4B2 mov dword ptr [ebp-0Ch],1Eh
7:
8: char* pa = &a;
0040D4B9 lea eax,[ebp-4]
0040D4BC mov dword ptr [ebp-10h],eax
9: short* pb = &b;
0040D4BF lea ecx,[ebp-8]
0040D4C2 mov dword ptr [ebp-14h],ecx
10: int* pc = &c;
0040D4C5 lea edx,[ebp-0Ch]
0040D4C8 mov dword ptr [ebp-18h],edx
11:
12: char** ppa = (char**)&pa;
0040D4CB lea eax,[ebp-10h]
0040D4CE mov dword ptr [ebp-1Ch],eax
13: short** ppb = (short**)&pb;
0040D4D1 lea ecx,[ebp-14h]
0040D4D4 mov dword ptr [ebp-20h],ecx
14: int** ppc = (int**)&pc;
0040D4D7 lea edx,[ebp-18h]
0040D4DA mov dword ptr [ebp-24h],edx
0040D4DD pop edi
0040D4DE pop esi
0040D4DF pop ebx
0040D4E0 mov esp,ebp
0040D4E2 pop ebp
0040D4E3 ret
指標的求值
int* px;
int** px2;
int*** px3;
int**** px4;
&px//int**
//*(px)是什麼型別 //int
//*(px2)是什麼型別 //int*
//*(px3)是什麼型別 //int**
//*(px4)是什麼型別 //int***
//前面帶*,其型別是原型別去掉一個*
int x = 10;
//*x是不存在的,只有變數型別帶*,才能在變數前加*
實驗一
CPP程式碼:
#include "stdafx.h"
void Fun()
{
int x = 10;
int* px = &x;
char y = *px;
printf("%d\n",y);
}
int main(int argc, char* argv[]) {
Fun();
return 0;
}
反彙編:
Fun:
0040D490 push ebp
0040D491 mov ebp,esp
0040D493 sub esp,4Ch
0040D496 push ebx
0040D497 push esi
0040D498 push edi
0040D499 lea edi,[ebp-4Ch]
0040D49C mov ecx,13h
0040D4A1 mov eax,0CCCCCCCCh
0040D4A6 rep stos dword ptr [edi]
0040D4A8 mov dword ptr [ebp-4],0Ah
0040D4AF lea eax,[ebp-4]
0040D4B2 mov dword ptr [ebp-8],eax
0040D4B5 mov ecx,dword ptr [ebp-8]
0040D4B8 mov dl,byte ptr [ecx]
0040D4BA mov byte ptr [ebp-0Ch],dl
0040D4BD movsx eax,byte ptr [ebp-0Ch]
0040D4C1 push eax
0040D4C2 push offset string "%d\n" (0042210c)
0040D4C7 call printf (0040d700)
0040D4CC add esp,8
0040D4CF pop edi
0040D4D0 pop esi
0040D4D1 pop ebx
0040D4D2 add esp,4Ch
0040D4D5 cmp ebp,esp
0040D4D7 call __chkesp (004010a0)
0040D4DC mov esp,ebp
0040D4DE pop ebp
0040D4DF ret
結果:
10
分析:
-
int x = 10 //[ebp-4] = 10 int* px = &x //[ebp-8] = [ebp-4]的地址 char y = *px //[ebp-0xC] = [ebp-8]裡那個地址所存的值 = 10
-
int* x *x == int char* x *x == char int** x *x == int* 前面加*,型別等於原來型別去掉一個*
用指標運算元組
陣列首地址
char arr[10];
char* p = &arr[0]; //取陣列第一個元素的地址
char* p = arr; //簡寫
遍歷列印陣列
在陣列中,相鄰元素的地址相差一個數據寬度,加上之前指標的加法,就能實現指標遍歷列印陣列
void Function() {
int arr[5] = {1,2,3,4,5};
int* p = arr;
for (int i = 0; i < 5; i++) {
printf("%d ",*(p+i));
}
}
對於以上函式,下方是相同實現
void Function() {
int arr[5] = {1,2,3,4,5};
for (int i = 0; i < 5; i++) {
printf("%d ",*(arr+i));
}
}
總結
&arr[0]
代表陣列中第一個元素的地址,可以省略為陣列名*(p+i) = p[i]