指针内容详解

前言

  • 首先我们要知道什么是指针,指针就是个变量,用来存放地址,地址唯一标识一块内存空间。指针的大小是固定的4/8个字节(32位平台/64位平台),并且指针是有类型,指针的类型决定了指针的 ± 整数的步长,指针解引用操作的时候的权限,因此我们以不同类型的指针展开分开讲解。

1.字符指针

  • 字符指针的模样是char* ,通常用来存储字符或字符串的地址,比如:
int main()
{
    char ch = 'w';
    char *pc = &ch;
    *pc = 'w';
    return 0;
}
  • 这其实就是将字符‘w’的地址存放到了指针变量pc当中,当使用它的时候我们只需要对它进行解引用操作就可以了,解引用操作符是 * ,在上面的 *pc当中, *pc = = ch = = ’ w ',这里只是说等价,不是 == 操作符。上面也说它还可以存储字符串的地址,像这样:
int main()
{
    const char* pstr = "hello world";
    printf("%s\n", pstr);
    return 0;
}
  • 那我们可以思考这是将“ hello world " 的全部地址都存放到指针变量pstr当中吗?其实并不是的,它存放的只有首字符‘ w ’ 的地址,但是它与数组相似,会根据第一个元素的地址依次找到后面的元素,从而将它们打印出来。

2.指针数组

  • 这个也是很好理解,比如int arr[10] 是整型数组,arr是数组名,存放的元素是整型,所以是整型数组。那么指针数组也是一样,首先是个数组,其次存放元素是指针,写出来就是int* arr[10] ,这里也就是整形指针数组,当然还有char* arr[10],我就不一一列举了。

3.数组指针

  • 那我们前面讲了指针数组,指针数组是指针呢?还是数组呢?根据上面的讲解我们知道指针数组是一个数组,那么同样的理解数组指针应该就是一个指针
  • 那么数组指针又是什么样的呢?我们最熟悉的是整型指针,比如int* pc,我们一步一步来分析,首先它是个指针,写法为* pc,其次指向的是整型,那么就是int* pc。数组指针也可以这么去分析,首先是个指针* ptr,再然后指向的是一个数组,那么就是 (*ptr)[10],每个数组的元素类型是int,那么最终的写法就是int (*ptr)[10]。
  • 至于这里为什么带括号,是因为‘ [ ] ’ 的优先级比‘ * ’ 要高,如果不带括号ptr就会先于[ ] 结合。那么ptr就不在是指针了,ptr[ ]就变成了一个数组,存放的元素为整型指针,从而变成了指针数组int* ptr[10],而不是数组指针,因此必须加上()来保证p先和*结合。

&数组名与数组名

  • 这里我们在额外讲解一些知识,我们都是数组名是首元素的地址,那么&数组名与数组名一样吗?我们来看看以下代码:
#include <stdio.h>
int main()
{
 int arr[10] = { 0 };
 printf("arr = %p\n", arr);
 printf("&arr= %p\n", &arr);
 printf("arr+1 = %p\n", arr+1);
 printf("&arr+1= %p\n", &arr+1);
 return 0;
}
  • 如果&数组名与数组名是相等的话,那么打印出来的结果是不是一样的呢?让我们来看结果:在这里插入图片描述
  • 我们发现arr与&arr的地址是一样的,说明都是首元素的地址,但是都+1之后的结果为什么不同呢?我们会发现006FF9C4与006FF9C8之间差了一个4,刚好是一个int的大小,说明arr+1只是跳过了一个元素大小,那我们看006FF9C4与006FF9EC,相差了28,(注意:这里的地址都是用16进制表示的)将十六进制28转化为十进制是(216 ^ 1 + 816 ^ 1) = 40,算法与二进制转十进制一样,只是把10换成了16。40刚好是10个整型的空间,说明跳过的刚好是一个数组的大小,此时我们就知道了arr是首元素的地址,而&arr取出的是整个数组的地址。
  • 根据上面的代码我们发现,其实&arr和arr,虽然值是一样的,但是意义是不一样的。实际上:&arr 表示的是数组的地址,而不是数组首元素的地址。

