C语言、指针(二)

指针(二)

  • 类型转换
  • &符号的使用
  • “带*类型” 的特征探测:求值
  • 用指针操作数组

 一、类型转换

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("
");
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("
");
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("
");
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("
");                    
26 }                    
27 
28 
29 int main(int argc, char* argv[])
30 {
31     Function();
32     return 0;
33 }
原文地址:https://www.cnblogs.com/Reverse-xiaoyu/p/11749789.html