指针(一)

指针

忘记指针,重学指针

指针类型引入

可以简单的将指针类型看作为一个带*的的类型

所有的类型后面加一个或者多个*即为指针类型

指针类型的声明

  1. 一般类型声明
char c;
short s;
int i;
__int64 l;
float f;
double d;

struct student {
    int x;
    int y;
};
  1. 指针类型声明
char* c;
short* s;
int* i;

struct student {
    int x;
    int y;
};
student* stu;
//可以将附在变量名前,如char *c,但并不建议这样声明
//可以带多个*
char**** c;
short**** s;
int**** i;

struct student {
    int x;
    int y;
};
student**** stu;

指针类型的赋值

  1. 传统类型赋值
char c = 1;
short s = 2;
int i = 3;
//以上方式的赋值为简化写法
//以完整写法赋值应为以下方式
char c = (char)1;
short s = (short)2;
int i = (int)3;
  1. 指针类型赋值
//只能以完整写法赋值
char* c = (char*)1;
short* s = (short*)2;
int* i = (int*)3;

char** c = (char**)1;
short** s = (short**)2;
int** i = (int**)3;

指针类型的宽度

普通类型的宽度

CPP代码:

#include "stdafx.h"
void Fun()
{
	char x;
	short y;
	int z;

	x = 1;
	y = 2;
	z = 3;
}


int main(int argc, char* argv[]) {
	Fun();
	return 0;
}

反汇编:

Fun:
00401020   push        ebp
00401021   mov         ebp,esp
00401023   sub         esp,4Ch
00401026   push        ebx
00401027   push        esi
00401028   push        edi
00401029   lea         edi,[ebp-4Ch]
0040102C   mov         ecx,13h
00401031   mov         eax,0CCCCCCCCh
00401036   rep stos    dword ptr [edi]
;-------------------------------------------------
00401038   mov         byte ptr [ebp-4],1
0040103C   mov         word ptr [ebp-8],offset Fun+20h (00401040)
00401042   mov         dword ptr [ebp-0Ch],3
;-------------------------------------------------
00401049   pop         edi
0040104A   pop         esi
0040104B   pop         ebx
0040104C   mov         esp,ebp
0040104E   pop         ebp
0040104F   ret

分析:

  • 通过反汇编可以看出,对于char short int这3种类型的变量,局部变量空间分配的都是4字节([ebp-4] [ebp-8] [ebp-0Ch]),但是赋值宽度分别为byte word dword,可以看出三种类型的宽度为1 2 4字节

指针类型的宽度

CPP代码:

#include "stdafx.h"
void Fun()
{
	char* x;
	short* y;
	int* z;

	x = (char*)1;
	y = (short*)2;
	z = (int*)3;
}


int main(int argc, char* argv[]) {
	Fun();
	return 0;
}

反汇编:

Fun:
00401020   push        ebp
00401021   mov         ebp,esp
00401023   sub         esp,4Ch
00401026   push        ebx
00401027   push        esi
00401028   push        edi
00401029   lea         edi,[ebp-4Ch]
0040102C   mov         ecx,13h
00401031   mov         eax,0CCCCCCCCh
00401036   rep stos    dword ptr [edi]
;-------------------------------------------------
00401038   mov         dword ptr [ebp-4],1
0040103F   mov         dword ptr [ebp-8],2
00401046   mov         dword ptr [ebp-0Ch],3
;-------------------------------------------------
0040104D   pop         edi
0040104E   pop         esi
0040104F   pop         ebx
00401050   mov         esp,ebp
00401052   pop         ebp
00401053   ret

分析:

  • 赋值时的宽度均为dword,指针类型宽度为4字节

带有多个*

CPP代码:

#include "stdafx.h"
void Fun()
{
	char**** x;
	short**** y;
	int**** z;

	x = (char****)1;
	y = (short****)2;
	z = (int****)3;
}


int main(int argc, char* argv[]) {
	Fun();
	return 0;
}

反汇编:

Fun:
00401020   push        ebp
00401021   mov         ebp,esp
00401023   sub         esp,4Ch
00401026   push        ebx
00401027   push        esi
00401028   push        edi
00401029   lea         edi,[ebp-4Ch]
0040102C   mov         ecx,13h
00401031   mov         eax,0CCCCCCCCh
00401036   rep stos    dword ptr [edi]
;-------------------------------------------------
00401038   mov         dword ptr [ebp-4],1
0040103F   mov         dword ptr [ebp-8],2
00401046   mov         dword ptr [ebp-0Ch],3
;-------------------------------------------------
0040104D   pop         edi
0040104E   pop         esi
0040104F   pop         ebx
00401050   mov         esp,ebp
00401052   pop         ebp
00401053   ret

