C/C++总结笔记——指针2:二级指针、指针数组&数组指针、函数指针(回调函数)&函数指针数组、二维指针数组&数组指针

先看一道经典的C语言题:用变量a给出下面的定义

a) 一个整型数(An integer)
b)一个指向整型数的指针( A pointer to an integer)
c)一个指向指针的的指针,它指向的指针是指向一个整型数( A pointer to a pointer to an intege)r
d)一个有10个整型数的数组( An array of 10 integers)
e) 一个有10个指针的数组,该指针是指向一个整型数的。(An array of 10 pointers to integers)
f) 一个指向有10个整型数数组的指针( A pointer to an array of 10 integers)
g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument and returns an integer)
h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数 ( An array of ten pointers to functions that take an integer argument and return an integer )

// a) 一个整型数
int a; 
// b)一个指向整型数的指针
int *a;
// c)一个指向指针的的指针(二级指针),它指向的指针是指向一个整型数
int **a; 
// d)一个有10个整型数的数组
int a[10]; 
// e) 一个有10个指针的数组,该指针是指向一个整型数的
int *a[10]; 
// f) 一个指向有10个整型数数组的指针
int (*a)[10]; 
// g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数
int (*a)(int); 
// h)  一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数
int (*a[10])(int);

1.二级指针(c)

如果一个指针指向的是另外一个指针,我们就称它为二级指针,或者指向指针的指针
当函数参数为指针,我们需要动态的改变指针指向的地址(即传入不同指针)时(不使用引用),当传入的参数是二级指针变量的地址,对一级指针进行修改,则相当于对原指针地址进行了修改,

1、二级指针作为参数传递,可以实现改变参数指针指向的位置。

int* b = new int(2);
void Func(int** num){
    *num = b;
}
int main(){
    int* a = new int(1);
    Func(&a);
    cout<<*a<<endl;
}

2、二级指针可用于内存分配。

void  my_malloc(char **s)  {  
	*s=(char*)malloc(100);  
}  
void  main(){  
	char *p=NULL;
	my_malloc(&p);
	if(p)
		free(p);  
} 

2.指针数组与数组指针(f)&(g)

#include <stdio.h>
int main(){
    int p[3]={10,20,30};
    int *p1[3];
    int (*p2)[3];

    p1[0]=&p[0];
    p1[1]=&p[1];
    p1[2]=&p[2];
    printf("*p1[0] = %d, *p1[1] = %d, *p1[2] = %d\n", *p1[0], *p1[1], *p1[2]);
    printf("p1[0] = %#X, p1[1] = %#X, p1[2] = %#X\n", p1[0], p1[1], p1[2]);
    printf("&p1[0] = %#X, &p1[1] = %#X, &p1[2] = %#X\n", &p1[0], &p1[1], &p1[2]);

    p2=&p;//p2=p;会出现 warning,但不影响结果
    printf("(*p2)[0] = %d, (*p2)[1] = %d, (*p2)[2] = %d\n", (*p2)[0], (*p2)[1], (*p2)[2]);
    printf("&((*p2)[0]) = %#X, &((*p2)[1]) = %#X, &((*p2)[2]) = %#X\n", 
            &((*p2)[0]), &((*p2)[0]), &((*p2)[0]));

    printf("p = %#X, p1 = %#X, p2 = %#X\n", p, p1, p2);
    printf("*p = %#X, *p1 = %#X, *p2 = %#X\n", *p, *p1, *p2);
    printf("**p1 = %d, **p2 = %d\n", **p1, **p2);
    
    printf("sizeof(p) = %d, sizeof(p1) = %d, sizeof(p2) = %d\n", sizeof(p), 
            sizeof(p1), sizeof(p2));
    return 0;
}
/*输出
*p1[0] = 10, *p1[1] = 20, *p1[2] = 30
p1[0] = 0X61FE0C, p1[1] = 0X61FE10, p1[2] = 0X61FE14
&p1[0] = 0X61FDF0, &p1[1] = 0X61FDF8, &p1[2] = 0X61FE00

(*p2)[0] = 10, (*p2)[1] = 20, (*p2)[2] = 30
&((*p2)[0]) = 0X61FE0C, &((*p2)[1]) = 0X61FE0C, &((*p2)[2]) = 0X61FE0C

p = 0X61FE0C, p1 = 0X61FDF0, p2 = 0X61FE0C
*p = 0XA, *p1 = 0X61FE0C, *p2 = 0X61FE0C
**p1 = 10, **p2 = 10

sizeof(p) = 12, sizeof(p1) = 24, sizeof(p2) = 8
*/

指针数组
对于语句“intp1[3]”,因为“[]”的优先级要比“”要高,所以 p1 先与“[]”结合,构成一个数组的定义,数组名为 p1,而“int*”修饰的是数组的内容,即数组的每个元素。也就是说,该数组包含 3 个指向 int 类型数据的指针,因此,它是一个指针数组。

数组指针
对于语句“int(p2)[3]”,“()”的优先级比“[]”高,“”号和 p2 构成一个指针的定义,指针变量名为 p2,而 int 修饰的是数组的内容,即数组的每个元素。也就是说,p2 是一个指针,它指向一个包含3个 int 类型数据的数组。很显然,它是一个数组指针,数组在这里并没有名字,是个匿名数组。

