2. 函数指针 和 指针函数
(1) 指针函数
概念 : 函数返回的结果是一个地址, 即返回的是一个指针, 这个函数就是指针函数;
指针函数格式 : 类型说明符 *函数名(参数列表);
-- 示例 : char *getchar(void);
-- 格式说明 : char * 表示函数返回值是指针, 调用这个函数, 返回一个指针指向的char类型;
运算符优先级 : 指针函数有两个运算符 * 和 (), ()的优先级 大于 *, 因此函数名首先和 () 结合, 然后在和 * 结合;
(2) 函数指针
概念 : 函数指针指向了函数的地址, 该指针可以调用函数;
函数指针格式 : 类型说明符 (*指针名)(参数列表);
-- 示例 : char (*getcahr)(void);
运算符优先级 : * 和 指针名 先结合, 然后在与参数列表结合;
函数指针使用 :
-- 声明函数指针 : void (*getchar)(), 声明函数指针需要带上参数列表;
-- 为函数指针赋值 : getchar = &get_char 或者 getchar = get_char 两种方法, & 可有可无;
-- 调用函数指针方法 : (*get_char)();
(3) 使用函数指针示例
示例需求 :
-- 获取字符串数组 : 从标准输入流中读取字符串数据, 将字符串放入字符串数组 char **;
-- 可选参数 : -n, 如果有可选参数, 就是按照数值顺序排序, 否则按照字典顺序排序;
代码 :
/*************************************************************************
> File Name: method_pointer_sort.c
> Author: octopus
> Mail: octopus_work.163.com
> Created Time: Sat 22 Mar 2014 11:45:47 PM CST
************************************************************************/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//定义排序字符串最大个数
#define MAXLINES 50
//每个字符串最多50个元素
#define MAXLEN 50
//定义一个 有MAXLINES 个 元素的数组, 数组中的元素师字符串, 即char类型指针
char *lineptr[MAXLINES];
* 声明函数指针
int (*p_get_line)(char *, int);
int (*p_read_lines)(char **, int);
void (*p_write_lines)(char **, int);
void (*p_q_sort)(void **, int, int, int (*)(void *, void*));
* 声明函数, 如果直接使用这些函数, 即使函数定义在主函数后面也不会出错
* 如果要将函数赋值给函数指针, 需要提前声明这些函数
int get_line(char *, int);
int read_lines(char **, int);
void write_lines(char **, int);
void q_sort(void *v[], int left, int right, int (*comp)(void *, void *));
int numcmp(char *, char *);
int main(int argc, char **argv)
char line[MAXLEN];
int len, nlines, numberic = 0;
p_read_lines = read_lines;
p_write_lines = write_lines;
p_q_sort = q_sort;
//如果参数中含有 -n 说明这是按照数值顺序排序, 否则就按照字典顺序排序
if(argc > 1 && strcmp(argv[1], "-n") == 0)
numberic = 1;
if((nlines = (*p_read_lines)(lineptr, MAXLINES)) >= 0)
* 注意 :
* 使用 ? : 表达式选择 函数指针, 函数指针类型转换的时候, 为每个选项都添加转换
* 如果只转换 ? : 结果, 会报出警告
(*p_q_sort)((void **)lineptr, 0, nlines - 1, numberic ? (int (*)(void*, void*))numcmp : (int (*)(void*, void*))strcmp);
(*p_write_lines)(lineptr, nlines);
return 0;
printf("error \n");
return 1;
//从标准输入流中读取数据, 放入字符串中
int get_line(char *line, int max)
int i, c;
for(i = 0; (c = getchar()) != '\n' && c != EOF && i < max - 1; i ++)
*(line + i) = c;
*(line + i) = '\0';
return i;
//从标准输入流中读取数据, 放入字符串数组
int read_lines(char *lineptr[], int max)
int len, nlines = 0;
char *p, line[MAXLEN];
while((len = get_line(line, MAXLEN)) > 0)
if(nlines >= MAXLINES || (p = malloc(sizeof(char) * (len + 1))) == NULL)
return -1;
strcpy(p, line);
*(lineptr + nlines) = p;
nlines++;
return nlines;
//将字符串数组中的元素打印出来
void write_lines(char *lineptr[], int nlines)
int i;
for(i = 0; i < nlines; i++)
printf("the %d char sequence is : %s \n", i, *(lineptr + i));
//数值比较
int numcmp(char *s1, char *s2)
double v1, v2;
v1 = atof(s1);
v2 = atof(s2);
if(v1 < v2)
return -1;
else if(v1 > v2)
return 1;
else if(v1 == v2)
return 0;
//交换数组中 i j 元素
void swap(void *v[], int i, int j)
void *temp;
temp = *(v + i);
*(v + i) = *(v + j);
*(v + j) = temp;
//排序方法
void q_sort(void *v[], int left, int right, int (*comp)(void *, void *))
int i, last;
if(left >= right)
return;
swap(v, left, (left + right)/2);
last = left;
for(i = last + 1; i <= right; i++)
if((*comp)(v[i], v[left]) < 0)
swap(v, ++last, i);
swap(v, left, last);
q_sort(v, left, last - 1, comp);
q_sort(v, last + 1, right, comp);
}
执行结果 :
/*************************************************************************
> File Name: method_pointer_sort.c
> Author: octopus
> Mail: octopus_work.163.com
> Created Time: Sat 22 Mar 2014 11:45:47 PM CST
************************************************************************/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//定义排序字符串最大个数
#define MAXLINES 50
//每个字符串最多50个元素
#define MAXLEN 50
//定义一个 有MAXLINES 个 元素的数组, 数组中的元素师字符串, 即char类型指针
char *lineptr[MAXLINES];
* 声明函数指针
int (*p_get_line)(char *, int);
int (*p_read_lines)(char **, int);
void (*p_write_lines)(char **, int);
void (*p_q_sort)(void **, int, int, int (*)(void *, void*));
* 声明函数, 如果直接使用这些函数, 即使函数定义在主函数后面也不会出错
* 如果要将函数赋值给函数指针, 需要提前声明这些函数
int get_line(char *, int);
int read_lines(char **, int);
void write_lines(char **, int);
void q_sort(void *v[], int left, int right, int (*comp)(void *, void *));
int numcmp(char *, char *);
int main(int argc, char **argv)
char line[MAXLEN];
int len, nlines, numberic = 0;
p_read_lines = read_lines;
p_write_lines = write_lines;
p_q_sort = q_sort;
//如果参数中含有 -n 说明这是按照数值顺序排序, 否则就按照字典顺序排序
if(argc > 1 && strcmp(argv[1], "-n") == 0)
numberic = 1;
if((nlines = (*p_read_lines)(lineptr, MAXLINES)) >= 0)
* 注意 :
* 使用 ? : 表达式选择 函数指针, 函数指针类型转换的时候, 为每个选项都添加转换
* 如果只转换 ? : 结果, 会报出警告
(*p_q_sort)((void **)lineptr, 0, nlines - 1, numberic ? (int (*)(void*, void*))numcmp : (int (*)(void*, void*))strcmp);
(*p_write_lines)(lineptr, nlines);
return 0;
printf("error \n");
return 1;
//从标准输入流中读取数据, 放入字符串中
int get_line(char *line, int max)
int i, c;
for(i = 0; (c = getchar()) != '\n' && c != EOF && i < max - 1; i ++)
*(line + i) = c;
*(line + i) = '\0';
return i;
//从标准输入流中读取数据, 放入字符串数组
int read_lines(char *lineptr[], int max)
int len, nlines = 0;
char *p, line[MAXLEN];
while((len = get_line(line, MAXLEN)) > 0)
if(nlines >= MAXLINES || (p = malloc(sizeof(char) * (len + 1))) == NULL)
return -1;
strcpy(p, line);
*(lineptr + nlines) = p;
nlines++;
return nlines;
//将字符串数组中的元素打印出来
void write_lines(char *lineptr[], int nlines)
int i;
for(i = 0; i < nlines; i++)
printf("the %d char sequence is : %s \n", i, *(lineptr + i));
//数值比较
int numcmp(char *s1, char *s2)
double v1, v2;
v1 = atof(s1);
v2 = atof(s2);
if(v1 < v2)
return -1;
else if(v1 > v2)
return 1;
else if(v1 == v2)
return 0;
//交换数组中 i j 元素
void swap(void *v[], int i, int j)
void *temp;
temp = *(v + i);
*(v + i) = *(v + j);
*(v + j) = temp;
//排序方法
void q_sort(void *v[], int left, int right, int (*comp)(void *, void *))
int i, last;
if(left >= right)
return;
swap(v, left, (left + right)/2);
last = left;
for(i = last + 1; i <= right; i++)
if((*comp)(v[i], v[left]) < 0)
swap(v, ++last, i);
swap(v, left, last);
q_sort(v, left, last - 1, comp);
q_sort(v, last + 1, right, comp);
}
.
3. 指针函数的复杂案例分析
(1) 指针函数 和 函数指针 分析
示例 :
-- 示例一 : char *get_line(char *line, int max);
-- 示例二 : char **get_line(char *line, int max);
-- 示例三 : int *(*get_line)(char *line, int max);
分析 :
-- 示例一 : get_line 普通函数, 返回值是一个char类型指针, 即返回一个字符串;
-- 示例二 : get_line 普通函数, 返回值是一个二级指针, 即字符串数组;
-- 示例三 : get_line 函数指针, 该指针的返回值是一个int类型的指针, 即指针; get_line不是函数名, 是一个指针变量, 使用 int *(*)(char *line, int max) get_line 可以清楚的定义该指针, 不过如果这样定义就错误了;
(2) 指函数指针转换
示例 :
char fun();
void (*p)();
*(char*)&p = (char)fun;
(*p)();
解析 :
-- void (*p)() : 该表达式定义了一个函数指针, 该指针p 指向一个函数, 这个函数的返回值 和 参数都为NULL;
-- *(char*)&p : p是函数指针, &p 是指向函数指针的指针, (char*)&p 将 指向函数指针的指针 类型改为 char*, *(char)&p 就是 取出转换类型的函数指针, 这个是已经转换好类型的函数指针;
-- (char)fun : 将fun函数的 函数指针转换为 char 类型, 函数的入口地址转换为 char 类型;
-- *(char*)&p = (char)fun : 指的是将函数的地址 赋值给 指针变量p;
-- (*p)() : 调用这个 指针 指向的函数;
(3) 将地址转换成函数指针
示例 :
解析 :
-- void(*)() : 函数指针类型, 该类型指向的函数 返回值 和 参数 均为 NULL;
-- (void(*)())0 : 将 0 转换为函数指针, 前提是这个位置有该类型的函数;
-- *(void(*)())0 : 将 函数指针 指向的函数取出, 后面加上(), 就是执行这个函数;
(4) 函数指针作为返回值
示例 : 函数指针作为返回值, 正向写写不出来, 要反向推理;
char(*get_char(char))(char *, int);
分析 : 从get_char 开始解析;
-- get_char(char) : get_char 先跟()结合, 表明这是一个函数;
-- *get_char(char) : get_char(char) 与 * 结合, 表明该函数返回值是一个指针;
-- (*get_char(char))(char *, int) : (*get_char(char)) 返回指针, 与后面的(char *, int)结合, 返回的是一个函数指针, 该指针指向函数;
-- char(*get_char(char))(char*, int) : 表明这个返回值函数指针指向的函数的返回值是 char 类型;
简单的替代方法 : 使用 typedef;
typedef char(*RETURN)(char *, int);
the 2 char sequence is : r
the 3 char sequence is : w
61 return 0;
(gdb) n
69 }
(gdb) n
0x000000306801d994 in __libc_start_main () from /lib64/libc.so.6
(gdb) quit #退出调试
A debugging session is active.
Inferior 1 [process 7799] will be killed.
Quit anyway? (y or n) y