C/C++学习笔记:指针和引用

181 阅读5分钟

指针数组和数组指针

分清楚这二者的区别只需要关注其后两个字:

指针数组本质为数组,数组中存储着指针

数组指针本质为指针,该指针指向一个数组

然后我们还需要明确一下优先级的顺序:() > [] > *

    int *p1[5];
    //根据优先级,先看[],由此看出p1为一个长度为5的数组
    //再结合*,该数组元素为指针类型,因此为指针数组
    
    int (*p2)[5];
    //根据优先级,先看(),由此看出p2为一个指针,该指针指向一个长度为5的数组
    //因此为数组指针

数组指针例子:

    int a[5]={1,2,3,4,5};  
    //定义一个一维数组
    int (*P)[5]
    //定义一个数组指针,步长为5
    p=&a;
    //将数组a的首地址赋值给p
    
    printf("%p\n",a);    //输出数组a的地址
    printf("%p\n",p);    //p存储a的地址,输出数组a的地址
    printf("%p\n",*p);   //输出数组a的地址
    printf("%p\n",p[0]); //输出数组首元素的地址
    printf("%d\n",**p);  //可以理解为*(*p),输出a[1]的值
    printf("%d\n",*p[0]);//根据优先级,先看p[0]为首元素地址,*解引用后输出a[1]的值
    
    int b[3][4];
    //定义一个二维数组
    int(*p1)[4];
    //定义一个数组指针,指向含四个元素的一位数组
    p1=b;
    //将该二维数组首地址赋值给p1,p1=b与p1=&b[0]等价
    p1++;
    //此语句执行后p1指向从b[0][]变为b[1][]
    

由上述可知,数组指针也称指向一维数组的指针,所以数组指针也称行指针

指针数组例子:

    int a = 1;
    int b = 2;
    int *p[2];
    p[0] = &a;
    p[1] = &b;

    printf("%p\n", p[0]);  //a的地址
    printf("%p\n", &a);    //a的地址
    printf("%p\n", p[1]);  //b的地址
    printf("%p\n", &b);    //b的地址
    printf("%d\n", *p[0]); //p[0]表示a的地址,则*p[0]表示a的值
    printf("%d\n", *p[1]); //p[1]表示b的地址,则*p[1]表示b的值


    //将二维数组赋给指针数组
    int *p1[3]; //一个一维数组内存放着三个指针变量,分别是p[0]p[1]p[2],所以要分别赋值
    int c[3][4];
    for (int i = 0; i<3; i++)
        p1[i] = c[i];

一点小补充

    int arr[5]={1,2,3,4,5};
    int (*p1)[5]=&arr; //正确
    int (*p2)[5]=arr;  //错误

事实上arr和&arr的值相同,都是表示数组的地址,那为何在编译时会报错呢?

原因在于在C语言中赋值符号"="的两边数据类型要相同,若不同则需要显式或隐式类型转换

在上述代码中,p1和p2都是数组指针,指向整个数组,&arr表示整个数组的地址,由此正确, 但arr表示的是数组首元素的地址(指向单个元素的指针),虽然值相同,但类型不同,由此会提示错误信息

指针函数和函数指针

与上述概念类似,要分清这二者的区别同样只需要关注其后面两个字:

指针函数本质为一个函数,其返回值类型为指针类型

    int *func();
    //指针函数,返回值类型为int *型
    void *func1();
    //void *表示可以返回任意类型的指针,但接收void *函数返回值时需要强转
    //但不建议这么使用,因为强转有风险

函数指针本质为一个指针,其指向一个函数的地址,通俗点说就是一个指向函数的指针

    int (*func)();
    //定义了一个函数指针
    
    //函数指针需要将一个函数的地址赋值给它,一般来说有两种写法
    func = Function;
    func = &Function;
    //&不是必须的,因为函数名就代表了它的地址
    
    //调用函数指针的方法也有两种
    x = (*func)();
    x = func();

引用(C++)

需要注意的是,C语言中是没有引用的,引用相当于为对象取了另外一个名字

    int val=100;
    int &reval=val;    //reval指向val,是val的另外一个名字
    int &reval2;       //错误写法,引用必须被初始化

初始化变量时,初始值会被拷贝到新建的对象中,然而定义引用时,程序把引用和它的初始值绑定在一起,而不是拷贝给引用,一旦初始化完成,引用就会和初始值对象一直绑定,无法令引用重新绑定到另外一个对象

    int &reval = 10;    //错误,引用类型初始值必须是一个对象
    double dval = 3.14;
    int &reval = dval;  //错误,此处的引用类型必须要int型对象

补充:引用即别名,只是为一个已经存在的对象所起的另外一个名字,引用本身不是一个对象,不能定义引用的引用,也不能定义指向引用的指针,但指针式对象,存在对指针的引用

    int i=42;
    int *p;
    int *&r=p;    //r时一个对指针p的引用
    
    r=&i;        //r引用了一个指针,因此给r赋值&i就是令p指向i
    *r=0;         //解引用r得到i,也就是p指向的对象,将i的值改为0

注:要理解r的类型,可以从右往左阅读r的定义,离变量名最近的符号对变量有最直接的影响,例如:&离r最近,由此r时一个引用,其余部分用以确定r引用的类型是什么,此例中* 说明r引用的是一个指针