指针进阶(1)

目录

一.字符指针

二.指针数组

三.数组指针

三.二 数组名

那么如何使用数组指针呢?

四.数组参数、指针参数

五.函数指针

 四.2

五.函数指针数组

六.指向函数指针数组的指针

七.回调函数

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


一.字符指针

何为字符指针?

让我们来看个例子

int main(){
    char ch = 'w';
    char *pc = &ch;
    *pc = 'b';
    printf("%c\n",ch);
    return 0;
}

其中pc就是字符指针

其中要注意的是

char* p = "abcdef";
printf("%s\n",p);

“abcdef”是常量字符串,存储在常量存储区:这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改。防止被修改,可以在char前加入const

例题一

int main() {
	const char* p1 = "abcdef";
	const char* p2 = "abcdef";

	char arr1[] = "abcdef";
	char arr2[] = "abcdef";

	if (p1 == p2) {
		printf("p1==p2\n");
	}
	else {
		printf("p1!=p2\n");
	}
	if (arr1 == arr2) {
		printf("arr1==arr2\n");
	}
	else {
		printf("arr1!=arr2\n");
	}
	return 0;
}

打印结果为

为什么呢?

p1 和p2指向的是同一个常量字符串,C/C++会把常量字符串放在单独的内存区域,当几个指针指向同一字符串,实际上会指向同一内存!因此p1==p2!

但在arr数组中,他们会开辟不同的空间 ,所以arr1!=arr2!

二.指针数组

指针数组是数组,用来存放指针的数组!

注意与后面要学习的数组指针要区分!!!

int arr[10];//整型数组
char ch[5];//字符数组

//指针数组
int* arr2[6];//存放整型指针的数组
char* arr3[5];//存放字符指针

注意 arr2的数组元素的类型为 int*

同样地,arr3 即为char*

如果我要将上面的代码打印出来,可加入————

for (i = 0; i < 3; i++) {
		int j = 0;
		for (j = 0; j < 5; j++) {
			printf("%d ", *(parr[i] + j));
		}
		printf("\n");
	}

这里的 *(parr[i]+j)    +j代表arr中的元素展开 

同样可写成 parr[i][j]

虽是二维数组的形式,arr1,arr2,arr3并不是连续存在的,所以本质上不是二维数组!!

三.数组指针

注意 这里是指针

定义:指向数组的指针

注意区分

int *p1[10];
int (*p2)[10];

第一个是指针数组,本质是数组,存放的是指针

第二个是数组指针,本质是指针,指针指向的是数组

该数组有十个元素,每个元素都是int 类型

三.二 数组名

1.数组名通常指的是数组首元素地址,但有俩个例外

1.sizeof(数组名)——>       计算的是整个数组的大小,单位是字节

2.&数组名——>        表示的依然是整个数组的地址!!!!


注意区分解引用

char *arr[5]={0};
char *(*pc)[5]=&arr;

(*pc)才是解引用,char *是类型!!!

并且 数组指针与二级指针有着本质上的区别 

又比如说 

p是指向数组的,*p其实就相当于数组名,数组名又是数组首元素的地址

所以 *p本质上是数组首元素的地址 

要记住

 优先级顺序          ()        >        []>        *

(*p)[n]:根据优先级,先看括号内,则p是一个指针,这个指针指向一个一维数组,数组长度为n,这是“数组的指针”,即数组指针;

*p[n]:根据优先级,先看[],则p是一个数组,再结合*,这个数组的元素是指针类型,共n个元素,这是“指针的数组”,即指针数组。

那么如何使用数组指针呢?

在一个二维数组中

例如 int arr[3][5];

arr是数组名,表示的是第一行也就是序列为0 的一行的地址(将一行当成一个元素)

看上述代码 其中的print2(arr,3,5);        arr代表的是第一行的地址,第一行的地址是一维数组的地址,是一个指向一位数组的指针 

int(*p)[5]:

p的类型是: int(*)[5];

p指向的是一个有五个元素的整型数组

p+1——>跳过一个有五个int元素的数组!


我们已经学习很多数组和指针,让我们来回顾一下

int arr[5];    arr是整型数组
int *parr1[10];    parr1是整型指针数组
int (*parr2)[10];    parr2是数组指针
int (*parr3[10])[5];    parr3是存放数组指针的数组

考虑优先级


再比如,

int (*parr3[10])[5]={&arr1,&arr2,&arr3};

这是存放数组指针的数组 

存放的是arr的地址;该数组类型是 int(*)[5];

四.数组参数、指针参数

先来个小小的题目

1.一维数组传参

 以上那组传参是对的?

答案是:以上都可以

其中要注意的是arr2是首元素地址,类型是int*

指针对指针可以传,数组对数组,数组对指针;

2.二维数组传参

#include<stdio.h>
void test(int **ptr)
{
    printf("num=%d\n",**ptr);
}
int main(){
    int n=10;
    int*p=&n;
    int **pp=&p;
    test(pp);
    test(&p);
    return 0;
}

总结:实参形参二者类型要一致

五.函数指针

        

对于函数来说,&函数名==函数名,都是其地址形式!!!

那么函数指针是什么形式呢?

以上述代码为例,可将add函数写作

int (*pf)(int,int)=&add

 这里的*(解引用)可以不加,但如果加必须带有括号!!(优先级)


下面来举几个例子

 四.2

计算器

五.函数指针数组

我们通过编写一段还原计算器小部分内容的代码来学习这节内容!

void menu() {
	printf("*******************\n");
	printf("***1.add  2.sum  ***\n");
	printf("***3.mul  4.div  ***\n");
	printf("***    0.exit    ***\n");
	printf("*******************\n");
}

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 input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	int (*arr[5])(int, int) = { 0,add,sub,mul,Div};    //这里的将几个函数地址作为数组
	do {
		menu();
		scanf_s("%d", &input);
		printf("请输入俩个操作数 > \n");
		scanf_s("%d %d", &x, &y);
		ret = arr[input](x, y);
		printf("%d\n", ret);
	}while(input);
	
		return 0;
}

六.指向函数指针数组的指针

七.回调函数

1.回调函数的定义:

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

我们再来学习一下新的函数

qsort

 我们可知qsort是一种快速排序思想实现的一个函数!

它可以排任何类型!

void qsort
( void *base, //你要排序的数据的初始地址
 size_t num,    //待排序的数据元素个数
 size_t width,    //待排序的数据元素大小
 int ( *cmp )(const void *e1, const void *e2 ) );    //函数指针————比较函数

举一个很简单代码

#include<stdio.h>
#include<stdlib.h>
int cmp_int(const void* e1, const void* e2) {
	return (*(int*)e1 - *(int*)e2);
}

int main() {
	int arr[] = { 2,3,4,6,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	for (int i = 0; i < sz; i++) {
		printf("%d ", arr[i]);
	}
	return 0;
}

其中 cmp_int 可以理解为回调函数!

还有,e1-e2 代表的是 升序排列,如果想降序 可以将其交换位置!

qsort除了可以排整形数据,还可以排列结构体!

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值