指针(二)
指针(二)
忘记指针,重学指针
指针的类型转换
类型转换
- 将一个类型的数据赋值给另一种类型的变量
例:
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]