1. 程式人生 > 其它 >指標(二)

指標(二)

指標(二)

忘記指標,重學指標

指標的型別轉換

型別轉換

  • 將一個型別的資料賦值給另一種型別的變數

例:

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]