数组指针与数组名的关系
p2=&p;//p2=p;会出现 warning,但不影响结果。(有些编译器直接报错)
在这里&p 是指整个数组的首地址,而 arr仅仅是数组首元素的首地址。赋值符号“=”号两边的数据类型不同(正常必须相同),则需要显示或隐式类型转换,因此发生警告可以运行。

3.函数指针&函数指针数组

函数指针: 一个指向函数的指针。一般用函数名表示。区别于返回值为指针的函数。
函数指针数组:元素为函数指针的数组。转移表。c语言中函数不可以定义为数组,只能通过定义函数指针来操作。

1、函数指针作为参数传递给另一个函数(实现回调函数)
回调函数:将一个函数指针作为参数传递给其它函数。后者将“回调”用户函数。
回调函数作用是为降低模块间的耦合度,针对不同的回调函数,可以用一个统一的函数接口调佣,是
实现软件的高内聚低耦合的一种方法。

函数 F1 调用函数 F2 的时候,函数 F1 通过参数给 函数 F2 传递了另外一个函数 F3 的指针,在函数 F2 执行的过程中,函数F2 调用了函数 F3,这个动作就叫做回调(Callback),而先被当做指针传入、后面又被回调的函数 F3 就是回调函数。

#include<stdio.h>

int Callback_1(){// Callback Function 1
    printf("Hello, this is Callback_1 \n");
    return 0;
}
int Callback_2(){// Callback Function 2
    printf("Hello, this is Callback_2 \n");
    return 0;
}
int Callback_3(){// Callback Function 3
    printf("Hello, this is Callback_3 \n");
    return 0;
}

int Handle(int (*Callback)()){
    printf("Entering Handle Function. \n");
    Callback();
    printf("Leaving Handle Function. \n");
}

int main(){
    printf("--------------------------------------------------- \n");
    Handle(Callback_1);
    printf(" \n");
    Handle(Callback_2);
    printf(" \n");
    Handle(Callback_3);
    printf("--------------------------------------------------- \n");
    return 0;
}
/*
--------------------------------------------------- 
Entering Handle Function. 
Hello, this is Callback_1
Leaving Handle Function.

Entering Handle Function.
Hello, this is Callback_2
Leaving Handle Function.

Entering Handle Function.
Hello, this is Callback_3
Leaving Handle Function.
---------------------------------------------------
*/

2、函数指针数组作为转移表
为了使用switch语句,表示操作符的代码必须是整数。如果它们是从零开始连续的整数,我们可以使用转换表来实现相同的任务。转换表就是一个函数指针数组。这样方便把具体操作和选择操作的代码分开。

# include <stdio.h>
# include <stdlib.h>
 
int Add(int x, int y){
	return x + y;
} 
int Sub(int x, int y){
	return x - y;
} 
int Mul(int x, int y){
	return x * y;
} 
int Div(int x, int y){
	return x/y;
} 
 
int main(){
	int a=8, b=5;
	int ret = 0;
	int(*p[5])(int a, int b) = {Add,Sub,Mul,Div};//函数指针数组的使用
    for(int i=0;i<4;i++){
        ret = (*p[i])(a, b);
        printf("ret=%d\n", ret);
    }
	// system("pause");
	return 0;
}
/*
ret=13
ret=3
ret=40
ret=1
*/

指向函数指针数组的指针 :void (*(p)[10])(const char);

二维指针数组&数组指针

二维数组在概念上是二维的,有行和列,但在内存中所有的数组元素都是连续排列的。

int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };
/*
0X61FDE0 0X61FDE4 0X61FDE8 0X61FDEC 0X61FDF0 0X61FDF4 0X61FDF8 0X61FDFC 0X61FE00 0X61FE04 0X61FE08 0X61FE0C
	0		1		2			3		4		5		6			7		8		9		10			11		
*/

int (*p)[4]为数组指针,p 指向的数据类型是int [4],那么p+1就前进 4×4 = 16 个字节,p-1就后退 16 个字节,这正好是数组 a 所包含的每个一维数组的长度。也就是说,p+1会使得指针指向二维数组的下一行,p-1会使得指针指向数组的上一行。

int (*p)[4] = a;

数组名 a 在表达式中也会被转换为和 p 等价的指针!那么等价关系如下:
a+i == p+i
a[i] == p[i] == *(a+i) == *(p+i)
a[i][j] == p[i][j] == *(a[i]+j) == *(p[i]+j) == ((a+i)+j) == ((p+i)+j)

#include <stdio.h>

int main(){
    int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
    int(*p)[4];
    int i,j;
    p=a;
    for(i=0; i<3; i++){
        for(j=0; j<4; j++) printf("%2d  ",*(*(p+i)+j));
        printf("\n");
    }
    return 0;
}


/*
 0   1   2   3  
 4   5   6   7
 8   9  10  11
*/

https://www.cnblogs.com/suwen/p/5266227.html
http://c.biancheng.net/view/335.html
https://www.runoob.com/w3cnote/c-callback-function.html
https://blog.csdn.net/qq_29567701/article/details/83659742
http://c.biancheng.net/view/2022.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值