天天看点

C++指针的深度理解

前言

笔者会从各种的例子和面试题入手,将逐步去分析指针的知识点和指针的一些高级的用法。

1.介绍指针的基本知识点

C++指针的深度理解

第一个例子,也许一些人会疑惑为什么t是512了,先看下面的图 

C++指针的深度理解

从笔者自己画的图分析,引用(&)这个符号返回的是这个类型最低位的地址而不是最高位数的地址,还有就是int型指针和char型的指针的区别到底在哪里?不同类型的指针唯一区别就是偏移量的不同,它们存的都是地址,但是char型指针偏移量是1个字节,而int型指针的偏移量是4个字节(void *的指针是只有地址 没有偏移量),所以pChar+1就可以指向int型数据内部的第二个字节位置的地址,这个访问看出上去非法的,但是确实可行,因此t就是2的9次方得到512也不奇怪。这样的指针可以说破坏了int型的结构,可以看出指针的灵活,如果没有访问权限的问题,指针可以随意修改任何程序的数值,指针也可以直接赋给它一个地址,如下面的图

C++指针的深度理解

可以看出指针非常强大,但是因为系统有访问权限的设置,就算知道另外一个程序的数值的地址也难以修改,当然可以通过Dll注入去修改其他程序的数值(这种方法笔者有时间会去详细的介绍的),接下让我们去看一下关于指针的一些简单的面试题。

C++指针的深度理解

第一个ptr指针指向是a往后偏移1个字节的地址,然后将其强制转换成int *,让这个指针的偏移量是4个字节。

第二个ptr指针指向是a往后偏移4个字节的地址,因为先将(&a)转换成int型指针了,所以之后的加1就是4个字节的偏移量(sizeof(int))。

第三个ptr指针直接指向一个(int)a+1的地址,笔者也不知道到底指向那里了,这个和上述直接赋值一个地址一样的效果。

2.介绍指针和数组的关系

一维数组名其实和指针常量基本没有差别,唯一的区别就是指针常量自身占据栈上的内存空间指向数组的首地址,而一位数组名本身的地址就是这个数组的首地址(变量的别名和指针也有这个区别),并且它们的指向地址都不能改变,如下图所示。

C++指针的深度理解

n级指针可以表示n维数组,笔者接下来会用二级指针去表示二维数组,表达一下二级指针的基础知识点,希望一些不太了解指针的人可以举一反三,去深入了解各种的n级指针,如图所示。

C++指针的深度理解

从图中可以知道二级指针向堆申请的空间不是连续的,二级指针p的偏移量是sizeof(int)*n(也就是一行为偏移量),一级指针*p的偏移量是sizeof(int),二级指针第一次解引用就会成为一级指针,一级指针解引用就是这个地址存的值,既然谈到了二级指针,接下来谈一下int *p[n]和int (*p)[n]的区别,int *p[n]是数组指针,也就是说p[0],p[1]..都是一个指针,而int (*p)[n]是一级行指针,偏移量是sizeof(int)*n,这种指针只能访问二维数组的行的首地址,里面的具体单位无法访问,以此类推我们可以知道三级指针的偏移量是整个二维数组。

3.函数指针

接下来笔者用指针去写一个转移表,让读者们知道指针不仅可以指向任何数据类型也可以指向函数的首地址,下面就是转移表代码。

#include<iostream>
using namespace std;
double add(double ,double );
double sub(double ,double );
double mul(double ,double );
double div(double ,double );
int main(void)
{
    double f=0;
    double (*work[4])(double ,double)={add,sub,mul,div};
    f=work[0](2.3,3.1);
    cout<<f<<endl;
    return 0;
}
double add(double a,double b)
{
    return a+b;
}
double sub(double a,double b)
{
    return a-b;
}
double mul(double a,double b)
{
    return a*b;
}
double div(double a,double b)
{
    return a/b;
}
           

红色代码的部分就是数组函数指针,回调函数就是将一个函数指针作为参数传递给另外一个函数去调用,了解C#语言的,应该知道C#的委托和函数指针本质基本是一样的,指针大致的用法就这么多了,希望大家看了这篇文章对指针的了解有所提升,温馨提示对指针还不太掌握的,尽量使用指针常量(虽然这么做失去了灵活性),用指针加某一个单位移动指向的位置(p+n),而不是指针自增去移动(p+=n),因为自增去移动的时候最后到底指向那里了,有可能都是未知的。如果那里有错,欢迎大牛改正。

继续阅读