目录

  • 1 第一章 C语言简介
    • 1.1 C语言前世今生
    • 1.2 主流开发环境介绍
    • 1.3 第一个小程序解析
    • 1.4 常见编译错误
    • 1.5 章节知识点小结
  • 2 算法基础
    • 2.1 算法-程序的灵魂
    • 2.2 算法的描述-流程图
  • 3 数据类型与运算符
    • 3.1 数据描述
    • 3.2 运算符和表达式1
    • 3.3 运算符和表达式2
    • 3.4 章节知识点小结
  • 4 顺序结构程序设计
    • 4.1 输入和输出
    • 4.2 顺序结构程序设计
    • 4.3 章节知识点小结
  • 5 选择结构程序设计
    • 5.1 关系运算符和关系表达式
    • 5.2 逻辑运算符和逻辑表达式
    • 5.3 if语句
    • 5.4 条件运算符
    • 5.5 switch语句
    • 5.6 章节知识点小结
  • 6 循环结构程序设计
    • 6.1 while循环结构
    • 6.2 do_while循环结构
    • 6.3 for循环结构
    • 6.4 循环的嵌套
    • 6.5 break语句和continue语句
    • 6.6 章节知识点小结
  • 7 数组
    • 7.1 一维数组
    • 7.2 二维数组
    • 7.3 字符数组
    • 7.4 章节知识点小结
  • 8 函数
    • 8.1 子程序设计
    • 8.2 函数定义
    • 8.3 函数的调用
    • 8.4 局部变量和全局变量
    • 8.5 参数传递
    • 8.6 函数递归调用
    • 8.7 章节知识点小结
  • 9 指针
    • 9.1 指针的基本概念
    • 9.2 指针变量的定义及引用
    • 9.3 通过指针引用数组元素
    • 9.4 指向多维数组的指针和指针变量
    • 9.5 用指向数组的指针作函数参数
    • 9.6 指针与字符串
    • 9.7 函数指针和指针函数
    • 9.8 章节知识点小结
  • 10 用户自己建立数据类型
    • 10.1 定义和使用结构体变量
    • 10.2 使用结构体数组
    • 10.3 结构体指针
    • 10.4 章节知识点小结
  • 11 编译预处理
    • 11.1 宏定义预处理
    • 11.2 文件包含预处理
    • 11.3 条件编译预处理
    • 11.4 章节知识点小结
  • 12 文件
    • 12.1 文件的基本知识
    • 12.2 文件的基本操作
    • 12.3 章节知识点小结
函数指针和指针函数


函数指针和指针函数,在学习 C 语言的时候遇到这两个东西简直头疼,当然还有更头疼的,比如什么函数指针函数、指针函数指针、数组指针、指针数组、函数指针数组等等,描述越长其定义就越复杂,当然理解起来就越难,特别是刚开始学习这门语言的童鞋,估计碰到这些东西就已经要崩溃了,然后好不容易死记硬背下来应付考试或者面试,然后过了几天发现,又是根本不会用,也不知道该在哪些地方用,这就尴尬了。

今天这里只讲两个相对简单的,其实上面说那些太复杂的东西也真的很少用,即便是用了理解起来很麻烦,所以莫不如先深刻理解这两个比较容易的,并且项目中比较常用到。

1、指针函数

指针函数,简单的来说,就是一个返回指针的函数,其本质是一个函数,而该函数的返回值是一个指针。

声明格式为:*类型标识符函数名(参数表)

这似乎并不难理解,再进一步描述一下。

看看下面这个函数声明:

int fun(int x,int y);

这种函数应该都很熟悉,其实就是一个函数,然后返回值是一个 int 类型,是一个数值。

接着看下面这个函数声明:

int *fun(int x,int y);

这和上面那个函数唯一的区别就是在函数名前面多了一个*号,而这个函数就是一个指针函数。其返回值是一个 int 类型的指针,是一个地址。

这样描述应该很容易理解了,所谓的指针函数也没什么特别的,和普通函数对比不过就是其返回了一个指针(即地址值)而已。

指针函数的写法

int *fun(int x,int y);

int * fun(int x,int y)

int* fun(int x,int y);

这个写法看个人习惯,其实如果*靠近返回值类型的话可能更容易理解其定义。

我们来看一个非常简单的示例:

typedef struct _Data

{

   int a;

   int b;

}Data;

 

//指针函数

Data* f(int a,int b)

