一、指向指针的指针

想通过函数修改指针指向的内存位置,即修改指针变量的值时,需要使用指向指针的指针。

例如:

struct node{int value;struct node *next;
};//在链表开头加入新结点
struct node *add_to_list(struct node *list, int n)
{struct node *new_node = (struct node*)malloc(sizeof(struct node));if(new_node == NULL){printf("Error: malloc failed, no space left.\n");exit(EXIT_FAILURE);}new_node->value = n;new_node->next = list;return new_node;
}

若是想直接返回新链表的首地址:

...
new_node->value = n;
new_node->next = list;
list = new_node;return list;

由于函数是通过创建参数副本的方式执行的,因此上面的办法在函数调用结束之后对 list 的修改会失效。list 作为一个变量,函数修改任何外部变量都需要通过指向该变量指针来修改变量的值,即便这是一个指针变量。因此,要通过函数修改外部指针变量的值,需要用到指向指针的指针。

以下为正确代码:

void add_to_list(struct node **list, int n)      //参数改为指向指针的指针
{struct node *new_node = (struct node*)malloc(sizeof(struct node));if(new_node == NULL){printf("Error: malloc failed, no space left.\n");exit(EXIT_FAILURE);}new_node->value = n;new_node->next = *list;*list = new_node;
}//函数的调用
add_to_list(&first, n);             //first为函数首地址

二、指向函数的指针

函数指针: 指向函数的指针
指针函数:返回指针的函数

函数占用内存单元,因此每个函数都有地址。

2.1 函数指针作为参数

举例:求函数的积分

//形式1:
double integrate(double (*f)(double), double a, double b);//形式2:
double integrate(double f(double), double a, double b);
  • 形式1中,(*f)左侧的 double 为 f 所指向的函数的返回类型,右侧的 double 为所指向函数的参数表。形式2同理。

调用举例:

#define PI 3.14159;
double integrate(double (*f)(double), double a, double b);
...
double result;
result = integrate(sin, 0, PI/2);
...double integrate(double (*f)(double), double a, double b)
{...y = (*f)(x);       //通过*f调用f函数...
}

说明:

  • sin后面没有圆括号,编译器会视为指针,因此不会调用函数库中的 sin 函数代码,而是给 integrate 传递一个指向 sin 函数的指针。类比 a 和 a[i] 与 f 和 f(x) 的关系。如果 f(x) 是函数,则编译器将 f(x) 当作函数来调用,而将 f 视为指向 f(x) 的指针。
  • *f表示f指向的函数,x 是函数调用的实际参数
  • 在 main 函数中,调用integrate函数时,函数体内每一次 *f 都是对 sin 函数的调用

注意:

  • C语言允许使用 f(x) 来调用 f 所指向的函数(形式2),但(*f)(x)更符合真实情况,因为此处的 f 是指针,而不是函数名。

2.2 qsort 函数

所在头文件:<stdlib.h>
函数功能:对任意数组排序

函数原型:
void qsort(void* base, size_t n, size_t size, int(*compar)(void*, void*) );

  • 其中 int(*compar)(void*, void*)中的 int 表示 compar 函数的返回类型,(*compar)右侧圆括号的内容为 compar 函数的参数表。compar 为指向函数的指针,因此通过(*compar)来调用 compar 函数。
  • compar函数确定排序规则,为用户自主编写确定,qsort传递给compar两个数的地址(以void*形式传入),qsort依据compar的返回值确定这两个数的排列顺序。

compar函数返回值:

返回值 含义
< 0 第一个参数放前面
0 不变
> 0 第2个参数放前面

2.2.1 compar 函数的编写方式举例:

//整型数组
int compar(void* a, void* b)
{return (*(int*)a - *(int*)b );         //当待排序的数组元素为int类型时
}//字符串数组
int compar(const void* str1, const void* str2)
{return strcmp(*(char**)str1, *(char**)str2);
}//字符串链表
struct node{char name[50];struct node* next;
};
int compar(const void* p, const void* q)
{return strcmp(((struct node*)p)->name, ((struct node*)b)->name);
}
  • 在第一个中,由于整数相减可能导致数据溢出,因此如果待排序整数是任意给定的,则用 if 语句来比较 *(int*)a*(int*)b 更安全。
  • 在第3个中,强制类型转换符()的优先级低于取结构成员符->,因此需要多一个括号

