指针(二)

指针(二)

忘记指针,重学指针

指针的类型转换

类型转换

  • 将一个类型的数据赋值给另一种类型的变量

例:

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]
posted @ 2021-09-01 17:13  Ybitsec  阅读(58)  评论(0编辑  收藏  举报