指针的基础进阶

指针的进阶应用

一、指向函数的指针(函数指针)

1、什么是函数指针?

首先,函数是会占内存空间的。在程序中定义了一个函数,在编译时,编译系统会为函数代码分配一段存储空间,这段存储空间就是函数的地址,这段地址的起始地址(又称入口地址)就称为这个函数的指针(或函数的首地址)。

既然函数也有地址,那么我们能不能用一个指针指向函数的地址呢?

既然都是地址,那么就可以用指针指向它。

指向整型变量地址的指针是整型指针,指向字符型变量地址的指针是字符型指针,指向单精度变量地址的指针是float型指针,那指向函数的指针是什么指针呢?

这就是接下来要接触到的函数指针了。

2、函数指针的定义

//简单来说,函数指针就是指向函数的指针。
//定义函数指针的一般格式:数据类型 (*函数名)(函数参数列表);
int (*funp)(int,char);
//定义了一个指针函数,用于指向返回值类型为int型、函数参数为(int,char)型的函数

3、指针的初始化及使用

int funsum(int x,int y)
{	//求和函数
	return x+y;
}

int funmax(int x,int y)
{	//求最大值函数
	return x>y?x:y;
}

int funmin(int x,int y)
{	//求最小值函数
	return x<y?x:y;
}
int main()
{
	int (*funp)(int,int)=funsum;	//定义一个函数指针funp,初始化赋值指向函数funsum
	int a=10,b=20,c;	//函数指针有以下两个赋值方式和两种调用方式
	c=(*funp)(a,b);	//通过函数指针funp调用函数funsum,(*)区分funp是个函数指针
	funp=&funmax;	//改变函数指针funp的指向,&取函数地址,使其指向函数funmax
	c=funp(a,b);	//此时是通过函数指针funp调用函数funmax
	funp=funmin;	//改变函数指针funp的指向,可以省略&取址符,使其指向函数funmin
	c=funp(a,b);	//通过函数指针funp调用函数funmin
return 0;
}

4、使用函数指针作为函数参数(回调函数)

回调函数:通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就称这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

int funsum(int x,int y)
{	//求和函数
	return x+y;
}
int funmax(int x,int y)
{	//求最大值函数
	return x>y?x:y;
}

//回调函数:在函数里运用函数指针间接调用其他函数
int center(int x,int y,int (*fun)(int,int))
{//这里的函数形式参数fun为函数指针类型

	return (fun)(x,y);	//可以通过函数fun调用其所指向的函数

}

typedef int (a)(int,int);

center(1,2,funsum);	//调用时直接以函数名作为函数参数

center(10,20,funmax);

实例:简易计算器

#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <stdio.h>
#include <iostream>
using namespace std;

int sum(int a, int b)
{
	return a + b;
}

int sub(int a, int b)
{
	return a - b;
}

int mul(int a, int b)
{
	return a * b;
}

int mub(int a, int b)
{
	return a / b;
}



int center(int x,int y,int (*f)(int ,int))
{
	return f(x, y);
}

void function()
{
	while (1)
	{
		int (*funp)(int, int) = NULL;
		int n, a, b;
		printf("输入0:退出\t 输入1:相加\t 输入2:相减\t 输入3:相乘\t 输入4:相除\n");
		scanf("%d", &n);

		switch (n)
		{
		case 0: exit(0);
		case 1: funp = sum; break;
		case 2: funp = sub; break;
		case 3: funp = mul; break;
		case 4: funp = mub; break;
		}
		printf("请输入值\n");
		scanf("%d %d", &a, &b);

		printf("%d \n", center(a, b, funp));
	}
	
}

int main()
{
	function();

	system("pause");
	return 0;
}

5、使用typedef给函数指针取别名

typedef int (*funp)(int,int);		//给 int (*)(int,int)类型的函数指针取一个别名为funp,这里跟一般取别名不同

funp *p1;		//用别名funp定义(*)(int,int)类型的函数指针p1
p1 = sum;	//函数指针p1指向函数sum
p1(1,2);		//通过函数指针p1调用函数
//#define无法给复杂的类型取别名,但带参宏可以:#define pf(n) int (*n)(int ,int)
//(不推荐)
pf(q);	//用带参宏定义函数指针q
q = sum;
q(1,2);