{

   Data * data = new Data;

   data->a = a;

   data->b = b;

   return data;

}

int main(int argc, char *argv[])

{

   QApplication a(argc, argv);

   //调用指针函数

   Data * myData = f(4,5);

   qDebug() << "f(4,5) = " << myData->a <<myData->b;

   return a.exec();

}

输出如下:

f(4,5) = 4 5

注意:在调用指针函数时,需要一个同类型的指针来接收其函数的返回值。

不过也可以将其返回值定义为 void*类型,在调用的时候强制转换返回值为自己想要的类型,如下:

//指针函数

void* f(int a,int b)

{

   Data * data = new Data;

   data->a = a;

   data->b = b;

   return data;

}

调用:

Data * myData =static_cast<Data*>(f(4,5));

其输出结果是一样的,不过不建议这么使用,因为强制转换可能会带来风险。

 

2、函数指针

函数指针,其本质是一个指针变量,该指针指向这个函数。总结来说,函数指针就是指向函数的指针。

声明格式:类型说明符 (*函数名)   (参数)

如下:

int (*fun)(int x,int y);

函数指针是需要把一个函数的地址赋值给它,有两种写法:

fun = &Function

fun = Function;

取地址运算符&不是必需的,因为一个函数标识符就表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。

调用函数指针的方式也有两种:

x = (*fun)();

x = fun();

两种方式均可,其中第二种看上去和普通的函数调用没啥区别,如果可以的话,建议使用第一种,因为可以清楚的指明这是通过指针的方式来调用函数。当然,也要看个人习惯,如果理解其定义,随便怎么用都行啦。

示例

int add(int x,int y)

{

   return x+y;

}

int sub(int x,int y){

   return x-y;

}

//函数指针

int (*fun)(int x,int y);

 

int main(int argc, char *argv[])

{

   QApplication a(argc, argv);

   //第一种写法

   fun = add;

   qDebug() << "(*fun)(1,2) = " << (*fun)(1,2) ;

      //第二种写法

   fun = &sub;

   qDebug() << "(*fun)(5,2) = " << (*fun)(5,3)  << fun(5,3)

   return a.exec();

}

输出如下:

(*fun)(1,2) =  3

(*fun)(5,2) =  2 2

上面说到的几种赋值和调用方式我都分别使用了,其输出结果是一样的。

 

3、小结

1)定义不同

指针函数本质是一个函数,其返回值为指针。

函数指针本质是一个指针,其指向一个函数。

2)写法不同

指针函数:int* fun(int x,int y);

函数指针:int (fun)(int x,int y);

可以简单粗暴的理解为,指针函数的是属于数据类型的,而函数指针的星号是属于函数名的。

再简单一点,可以这样辨别两者:函数名带括号的就是函数指针,否则就是指针函数。

3)用法不同

示例有详细描述。

这两个概念很容易搞混淆,一定要深入理解其两者定义和区别,避免犯错。


函数的参数不仅可以是整型、实型、字符型等数据,还可以是指针类型。它的作用是将一个变量的地址传送到另一个函数中。

【例】对输入的两个整数按大小顺序输出。

 要求:设计一个函数来实现两个整数交换

试分析下面程序能实现这一功能吗?

#include <stdio.h>

int main()

{ int a,b;  

  scanf("%d,%d",&a,&b);   

  if (a<b)  swap(a,b); 

  printf("a=%d,b=%d\n",a,b); 

  return 0;

 }

void swap(int x,int y) 

{ int temp;

   temp=x;  x=y;   y=temp;

}

解题思路:定义一个函数swap,将两个整型变量的地址作为实参传递给swap函数的形参指针变量,在函数中通过指针实现交换两个参数变量的值。

#include <stdio.h>

int main()

{void swap(int *x,int *y);  

  int a,b;  

  scanf("%d,%d",&a,&b); 

  if (a<b)  

     swap(&a,&b); 

  printf("a=%d,b=%d\n",a,b); 

  return 0;

 }    

void swap(int *x,int *y) 

{ int temp;

   temp=*x;     

   *x=*y;

   *y=temp;

}

小结:

如果想通过函数调用得到n个要改变的值:


① 在主调函数中设n个变量


② 设计一个函数,有n个指针形参。


③ 在主调函数中调用这个函数时,将这n个变量地址作实参传递给该函数的形参


④ 在执行该函数的过程中,通过形参指针变量,改变它们所指向的n个变量的值


⑤主调函数中就可以使用这些改变了值的变量