指针
忘记指针,重学指针
指针类型引入
可以简单的将指针类型看作为一个带
*
的的类型所有的类型后面加一个或者多个
*
即为指针类型
指针类型的声明
- 一般类型声明
char c;
short s;
int i;
__int64 l;
float f;
double d;
struct student {
int x;
int y;
};
- 指针类型声明
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;
指针类型的赋值
- 传统类型赋值
char c = 1;
short s = 2;
int i = 3;
//以上方式的赋值为简化写法
//以完整写法赋值应为以下方式
char c = (char)1;
short s = (short)2;
int i = (int)3;
- 指针类型赋值
//只能以完整写法赋值
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;
}