分析:

  • 带*类型的变量宽度永远是4字节、无论类型是什么,无论有几个

  • 注意,指针的宽度会因为cpu位宽而有所不同

指针类型的自增自减

我们知道当类型为char short int等存储整数的类型时,自增自减的结果为自身加一、自身减一,那当类型为指针类型时自增自减会怎样?

实验一

CPP代码:

#include "stdafx.h"
void Fun()
{
	char* a;
	short* b;
	int* c;
	
	a = (char*)100;
	b = (short*)100;
	c = (int*)100;

	a++;
	b++;
	c++;
	printf("%d %d %d\n",a,b,c);
}


int main(int argc, char* argv[]) {
	Fun();
	return 0;
}

结果:

101 102 104

实验二

CPP代码:

#include "stdafx.h"
void Fun()
{
	char** a;
	short** b;
	int** c;
	
	a = (char**)100;
	b = (short**)100;
	c = (int**)100;

	a++;
	b++;
	c++;
	printf("%d %d %d\n",a,b,c);
}


int main(int argc, char* argv[]) {
	Fun();
	return 0;
}

结果:

104 104 104

总结

  • 增量等于去掉一个*后的变量类型的宽度(自减相同原理)
  • 指针存储的是一个变量的内存地址,自增(自减)运算就是寻找下一个(上一个)变量的内存地址,查找方法为当前地址减去其存储的变量类型的宽度

指针类型的加减

实验一

CPP代码:

#include "stdafx.h"
void Fun()
{
	char* a;
	short* b;
	int* c;
	
	a = (char*)100;
	b = (short*)100;
	c = (int*)100;

	a = a - 5;
	b = b - 5;
	c = c - 5;
	printf("%d %d %d\n",a,b,c);
}


int main(int argc, char* argv[]) {
	Fun();
	return 0;
}

反汇编:

Fun:
0040D4B0   push        ebp
0040D4B1   mov         ebp,esp
0040D4B3   sub         esp,4Ch
0040D4B6   push        ebx
0040D4B7   push        esi
0040D4B8   push        edi
0040D4B9   lea         edi,[ebp-4Ch]
0040D4BC   mov         ecx,13h
0040D4C1   mov         eax,0CCCCCCCCh
0040D4C6   rep stos    dword ptr [edi]
;-------------------------------------------------
;局部变量定义,指针宽度均为4字节
0040D4C8   mov         dword ptr [ebp-4],64h
0040D4CF   mov         dword ptr [ebp-8],64h
0040D4D6   mov         dword ptr [ebp-0Ch],64h
;指针的减法
0040D4DD   mov         eax,dword ptr [ebp-4]
0040D4E0   sub         eax,5					;char* 减5
0040D4E3   mov         dword ptr [ebp-4],eax

0040D4E6   mov         ecx,dword ptr [ebp-8]
0040D4E9   sub         ecx,0Ah					;short* 减10
0040D4EC   mov         dword ptr [ebp-8],ecx

0040D4EF   mov         edx,dword ptr [ebp-0Ch]
0040D4F2   sub         edx,14h					;int* 减20
0040D4F5   mov         dword ptr [ebp-0Ch],edx

;printf function
0040D4F8   mov         eax,dword ptr [ebp-0Ch]
0040D4FB   push        eax
0040D4FC   mov         ecx,dword ptr [ebp-8]
0040D4FF   push        ecx
0040D500   mov         edx,dword ptr [ebp-4]
0040D503   push        edx
0040D504   push        offset string "%d %d %d\n" (00422f6c)
0040D509   call        printf (0040d750)
0040D50E   add         esp,10h
;-------------------------------------------------
0040D511   pop         edi
0040D512   pop         esi
0040D513   pop         ebx
0040D514   add         esp,4Ch
0040D517   cmp         ebp,esp
0040D519   call        __chkesp (004010c0)
0040D51E   mov         esp,ebp
0040D520   pop         ebp
0040D521   ret

结果:

  • 同样都是减5,但是得到了不同的结果
95 90 80

实验二

CPP代码:

