指针(二)
- 类型转换
- &符号的使用
- “带*类型” 的特征探测:求值
- 用指针操作数组
一、类型转换
a、普通类型之间的类型转换
在C语言中,经常会使用到类型转换问题,举个例子:
1 #include "stdafx.h"
2
3 void Function()
4 {
5 char a = (char)1;
6 short b = (short)2;
7 int c = (int)3;
8
9 char d = (char)c;
10 }
11
12 int main(int argc, char* argv[])
13 {
14 Function();
15 return 0;
16 }
在这个例子中,变量c为int类型,我们定义了一个char类型的变量d,将c赋给d时,前面加个小括号就是明确告诉编译器要把这个int类型的变量c转换成char类型,然后赋给char类型的变量d,这在C语言语法中是合法的,但是是不是所有的类型都可以进行强转呢?来看看下面的例子:
1 #include "stdafx.h"
2
3 struct Student
4 {
5 int hight;
6 int weight;
7 };
8
9 void Function()
10 {
11 char a = (char)1;
12 short b = (short)2;
13 int c = (int)3;
14
15 char d = (char)c;
16 //加小括号明确告诉编译器我要转换什么类型,编译一下,看这个情况可以不可以
17 Student e = (Student)c;
18 }
19
20 int main(int argc, char* argv[])
21 {
22 Function();
23 return 0;
24 }
看一看编译信息,看结构体允许这样转不,
调试信息中,可以看到编译器很明确的告诉我们,无法将int类型转换成struct Student,看来也不是所有的类型之间都可以相互转换~~~
但是基础类型,char、short、int之间可以相互转换,基础类型向结构体类型转换就不允许了!
b、带星号(*)类型之间的转换
1 #include "stdafx.h"
2
3 struct Student
4 {
5 int hight;
6 int weight;
7 };
8
9 void Function()
10 {
11 char* x;
12 int* y;
13
14 x = (char*)10;
15 y = (int*)20;
16
17 short* z = (short*)y;
18 char* a = (char*)y;
19 int* b = (int*)x;
20 }
21
22 int main(int argc, char* argv[])
23 {
24 Function();
25 return 0;
26 }
再来看看结构体带星类型能不能与普通带星类型进行转换
1 #include "stdafx.h"
2
3 struct Student
4 {
5 int hight;
6 int weight;
7 };
8
9 void Function()
10 {
11 char* x;
12 int* y;
13
14 x = (char*)10;
15 y = (int*)20;
16
17 short* z = (short*)y;
18 char* a = (char*)y;
19 int* b = (int*)x;
20
21 Student* student = (Student*)x;
22 Student* student2 = (Student*)y;
23 Student* student3 = (Student*)z;
24 }
25
26 int main(int argc, char* argv[])
27 {
28 Function();
29 return 0;
30 }
根据编译结果可以看出,是可以的
这一块的反汇编代码就不贴了,之前在汇编里头,byte、word、dword类型转换的时候都有过测试
二、&符号的使用
先不介绍&是怎么用的,什么概念,我们抛出问题例子来看&符号,看看编译器怎么说
1 #include "stdafx.h"
2
3 void Function()
4 {
5 char a = 10;
6 short b = 20;
7 int c = 30;
8
9 char d = &a;
10 }
11
12 int main(int argc, char* argv[])
13 {
14 Function();
15 return 0;
16 }
例子中,我们使用char类型的变量d来接受&a的值,我们编译一下
编译器说,没办法将一个char* 类型转换成char类型,看来在变量前面加上了&符号之后,这个变量就成了带*类型
我们将代码更改成如下:
1 #include "stdafx.h"
2
3 void Function()
4 {
5 char a = 10;
6 short b = 20;
7 int c = 30;
8
9 char* d = &a;
10 }
11
12 int main(int argc, char* argv[])
13 {
14 Function();
15 return 0;
16 }
这个时候发现编译通过了
那么,我们在这里不妨来自己定义一下&符号?&是地址符,类型是其后面的类型加一个“*”,任何变量都可以使用&来获取地址,但不能用在常量上。
这下我们可以来回答了,&a是char* 类型, &b是short* 类型, &c是int* 类型
再来看看下面的例子
&pa是char** 类型, &pb是short** 类型, &pc是int** 类型
基本类型的定义探测完了,我们就来看看完整写法
1 #include "stdafx.h"
2
3 void Function()
4 {
5 char a = 10;
6 short b = 20;
7 int c = 30;
8
9 char* pa = (char*)&a;
10 short* pb = (short*)&b;
11 int* pc = (int*)&c;
12
13 //简写为:
14 char* pa = &a;
15 short* pb = &b;
16 int* pc = &c;
17
18 }
19
20 int main(int argc, char* argv[])
21 {
22 Function();
23 return 0;
24 }
1 #include "stdafx.h"
2
3 void Function()
4 {
5 char a = 10;
6 short b = 20;
7 int c = 30;
8
9 char* pa = &a;
10 short* pb = &b;
11 int* pc = &c;
12
13 char** ppa = (char**)&pa;
14 short** ppb = (short**)&pb;
15 int** ppc = (int**)&pc;
16
17 //简写为:
18 char** ppa = &pa;
19 short** ppb = &pb;
20 int** ppc = &pc;
21 }
22
23 int main(int argc, char* argv[])
24 {
25 Function();
26 return 0;
27 }
三、“带*类型”的特征探测:求值
int* px;
int** px2;
int*** px3;
int**** px4;
//*(px) 是什么类型?
//*(px2) 是什么类型?
//*(px3) 是什么类型?
//*(px4) 是什么类型?
1 #include "stdafx.h"
2
3 void Function()
4 {
5 int x = 10;
6 int* px = &x;
7 int y = *px;
8
9 }
10
11 int main(int argc, char* argv[])
12 {
13 Function();
14 return 0;
15 }
反汇编代码如下:
1 0040D490 push ebp
2 0040D491 mov ebp,esp
3 0040D493 sub esp,4Ch
4 0040D496 push ebx
5 0040D497 push esi
6 0040D498 push edi
7 0040D499 lea edi,[ebp-4Ch]
8 0040D49C mov ecx,13h
9 0040D4A1 mov eax,0CCCCCCCCh
10 0040D4A6 rep stos dword ptr [edi]
11 0040D4A8 mov dword ptr [ebp-4],0Ah
12 0040D4AF lea eax,[ebp-4]
13 0040D4B2 mov dword ptr [ebp-8],eax
14 0040D4B5 mov ecx,dword ptr [ebp-8]
15 0040D4B8 mov edx,dword ptr [ecx]
16 0040D4BA mov dword ptr [ebp-0Ch],edx
17 0040D4BD pop edi
18 0040D4BE pop esi
19 0040D4BF pop ebx
20 0040D4C0 mov esp,ebp
21 0040D4C2 pop ebp
0040D4A8 mov dword ptr [ebp-4],0Ah ;将0xA(十进制的10)放到局部变量ebp-4中,这里我们的局部变量定义的是x
0040D4AF lea eax,[ebp-4] ;取ebp-4的地址放入eax中
0040D4B2 mov dword ptr [ebp-8],eax ;将eax的值放入局部变量ebp-8中,这里我们的局部变量定义的是px,它的类型是int*类型
0040D4B5 mov ecx,dword ptr [ebp-8] ;将ebp-8的值放入到ecx中
0040D4B8 mov edx,dword ptr [ecx] ;取ecx值所代表的地址中的值放入edx中,也就是取ebp-8(px)的内容并当做地址,取这个地址的内容
0040D4BA mov dword ptr [ebp-0Ch],edx ;最后将取出来的值放到ebp-0xc中,ebp-0xc是我们的局部变量y
1 #include "stdafx.h"
2
3 void Function()
4 {
5 int x,y;
6 int* px;
7 int** px2;
8 int*** px3;
9
10 x = 10;
11 px = &x;
12 px2 = &px;
13 px3 = &px2;
14
15 y = *(*(*(px3)));
16 }
17
18 int main(int argc, char* argv[])
19 {
20 Function();
21 return 0;
22 }
观察这段代码的反汇编,这里我不做解释了,解释起来很麻烦,也不算是麻烦吧,读者稍微有点汇编底子,相信也不会看我啰嗦
0040D490 push ebp
0040D491 mov ebp,esp
0040D493 sub esp,54h
0040D496 push ebx
0040D497 push esi
0040D498 push edi
0040D499 lea edi,[ebp-54h]
0040D49C mov ecx,15h
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-0Ch],eax
0040D4B5 lea ecx,[ebp-0Ch]
0040D4B8 mov dword ptr [ebp-10h],ecx
0040D4BB lea edx,[ebp-10h]
0040D4BE mov dword ptr [ebp-14h],edx
0040D4C1 mov eax,dword ptr [ebp-14h]
0040D4C4 mov ecx,dword ptr [eax]
0040D4C6 mov edx,dword ptr [ecx]
0040D4C8 mov eax,dword ptr [edx]
0040D4CA mov dword ptr [ebp-8],eax
0040D4CD pop edi
0040D4CE pop esi
0040D4CF pop ebx
0040D4D0 mov esp,ebp
0040D4D2 pop ebp
0040D4D3 ret
总结:
1、带*类型的变量,可以通过在其变量前加*来获取其指向内存中存储的值.
2、在带*类型的变量前面加*,类型是其原来的类型减去一个*.
四、用指针操作数组
char arr[10];
char* p = &arr[0]; //取数组第一个元素的地址
char* p2 = arr; //简写
看看实例吧
1 #include "stdafx.h"
2
3 void CharArray()
4 {
5 char arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
6
7 char* p = &arr[0]; //取数组第一个元素的地址
8 //char* p2 = arr; //简写
9 for (int i = 0; i < 10; i ++)
10 {
11 printf("%d ", *(p + i));
12 }
13 printf("\n");
14 }
15
16 void ShortArray()
17 {
18 short arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
19
20 short* p = &arr[0]; //取数组第一个元素的地址
21 //char* p2 = arr; //简写
22 for (int i = 0; i < 10; i ++)
23 {
24 printf("%d ", *(p + i));
25 }
26 printf("\n");
27 }
28
29 void IntArray()
30 {
31 int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
32
33 int* p = &arr[0]; //取数组第一个元素的地址
34 //char* p2 = arr; //简写
35 for (int i = 0; i < 10; i ++)
36 {
37 printf("%d ", *(p + i));
38 }
39 printf("\n");
40 }
41
42 int main(int argc, char* argv[])
43 {
44 CharArray();
45 ShortArray();
46 IntArray();
47 return 0;
48 }
总结:
1、&arr[0]代表取数组中第一个元素的地址,可以省略为数组名.
2、*(p+i) = p[i]
将数组中的值进行倒置,利用指针
1 #include "stdafx.h"
2
3 void Function()
4 {
5 int arr[5] = {1, 2, 3, 4, 5};
6 int length = 5;
7 int* parr = arr;
8 int* pfirst = arr;
9 int* pend = &arr[length-1];
10
11 //..此处添加代码,使用指针,将数组的值倒置
12 for (; pfirst <= pend; pfirst ++, pend --)
13 {
14 int temp = *pend;
15 *pend = *pfirst;
16 *pfirst = temp;
17 }
18
19
20 //打印数组值的代码已经写完,不需要修改
21 for(int k=0; k < 5; k ++)
22 {
23 printf("%d ", *(parr + k));
24 }
25 printf("\n");
26 }
27
28
29 int main(int argc, char* argv[])
30 {
31 Function();
32 return 0;
33 }