2.2.2 qosrt 完整用法

#include <stdio.h>
#include <stdlib.h>
...
int compar(const void* a, const void* b){return ( *(int*)a - *(int*)b );        //按从小到大重新排序
}int main(){int a[5] = {5,4,3,2,1};qsort(a, 5, sizeof(int), compar);for(int i=0; i<5; i++){printf("%d ", a[i]);        //输出1 2 3 4 5}return 0;
}

2.3 函数指针的其他用途

C语音把函数指针也视为存储数据的指针,因此可以用变量存储函数指针,定义返回函数指针的函数。

void (*pf)(int);     //定义各个可以存储函数指针的变量pfpf = f;         //f本身是该函数的指针,不能用取地址符&f
(*pf)(i);       //调用f(i)
pf(i);          //调用f(i)
  • 以上定义中,pf可以指向任何带有 int 型参数并返回 void 型值的函数

函数指针数组

//定义一个函数指针数组
void (*file_name[])(void) = {new_cmd;open_cmd;close_cmd;close_all_cmd;save_cmd;save_as_cmd;save_all_cmd;print_cmd;exit_cmd;};...void new_cmd(){...
}void open_cmd(){...
}...void exit_cmd(){...
}

2.4 应用举例:列三角函数表

#include <stdio.h>
#include <math.h>void tabulate(double (*f)(double), double first, double last, double incr);int main(){double initial, final, increment;printf("Enter initial value: ");scanf("%lf", &initial);printf("Enter final value: ");scanf("%lf", &final);printf("Enter increment: ");scanf("%lf", &increment);printf("\n      x       sin(x)""\n   -------   -------\n");tabulate(sin, initial, final, increment);printf("\n      x       cos(x)""\n   -------   -------\n");tabulate(cos, initial, final, increment);printf("\n      x       sin(x)""\n   -------   -------\n");tabulate(sin, initial, final, increment);return 0;
}void tabulate(double (*f)(double), double first, double last, double incr)
{double x;int i, num_intervals;num_intervals = ceil((last - first) / incr);    for(i = 0; i < num_intervals; i++){x = first + i*incr;printf("%10.5f %10.5f\n", x, (*f)(x));}
}

说明:

  • double ceil(double x)函数:返回大于或等于 x 的最小整数 (以double类型返回)。

输出结果示例:

三、受限指针 restrict (C99)

int * restrict p;

若 p 所指向的对象只能通过 p 来访问或修改。

举例:

int * restrict p;
int * restrict q;
p = (int*)malloc(sizeof(int));
q = p;
*q = 0;                //未定义行为,无法通过q修改p指向的内容

如果一个对象有多种访问方式,这些访问方式互称为 “ 别名 ” 。

应用举例:
void *memcpy(void * restrict s1, void * restrict s2, size_t n);
void *memmove(void * s1, void * s2, size_t n);

  • memcpymemmove都是复制内存块的内容,区别在于原内存和目的地是否允许重叠,前者不允许重叠,后者可以重叠。

四、弹性数组成员 (C99)

当结构体的最后一个成员是数组时,其长度可以省略。

struct vstring{int len;char str[];
};
...
struct vstring *str = malloc(sizeof(struct vstring) + n);
str->len = n;

