指针—— 容易忘记的使用方式

引言:说到指针,学过C语言的同学想必都非常清楚类似于解引用(*),取地址(&)这些常用的符号,但是,有一些指针,如果不经常用到,很可能看到就晕,也会有畏惧之心,这篇文章将会向大家介绍指针的一些容易被遗忘的类型。

(*(void (*)())0)();
void (*signal(int , void(*)(int)))(int);//void(*)(int) signal(int,void(*)(int))//err

看到上面两段代码,是否会突然一慌呢,如果会的话,赶紧来学习一下吧~

1.数组指针和函数指针

为了让大家可以更加深刻的记住这些比较难以记住的指针,前面我讲涉及到的思路和大家分享一下,

所以我把数组指针和函数指针放一块咯~

1.1如何定义(善用类比的观察)

int* p;//这是指向整型的指针用int*,叫整型指针
char* p2;//这是指向字符的指针char*,叫字符指针
//·······
int** pp;//这是指向指针的指针,叫二级指针,存放的是一级指针的地址
int***ppp;//同理还可以有三级四级五级n级指针
//那么可以看看以下比较套娃式的指针,虽然有点抽象,但是也可以用以上类比的方式理解
int* p3[10];//这是什么指针?这不是指针,是数组,p3首先和[]结合,是一个数组,然后再是到int*,这个数组存放的是指向整型类型的指针
int(*p4)[10];//这是才是一个指针,p4先和*结合说明他是一个指针,再往外看到int[10],回想上面的,可以很轻松想到,这个指针指向的是一个数组的地址,而这个数组里有是个元素,并且是一个整型类型的数组----->这是一个数组指针

int abc(int a,int b);
int (*p5)(int,int);//指向函数地址的指针,函数指针
char* abc(int a,char b);
char* (*p6)(int,char);
//函数指针--可用于回调函数,通过传递函数的地址来调用函数
int(*p7[4])(int,int)//这个是函数指针数组---可用于转移表

那么现在,我相信大家对于开头的问题,即使有疑问也已经有所解答了吧~

(*(void (*)())0)();//(void (*)())0从最里面我们可以看到这是一个强转,把0强制转化为函数指针类型,然后作为函数指针参数传递
void (*signal(int , void(*)(int)))(int);//这个也是类似的我们其实可以看成void(*)(int) signal(int,void(*)(int))来帮助理解,void(*)(int) 是类型名,后面是我们要进行传参的内容,但是这种写法是错误的噢,

1.2有什么用呢?

1.2.1(数组指针可用于二维数组传参)
//在学习数组指针之前,我们进行二维数组的传参,可以需要依赖这种方式
#include <stdio.h>
void test(int a[3][5], int r, int c)//在这里我们需要将二维数组写在上面
{	int i = 0;
	int j = 0;
    for(i=0; i<r; i++)
	{
		for(j=0; j<c; j++)
		{
			printf("%d ", a[i][j]);
		}
		printf("\n");
	}
}
//在学习数组指针之后,我们可以这样!
void test2(int (*p)[5], int r, int c)//而现在,我们可以将它写成指针的形式进行传参
{	int i = 0;
	int j = 0;
	for(i=0; i<r; i++)
	{
		for(j=0; j<c; j++)
		{
			printf("%d ", *(*(p+i)+j));
		}
	printf("\n");
}
}

int main()
{
	int arr[3][5] = {{1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7}};
	test(arr, 3, 5);
    test2(arr, 3, 5);//这两种调用方式将会是一样的结果噢
	return 0;
}
1.2.1(函数指针的使用)
#include <stdio.h>
int Add(int x, int y)
{
		return x+y;
}
int main()
{
	int(*pf3)(int, int) = Add;//这里取出Add函数的地址,函数指针里存的就是Add函数的地址
    int(*pf3)(int, int) = &Add;//这种和上面的结果是一样的,都是直接取出了函数的地址
    printf("%d\n",Add(2,3));//--函数名调用
	//----------------------------学习了函数指针后,我们可以用以下方式进行调用函数,在后续的回调函数的使用会非常重要
    printf("%d\n", (*pf3)(2, 3));//--函数指针的调用
	printf("%d\n", pf3(3, 5));//*可以省略,写不写都和上一行一致--函数指针的调用
	return 0;
}

2.void*指针

可以接收任意指针的类型,但是不可以对他进行解引用和±整数的运算,多用于函数封装的时候,我们还不知道要给他传什么类型的参数时候使用

#include <stdio.h>
int main()
{
	int a = 10;
	void* p1 = &a;//接收是可以的
	void* p2 = &a;
	*p1 = 10;//这样会报错
	*p2 = 0;
	return 0;
}

在这里插入图片描述

3.const的使用

变量是可以修改的,如果把变量的地址交给⼀个指针变量,通过指针变量的也可以修改这个变量。但是如果我们希望⼀个变量加上⼀些限制,不能被随便修改,那我们应该怎么办呢,这就是const的功效!

#include <stdio.h>
void test1()
{
	int n = 10;
	int m = 20;
	int *p = &n;
	*p = 20;
	p = &m; 
}//此时正常情况下,我们是可以对*p和p进行赋值的
void test2()
{
	int n = 10;
	int m = 20;
	const int* p = &n;
	*p = 20
	p = &m; 
}//这种情况呢?是否赋值成功呢?
void test3()
{
	int n = 10;
	int m = 20;
	int *const p = &n;
	*p = 20; 
	p = &m; 
}//这种情况又能否成功呢?
void test4()
{
 	int n = 10;
 	int m = 20;
	int const * const p = &n;
	*p = 20; 
	p = &m; 
}//这个呢?

在运行过后我们可以发现,

test2中,我们不能对p里面的内容进行修改,但是我们可以修改其地址;

test3中,我们不能对p的地址进行修改,但是我们可以修改里面的值,此时const修饰的是指针;

test4中,我们很遗憾发现,我们无论是对于指针,还是里面的值,都没有权力去改变。

而这个就是const的作用,在很多库函数的封装都会频繁用到,也是自己写出好的稳定的代码的好帮手。

结论:const修饰指针变量的时候

const如果放在星号左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。
但是指针变量本⾝的内容可变。
const如果放在的星号右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指
向的内容,可以通过指针改变。

的稳定的代码的好帮手。

结论:const修饰指针变量的时候

const如果放在星号左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。
但是指针变量本⾝的内容可变。
const如果放在的星号右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指
向的内容,可以通过指针改变。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值