zoukankan      html  css  js  c++  java
  • C语言、指针(七)

    指针(七)

    • 数组指针
    • 函数指针

    一、多维数组指针

     1)用一维数组指针访问一维数组

      代码:
     1 void fun()
     2 {
     3     int arr[5] = {1,2,3,4,5};
     4  
     5     int (*p)[5] = &arr;
     6     printf("%d
    ", *(*(p) + 2));    //结果是3
     7  
     8     int (*px)[2] = (int (*)[2])arr;    //强转为宽度为两个int的数组指针类型
     9     printf("%d
    ", *(*(px + 1) + 1));    //结果是4
    10 }

       分析:

        取地址运算&后的arr是其类型加上一个*,也就是int (*)[5];
        &arr的值和arr的值一样都是数组的首地址,只是类型不一样;
        *p是数组类型,相当于int*,根据带*类型的加法特性,相当于加2个int宽度,也就是从执行1到指向了3;
        int*做解引用,结果是3;
        px是两个int的数组指针,用强转的方式给它赋值,此时指向arr首地址;
        px+1的结果是加上px的类型去掉一个*的宽度,也就是加上两个int的宽度;
        *(px+1)是数组类型,相当于int*,加1后再加上一个int宽度;
        总共加了3个int宽度,指向了4;

     2)一维数组指针访问二维数组

      代码:
    1 void fun()
    2 {
    3     int arr[2][5] = {{1,2,3,4,5},{6,7,8,9,10}};
    4  
    5     int (*p)[5] = (int (*)[5])arr;
    6     printf("%d
    ", *(*(p) + 2));    //结果是3
    7 }

       分析:

          多维数组转成汇编本质上和一维数组一样;

     3)二维数组指针访问一维数组

      代码:
     1 void fun()
     2 {
     3     int arr[15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
     4  
     5     int (*p)[2][3] =(int (*)[2][3]) arr;
     6     printf("%d
    ", *(*(*(p)+1) + 2));        //6
     7     printf("%d
    ", *(*(*(p+1)+1) + 2));        //12
     8     printf("%d
    ", p[1][1][2]);                //12
     9     printf("%d
    ", (*(*(p)+1))[2]);            //6
    10 }

    4)二维数组指针访问二维数组

      代码:
     1 void fun()
     2 {
     3     int arr[2][7] = {{1,2,3,4,5,6,7},{8,9,10,11,12,13,14}};
     4  
     5     int (*p)[2][3] =(int (*)[2][3]) arr;
     6     printf("%d
    ", *(*(*(p)+1) + 2));        //6
     7     printf("%d
    ", *(*(*(p+1)+1) + 2));        //12
     8     printf("%d
    ", p[1][1][2]);                //12
     9     printf("%d
    ", (*(*(p)+1))[2]);            //6
    10  
    11     int (*px)[2][7] = &arr;
    12     printf("%d
    ", (*px)[1][2]);            //10
    13 }

    二、函数指针

      代码和数据本质上都是一堆二进制数;

      因此,在编译器看来,函数和和变量没有本质的区别;
      编译器将函数名当做全局变量;
      只要是变量都可以加*,变成指针类型;

     1)函数指针的声明:            

        返回类型(*变量名)(参数表)         
        如:
    1 int (*pFun)(int,int);
     

    2)赋值

    1 pFun = (int (*)(int,int))10;      

      或者        

    1 pFun = 函数名.   
      可以给函数指针赋任何值,但为了能正确运行,需要将返回值和参数类型正确的函数的地址赋值给函数指针;
      将函数名赋值给函数指针时,编译器会检查函数的参数和返回值是否正确,如果正确则通过编译,所以没必要强制转型了; 

    3)使用

      和函数使用方式相同
     1 int plus(int x, int y)
     2 {
     3     return x+y;
     4 }
     5  
     6 void fun()
     7 {
     8     int (*p)(int,int) = plus;
     9     printf("%d",p(1,2));    //3
    10 }

    4)特性

      宽度:
          任何指针类型宽度为4,函数指针也一样;
      运算:++、--、+整数、-整数、相减
          因为函数的代码宽度不能确定,所以无法确定函数指针去掉一个*后的宽度;
          因此函数指针无法做运算;
      比较:
          函数指针可以做比较;
     

     5)别名表示

    1 typedef int (*Fun)(int,int);        
     
      这个不是变量的声明,而是为函数指针起个别名:Fun 相当于函数指针类型
    1 Fun p;   

      这个才是变量的声明,p是变量,Fun是类型.    

     

    6)应用

      利用函数指针将代码隐藏到数据区;
      可以达到保护函数的目的:
          将函数编译后生成的二进制文件抠出来,放在数据区,例如数组;
          然后在数组上做一些手脚,将代码隐藏起来;
          再将原来存储函数的地方变成0;
          别人就很难对代码做逆向分析了;    
     
      代码:
     1 unsigned char code[] =         //相当于两个int数相加的机器码
     2 {        
     3         0x55,
     4         0x8B, 0xEC,
     5         0x83, 0xEC, 0x40,
     6         0x53,
     7         0x56,
     8         0x57,
     9         0x8D, 0x7D, 0xC0,
    10         0xB9, 0x10, 0x00, 0x00, 0x00,
    11         0xB8, 0xCC, 0xCC, 0xCC, 0xCC,
    12         0xF3, 0xAB,
    13         0x8B, 0x45, 0x08,
    14         0x03, 0x45, 0x0C,
    15         0x5F,
    16         0x5E,
    17         0x5B,
    18         0x8B, 0xE5,
    19         0x5D,
    20         0xC3
    21 };
    22  
    23 void fun(){
    24     typedef int (*Fun)(int,int);
    25     Fun p = (int (*)(int,int))&code;
    26     printf("%d",p(1,2));    //3
    27 }
  • 相关阅读:
    Differential Geometry之第六章平面曲线的整体性质
    球盒问题
    Fiddler (二) Script 用法
    Mac下使用Fiddler
    更新mac自带的python
    在Linux里设置环境变量的方法(export PATH)
    关于null和undefined
    ANE在ios上的使用流程和问题解决
    starling 笔记
    Android SDK安装时碰到的问题之解决办法
  • 原文地址:https://www.cnblogs.com/Reverse-xiaoyu/p/11774480.html
Copyright © 2011-2022 走看看