6、指针函数与函数指针的区别

所谓的指针函数,其本质上是个函数,是返回值为指针类型(地址)的函数。

所谓的函数指针,其本质上是个指针,是指向函数的指针。

int* f(int* x)	//指针函数
{
    return x;
}

int (*fp)(int*);	//函数指针
fp = f;		//函数指针指向指针函数

二、指针数组和数组指针

1、指针数组

(1)什么指针数组

所谓指针数组,其本质上是一个数组,数组中的每一个元素都是指针类型的,都可以指向对应数据类型的地址。

(2)指针数组的定义

定义的一般格式:数据类型 *指针数组名[数组元素个数];

int *p[6];	//定义一个指针数组,有6个元素,分别可以指向六个地址

(3)指针数组的使用
//使用指针数组指向二维字符数组
char arr[10][10],*p[10];
for(int i=0;i<10;i++)
{
	p[i]=arr[i];	//指针数组p中的每个元素指向二维数组arr的每一行
}
for(int i=0;i<10;i++)
{
	scanf(“%s”,p[i]);	//使用指针数组p给二维数组arr赋值
}
for(int i=0;i<10;i++)
{
	printf(“%s”,p[i]);	//使用指针数组p输出二维数组arr
}
 
//使用指针数组存储字符串的形式代替二维字符数组,达到省空间的目的
char *p[6]={“abc”,”123456”,”abcdefg”,”hello world!”,”xiaowei”,”x”}

2、数组指针

(1)什么是数组指针?

所谓的数组指针,其本质上是一个指针,是一个用于指向数组地址的指针.

(2)数组指针的定义

定义的一般格式:数据类型 (*指针变量名)[所指向数组的大小];

int a[3][4];
int (*p)[4];	//定义一个整型数组指针p,用于指向大小为4的整型数组
p=a;	//将整型数组指针p指向二维数组a的第一行
(3)数组指针的使用
//使用数组指针完成二维数组的输入和输出
int a[3][6];
int (*p)[6];
p = a;
for (int i = 0; i < 3; i++)
	for (int j = 0; j < 6;j++)
	{
		scanf("%d",&p[i][j]);
	}

for (int i = 0; i < 3; i++)
	for (int j = 0; j < 6;j++)
	{
		printf("%d\t",p[i][j]);
	}

用数组指针用于接受二维数组的地址,将二维数组作为函数参数传递需要用到数组指针接受:

void Print(int (*arr)[4],int n,int m)	//也可以写成  Print(int arr[][4],int n,int m)
{
	for(int i = 0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            printf("%d\t",arr[i][j]);
	    }
        printf("\n");
	}
}


int arr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
Print(arr,3,4);

或者也可以不用函数指针(不推荐,不好用)

void Print1(int* arr,int n)
{
     for(int j=0;j<n;j++)
     {
         printf("%d\t",arr[j]);
	 }			
}

int arr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
Print1(&arr[0][0],12);//传入二维数组的首地址,以一维数组形式输出

(4)数组指针的移动
p++;			//移动一整行
*(*(p+i)+j)		//可以把数组指针理解成为一个二级指针,通过两次解引用得到元素值
p[i][j];		//指针带数组下标的形式访问数组元素


int arr[3] = {1,2,3};
int(*q)[3] = &arr;	//指向大小为3的数组

三、指针常量与常量指针

1、指针常量
指针常量就是指向常量的指针
const int *p;
它的指向能够被改变,但是不能够改变值

2、常量指针
常量指针就是指针的指向不能够被改变的指针
int * const p;
它的能够改变值,但是不能够改变指向

示例:
int a = 10,b=20;
const int *p;
p = &a;
printf("%d\n",*p);  
//*p=30;	//值不能被改变
p = &b;	//可以改变指向
printf("%d\n",*p);

int * const q = &a;	//必须初始化指针指向
*q = 30;	//可以改变值
//q = &b;	//不能改变指向
printf("%d\n",*q);

指针常量和常量指针一般用于函数参数的传递,为了使在函数使用中不改变值以及指针的指向。
const int * const p=&a;//指针常量指针,都不能改变
posted @ 2022-02-03 11:00  宣哲  阅读(69)  评论(0编辑  收藏  举报