高级指针话题

由于二级指针在前边已经做过详细介绍,在此不做过多解释。接下来我们从指针的声明开始逐步深入。
一、声明
请看下面这段代码:

#include<stdio.h>

int main()
{
    int* p, a;
    a = 100;
    p = &a;
    printf("a=%d &a=%x p=%x &p=%x", a, &a, p , &p);
}

其在Dev-C++中的运行结果如下:
运行结果
这段代码向我们详细解释了指针的作用,并且进一步展示了地址(一般为左值 )和值(一般为右值)的区别与联系。注意声明部分的代码int* p, a;,我们将*与类型(int)放在一起形成(int*),从以往的编程经验来看,后边声明的两个变量pa的类型都应该是int*,但从运行结果来看,显然不是如此。*只作用于变量p,而a仍然只是一个普通的int型变量。因而我们可以得出*是和变量结合作为一个整体的,而不是和类型说明符结合。所以为了以后所写代码清晰明了,你可以在声明指针的时候采用这样的写法:

int *p, a;

指针和数组、函数结合在一起形成的高级声明不难理解,在此我不做过多解释,如果想要简单了解声明的解析方式,可以按照我上一期博客“C语言编程技巧”的第14条和第17条了解学习,也可以从书籍《C专家编程》的第三章深入学习(主要在64~68页)。
二、函数指针
顾名思义,函数指针就是指向函数的指针,它和函数的返回值是一个函数指针的函数是两个概念,不要混为一谈。
1.函数指针的声明
以下面的代码为例简要说明:

int f(int);
int (*pf)(int) = &f;

这样就声明(并且初始化)了一个函数指针pf
注:和其他指针一样,对函数指针进行间接访问之前必须把它初始化为指向某个函数。另外,在函数指针的初始化之前具有函数f的原型也很重要,否则会编译出错
附:返回值为函数指针的函数的一般声明为:int(*fun())()
2.函数指针的作用

  • 将一个函数作为参数传递给另一个函数。一般用于实现回调函数,这样可以实现一个函数的通用。
  • 转换表(转换表其实就是一个函数指针数组,它可以将具体操作与选择操作的代码分开,避免程序很长,难于阅读和维护)

(注:此处只对概念解析,具体作用的代码不做进一步解释说明(因为单独一个作用就可以写一篇博客),有意者可以阅读《C和指针》第13章)。
三、指针数组(Iliffe向量display
1.指针数组声明
可以通过声明了一个一维指针数组,其中每个指针指向一个字符串来取得类似二位字符数组的效果(这往往是指针数组的神奇之处),其声明如下:

char *pea[4];

(注:这种数组必须用指向为字符串而分配的内存的指针进行初始化,可以在编译时用一个常量初始值,也可以在运行时用for循环和malloc结合初始化,具体可以参考《C专家编程》第10章)
附:char *pea[4]把“pea”声明为一个具有4个元素的数组,每个元素的类型是一个指向字符的指针或者指向一个字符串的指针,单纯从声明无法区分两者。千万不要将它和(char*)pea[4]搞混,后者表示一个指向“具有4个字符类型元素的数组”的指针,这是由于优先级的问题导致。
2.用途

  • 存储各行长度不一的表(节省空间,避免不必要的数组空间浪费,我们将长度不一的字符串数组可以称为锯齿状数组)
  • 在一个函数调用中传递一个字符串数组

附:形参和实参的转换

名称 实参 所匹配的形式参数
数组的数组 char c[8][10] char(*)[10] 数组指针
指针数组 char *c[15] char **c指针的指针
数组指针 char (*c)[64] char (*c)[64]不改变
指针的指针 char **c char **c不改变

3.实际上,我们没有办法向函数传递一个普通的多维数组。这是因为我们需要知道每一维的长度,以便为地址运算提供正确的长度单位,在形参与实参的转换中,长度信息已经丢失。
四、数组指针
严格的来说,无法直接从函数返回一个数组。但是,可以让函数返回一个指向任何数据结构的指针,当然也可以是一个指向数组的指针。
1.声明

int (*paf())[20];

这里,paf是一个函数,它返回一个指向包含20个int元素的数组的指针。
(注:千万不要从函数中返回一个指向函数局部变量的指针,因为局部变量保存在堆栈区,随着函数调用的结束,该局部变量会被销毁,从而导致返回一个没意义的值。要想解决这个问题,可以给该局部变量前加上static关键字,将其保存在数据段,但最好的解决办法便是调用者自己分配内存来保存函数的返回值)
2.相关问题解析

为什么NULL指针会导致printf函数崩溃?

请看下面这段代码:

#include<stdio.h>

int main()
{
    char *p = NULL;
    printf("%s", p);
} 

这段代码在Dev-C++中运行结果如下:
这里写图片描述
在以前的编译器中运行以上代码会出现一个未定义的行为,原因在于C标准规定%s说明符的参数必须是一个指向字符数组的指针,由于NULL并不是一个这样的指针,所以程序会崩溃。

这些都是比较常用的高级指针,如果还有问题,随时call我,乐此不疲。

猜你喜欢

转载自blog.csdn.net/sqrt_2/article/details/81503637
今日推荐