4.函数指针

  • 顾名思义,它本质上还是一个指针,但是指向的是函数,那我们就先举个例子把,比如int Add(int x,int y),那么这又该如何表示呢?我们可以按照之前的思路,首先它是一个指针*pf,然后指向的是函数,那么就是(*pf)(),而每个函数的参数是不一样的,因此我们在书写的时候也要带上参数的类型,那么就是(*pf)(int,int),再然后就是函数的返回类型是int,那么我们的函数指针就是int (*pf)(int,int),使用的话也很简单,只需要 int ret = (*pf)(5,7)就可以了,其实这个 * 写不写都可以,此处写上只是方便理解。
  • 那就让我们看一个代码:(* (void ( * ) ( ) ) 0 )( );这个代码是什么意思呢?突破口当然是0了,就它不一样是个数字,那我们就来看 0 的前面是什么,以一个括号来看前面是:( void( * )( ) ),最外面的这一层括号其实是强制类型转换,意思就是将0的这个地址强制类型转换成了void( * )( ),它是一个函数指针,参数为空,返回类型为void,也就是在0这块地址空间被换成了一个函数指针,在0这里进行调用。

5.函数指针数组

  • 一样的解读思路,它是一个数组,存放的元素类型是函数指针,这里就不多讲解了,它的书写方式是int (* pf[10] )( int ),这样就是一个函数指针数组,是一个数组,存放了10个函数指针。
  • 那么这有什么用呢?当我们些一些相似的函数时,就可以使用函数指针数组,这可以极大的方便我们的书写,我们来看代码:
#include <stdio.h>
int add(int a, int b)
{
     return a + b;
}
int sub(int a, int b)
{
     return a - b;
}
int mul(int a, int b)
{
     return a*b;
}
int div(int a, int b)
{
     return a / b;
}
int main()
{
     int x, y;
     int input = 1;
     int ret = 0;
     int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表
     while (input)
     {
          printf( "*************************\n" );
          printf( " 1:add           2:sub \n" );
          printf( " 3:mul           4:div \n" );
          printf( "*************************\n" );
          printf( "请选择:" );
      scanf( "%d", &input);
          if ((input <= 4 && input >= 1))
         {
          printf( "输入操作数:" );
              scanf( "%d %d", &x, &y);
              ret = (*p[input])(x, y);
         }
          else
               printf( "输入有误\n" );
          printf( "ret = %d\n", ret);
     }
      return 0;
}
  • 如果正常写的话我们可能会用switch结构来进行选择,并且每次都要写出提示用户选择哪一个操作,这样用函数指针数组的话就可以极大的快捷了,并且也方便书写。

6.指向函数指针数组的指针

  • 它是一个指针,指向一个数组,数组存放的元素类型时函数指针,这就是指向函数指针数组的指针。

  • 首先是一个指针:*pf

  • 然后指向数组:(*pf)[10]

  • 再然后存放的是函数指针: int ( (*pf)[10] )( int ) 或 int ( * (*pf)[10] )( int ),这个‘ * ’写不写都可以的,上面有提到过,那就看看是如何定义的吧。

void test(char* str)
{
 printf("%s\n", str);
}
int main()
{
 //函数指针 pf
 void (*pf)(char*) = test;
 //函数指针的数组 pfArr
 void (*pfArr[5])(char* str);
 pfArr[0] = test;
 //指向函数指针数组 pfArr的指针 ppfArr
 void (*(*ppfArr)[5])(char*) = &pfArr;
 return 0;
}

总结

  • 好耶!!又双叒叕完成了一篇文章,此次文章还没写完,暂时先写这么多啦,如果大家有什么疑问可以私信我哦,我会为大家解答并且把大家的问题在本文中详细的写出来的!!
  • 希望这篇文章能对大家对指针的理解更深一层,如果觉得不错👍,可以给博主一个免费的一键三连,点赞、收藏+关注,谢谢大家啦!!如果有什么疑问或者发现了文章中的问题,可以在评论区留言喔。希望大家都会有所收获喔!!
  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不如小布.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值