#include "stdafx.h"
void Fun()
{
	char** a;
	short** b;
	int** c;
	
	a = (char**)100;
	b = (short**)100;
	c = (int**)100;

	a = a + 5;
	b = b + 5;
	c = c + 5;
	printf("%d %d %d\n",a,b,c);
}


int main(int argc, char* argv[]) {
	Fun();
	return 0;
}

反汇编:

Fun:
0040D4B0   push        ebp
0040D4B1   mov         ebp,esp
0040D4B3   sub         esp,4Ch
0040D4B6   push        ebx
0040D4B7   push        esi
0040D4B8   push        edi
0040D4B9   lea         edi,[ebp-4Ch]
0040D4BC   mov         ecx,13h
0040D4C1   mov         eax,0CCCCCCCCh
0040D4C6   rep stos    dword ptr [edi]
;-------------------------------------------------
;局部变量定义,指针宽度均为4字节
0040D4C8   mov         dword ptr [ebp-4],64h
0040D4CF   mov         dword ptr [ebp-8],64h
0040D4D6   mov         dword ptr [ebp-0Ch],64h

0040D4DD   mov         eax,dword ptr [ebp-4]
0040D4E0   add         eax,14h					;char** 加20
0040D4E3   mov         dword ptr [ebp-4],eax

0040D4E6   mov         ecx,dword ptr [ebp-8]
0040D4E9   add         ecx,14h					;short** 加20
0040D4EC   mov         dword ptr [ebp-8],ecx

0040D4EF   mov         edx,dword ptr [ebp-0Ch]
0040D4F2   add         edx,14h					;int** 加20
0040D4F5   mov         dword ptr [ebp-0Ch],edx

;printf function
0040D4F8   mov         eax,dword ptr [ebp-0Ch]
0040D4FB   push        eax
0040D4FC   mov         ecx,dword ptr [ebp-8]
0040D4FF   push        ecx
0040D500   mov         edx,dword ptr [ebp-4]
0040D503   push        edx
0040D504   push        offset string "%d %d %d\n" (00422f6c)
0040D509   call        printf (0040d750)
0040D50E   add         esp,10h
;-------------------------------------------------
0040D511   pop         edi
0040D512   pop         esi
0040D513   pop         ebx
0040D514   add         esp,4Ch
0040D517   cmp         ebp,esp
0040D519   call        __chkesp (004010c0)
0040D51E   mov         esp,ebp
0040D520   pop         ebp
0040D521   ret

结果:

120 120 120

总结

  • 与自增自减同理,增量等于去掉一个*后的变量类型的宽度×N
  • 加减运算就是寻找下N个(上N个)相同类型变量的内存地址,查找方法为当前地址减去其存储的变量类型的宽度×N

指针类型求差值

两个相同类型的指针可以做减法,结果为一个整数

实验一

CPP代码:

#include "stdafx.h"
void Fun()
{
    char* a;
    char* b;
    
    a = (char*)200;
    b = (char*)100;
    
    int d = a -b;
    printf("%d\n", d);
}


int main(int argc, char* argv[]) {
	Fun();
	return 0;
}

反汇编:

Fun:
0040D4B0   push        ebp
0040D4B1   mov         ebp,esp
0040D4B3   sub         esp,4Ch
0040D4B6   push        ebx
0040D4B7   push        esi
0040D4B8   push        edi
0040D4B9   lea         edi,[ebp-4Ch]
0040D4BC   mov         ecx,13h
0040D4C1   mov         eax,0CCCCCCCCh
0040D4C6   rep stos    dword ptr [edi]
;-------------------------------------------------
0040D4C8   mov         dword ptr [ebp-4],0C8h
0040D4CF   mov         dword ptr [ebp-8],64h

0040D4D6   mov         eax,dword ptr [ebp-4]
0040D4D9   sub         eax,dword ptr [ebp-8]
0040D4DC   mov         dword ptr [ebp-0Ch],eax

;printf function
0040D4DF   mov         ecx,dword ptr [ebp-0Ch]
0040D4E2   push        ecx
0040D4E3   push        offset string "%d %d %d\n" (00422f6c)
0040D4E8   call        printf (0040d750)
0040D4ED   add         esp,8
;-------------------------------------------------
0040D4F0   pop         edi
0040D4F1   pop         esi
0040D4F2   pop         ebx
0040D4F3   add         esp,4Ch
0040D4F6   cmp         ebp,esp
0040D4F8   call        __chkesp (004010c0)
0040D4FD   mov         esp,ebp
0040D4FF   pop         ebp
0040D500   ret