【C补充】指向指针或函数的指针相关推荐

  1. C++之指向对象成员函数的指针

    定义指向对象成员函数的指针变量的方法和定义指向普通函数指针变量方法有所不同: 1.普通指针函数变量的定义方法:数据类型名(*指针变量名)(参数列表): 例:void  (*p)(void); p = ...

  2. C语言返回指针的函数,指针函数,让一个函数返回一个字符串

    C语言函数返回指针的函数(指针函数) 什么是返回指针的函数 一个函数可以返回一个整形值 字符型值 实型值 1.如果一个函数它的返回值是一个地址(是一个指针的话),这个函数是一个返回值是指针即指针函数. ...

  3. 黑马程序员匠心之作|C++教程从0到1入门编程(60 指针-const修饰指针61 指针-指针和数组62 指针-指针和函数63 指针-指针配合数组和函数的案例)

    黑马程序员匠心之作|C++教程从0到1入门编程(60 指针-const修饰指针61 指针-指针和数组62 指针-指针和函数63 指针-指针配合数组和函数的案例) 一.60 指针-const修饰指针 二 ...

  4. 函数指针、函数返回指针、const指针、指向const指针,指向const的const指针。

    ①函数指针 函数指针是指向函数的指针变量. 因而"函数指针"本身首先应是指针变量,只不过该指针变量指向函数.这正如用指针变量可指向整型变量.字符型.数组一样,这里是指向函数.如前所 ...

  5. 理解数据成员指针、函数成员指针

    转自:http://www.cnblogs.com/malecrab/p/5572119.html 1. 数据成员指针 对于普通指针变量来说,其值是它所指向的地址,0表示空指针. 而对于数据成员指针变 ...

  6. C++_const修饰指针_指针和数组_指针和函数_指针配合数组和函数案例_用指针数组实现冒泡排序---C++语言工作笔记024

    然后我们再来看一下const修饰指针 这里第一种是常量指针 可以看到 const int * p =&a 这个p就是一个常量指针,可以看到,常量指针,指明了,这个指针指向的值是一个常量不能修改 ...

  7. 指针、函数、指针函数和函数指针

    指针 指针就是存储单元的地址,计算机是以字节为单元存储数据的,存储的地址就是指针. 好处:使程序更加简洁 int *p; //p代表指针,*p代表内容 &p地址 int *p;//四个字节的长 ...

  8. 【疑问感受】初见指针——当函数遇到指针

    --------------------------------------------------------------------------------------------------(● ...

  9. 指针数组,数组指针,函数指针,函数指针数组 ,指向函数指针数组的指针

    首先有个问题:指针和数组有什么关系呢? 答案:什么关系都没有. 指针就是指针,在32位平台下,永远占4个字节,其值为某一个内存的地址. 数组就是数组,其大小与元素的类型和个数有关.定义数组时必须指定其 ...

  10. 指向成员函数的指针有什么用_指针函数,函数指针,有点懵圈了?你能分清楚吗...

    指针函数和函数指针到底怎么区分? 1.前言 数组.指针,这两个词结合的顺序不同,其意义也不同. 同样的,函数.指针这两个词结合的顺序不同其意义也不同,即指针函数与函数指针的意义不同. 2.指针函数 指 ...

最新文章

  1. oracle9i 查询scn,Oracle10g的current_scn是如何计算的?
  2. linux系统web站点设置-http基础设置
  3. mysql双重分组没有值也要显示_mysql 统计数据,按照日期分组,把没有数据的日期也展示出来...
  4. VPC-阿里云专有网络 Virtual Private Cloud
  5. JustOJ1500: 蛇行矩阵
  6. weight_decay一般设置为多少_50岁的夫妻一般有多少存款?他们在为养老做准备吗?...
  7. 2007年7月23日旅游
  8. 小红书创始人瞿芳回应裁员风波:战略部署清晰 人员翻倍
  9. STM32 通用 Bootloader
  10. 南方cass提取坐标生成表格_如何利用EXCEL随机生成测量点坐标导入南方CASS中计算土方量...
  11. 高中数学,解析几何高考压轴题解题技巧
  12. 阿里云图片如何获取缩略图
  13. 普通运维人员是秋后的蚂蚱?
  14. Python正则表达式在线练习(网页版)和离线练习(本地版)
  15. 结合阿里云 FC 谈谈我对 FaaS 的理解
  16. (附源码)php校园电子图像信息采集系统 毕业设计 010930
  17. ubuntu下重装WIN7
  18. Python守护进程daemon实现
  19. C++Person类继承
  20. 号称能够理解自然语言的聊天机器人,在图灵测试下被分分钟打脸

热门文章

  1. 数学建模美赛2019 人生经验
  2. 【codejam_Round1B_C】Mousetrap
  3. matlab画频谱图
  4. 小程序微信JSAPI支付进行退款操作
  5. 测试报告包含哪些内容?
  6. Html设置图片大小代码
  7. 基于Arduino控制伺服电机(舵机)
  8. 树莓派入门(六)之控制舵机、伺服电机的驱动代码
  9. Java之Joda工具包处理时间的7点总结分享
  10. 使用三目表达式的踩坑记录