结果:

100

实验二

CPP代码:

#include "stdafx.h"
void Fun()
{
    short* a;
    short* b;
    
    a = (short*)200;
    b = (short*)100;
    
    int d = a -b;
    printf("%d\n", d);
}


int main(int argc, char* argv[]) {
	Fun();
	return 0;
}

反汇编:

Fun:
0040D4B0   push        ebp
0040D4B1   mov         ebp,esp
0040D4B3   sub         esp,4Ch
0040D4B6   push        ebx
0040D4B7   push        esi
0040D4B8   push        edi
0040D4B9   lea         edi,[ebp-4Ch]
0040D4BC   mov         ecx,13h
0040D4C1   mov         eax,0CCCCCCCCh
0040D4C6   rep stos    dword ptr [edi]
;-------------------------------------------------
0040D4C8   mov         dword ptr [ebp-4],0C8h
0040D4CF   mov         dword ptr [ebp-8],64h

0040D4D6   mov         eax,dword ptr [ebp-4]
0040D4D9   sub         eax,dword ptr [ebp-8]	;eax = 0x64
0040D4DC   sar         eax,1	;保留操作数右移1位 eax = 0x32
0040D4DE   mov         dword ptr [ebp-0Ch],eax

0040D4E1   mov         ecx,dword ptr [ebp-0Ch]
0040D4E4   push        ecx
0040D4E5   push        offset string "%d %d %d\n" (00422f6c)
0040D4EA   call        printf (0040d750)
0040D4EF   add         esp,8
0040D4F2   pop         edi
0040D4F3   pop         esi
0040D4F4   pop         ebx
0040D4F5   add         esp,4Ch
;-------------------------------------------------
0040D4F8   cmp         ebp,esp
0040D4FA   call        __chkesp (004010c0)
0040D4FF   mov         esp,ebp
0040D501   pop         ebp
0040D502   ret

结果:

50

实验三

CPP代码:

#include "stdafx.h"
void Fun()
{
    int* a;
    int* b;
    
    a = (int*)200;
    b = (int*)100;
    
    int d = a -b;
    printf("%d\n", d);
}


int main(int argc, char* argv[]) {
	Fun();
	return 0;
}

反汇编:

Fun:
0040D4B0   push        ebp
0040D4B1   mov         ebp,esp
0040D4B3   sub         esp,4Ch
0040D4B6   push        ebx
0040D4B7   push        esi
0040D4B8   push        edi
0040D4B9   lea         edi,[ebp-4Ch]
0040D4BC   mov         ecx,13h
0040D4C1   mov         eax,0CCCCCCCCh
0040D4C6   rep stos    dword ptr [edi]
;-------------------------------------------------
0040D4C8   mov         dword ptr [ebp-4],0C8h
0040D4CF   mov         dword ptr [ebp-8],64h

0040D4D6   mov         eax,dword ptr [ebp-4]
0040D4D9   sub         eax,dword ptr [ebp-8]	;eax = 0x64
0040D4DC   sar         eax,2					;eax = 0x19
0040D4DF   mov         dword ptr [ebp-0Ch],eax

0040D4E2   mov         ecx,dword ptr [ebp-0Ch]
0040D4E5   push        ecx
0040D4E6   push        offset string "%d %d %d\n" (00422f6c)
0040D4EB   call        printf (0040d750)
0040D4F0   add         esp,8
0040D4F3   pop         edi
0040D4F4   pop         esi
0040D4F5   pop         ebx
0040D4F6   add         esp,4Ch
;-------------------------------------------------
0040D4F9   cmp         ebp,esp
0040D4FB   call        __chkesp (004010c0)
0040D500   mov         esp,ebp
0040D502   pop         ebp
0040D503   ret

结果:

25

总结

  • 两相同指针类型相减的结果为,相减的结果除以去掉一个*的数据宽度

指针类型的大小比较

带*变量,如果类型相同,可以做大小的比较

CPP代码:

#include "stdafx.h"
void Fun()
{
    int****** a;
    int****** b;
    
    a = (int******)200;
    b = (int******)100;
    
    if (a > b)
		printf("a>b");
}


int main(int argc, char* argv[]) {
	Fun();
	return 0;
}

指针(一)

上一篇:剑指 Offer 13. 机器人的运动范围(中等)


下一篇:OneNote的粘贴出现问题 无法粘贴图片