【【C语言进阶】进阶指针】
文章目录
- 1、引言
- 2、知识回顾
- 3、地址的产生
- 4、字符指针
- 5、指针数组
- 6、数组指针
-
- 6.1、数组名
- 6.2、数组指针如何使用
- 6.3、数组传参、指针传参
- 7、函数指针
- 8、函数指针的数组
- 9、回调函数(函数指针的真正用途)
- 小知识
1、引言 经过一段的学习,我们已经大致掌握了C语言的基础,接下来就是更加深入的了解C语言的知识,今天这篇博客是对指针知识的进阶。
2、知识回顾 1、指针就是一个变量,用来存放地址,地址可以唯一访问一块空间
2、指针的大小为4/8个字节,32位bit的机器就是4个字节,64位bit为8个字节
3、指针有类型,指针类型决定了解引用操作时指针的权限
3、地址的产生 1、首先我们都知道电脑中存在CPU这个硬件
CPU会产生虚拟地址
32位虚拟地址空间 -> 32bit位的地址
64位虚拟地址空间 -> 64bit位的地址
CPU产生虚拟地址之后,会转换为物理地址,由物理地址访问内存中的区域
4、字符指针
文章图片
文章图片
5、指针数组 整型指针数组应用
文章图片
字符指针数组
文章图片
6、数组指针 数组指针是指向数组的指针
int* p1[10];
//p1与[]先结合,所以*p1是指针数组
int (*p2)[10];
//p2与*先结合,所以*p2是数组指针
6.1、数组名 首先我们要知道 arr 和 &arr 分别表示什么意思呢?
文章图片
从图中的代码对比我们可以得到结果
1、arr表示数组首元素地址,所以整型数组 int arr[10] 的首元素地址 arr+1 后跳过一个整型大小,也就是4个字节
2、而 &arr 表示将数组的地址存放起来,放在数组指针 int ( * ) [ 10 ]中,数组的地址+1,跳过整个数组大小,所以跳过40个字节
6.2、数组指针如何使用
文章图片
int (*parr3[10])[5];
//parr3和[]结合,说明parr3是一个数组,数组有10个元素
//每个元素的类型是int(*)[5],是一种数组指针
//该类型指针指向的数组有5个int类型的元素
下面举一个数组指针运用的例子
文章图片
虽然可以这么写,但实际操作中并不值得提倡
接下来是数组指针的正确用法
文章图片
6.3、数组传参、指针传参 1、一维数组传参
(一)数组传参的时候,形参写成数组的形式是可以的,同时形参数组可以不用规定大小
(二)本质上数组传参的时候,传的是数组名,数组名相当于首元素地址,所以形参部分可以写成指针(举例)
void test(int *arr[20])//或(int **arr)
{}
int main()
{
int* arr[20] = { 0 };
test(arr)
}
2、二维数组传参
(一)二维数组传参的时候,形参的二维数组 行 可以省略,但是 列 不能省略
(二)二维数组传参的时候,若是传数组名,此时的数组名相当于第一行的地址,所以应当用 int (*) [ ] 类型的形参来接收(举例)
//二维数组名本质上就是指向第一行的数组指针
void test(int arr[][5])//或(int (*arr)[5])
{}
int main()
{
int arr[3][5] = { 0 };
test(arr);
}
3、一级指针传参
(一)形参是一级指针,能接收什么样的参数(举例如下)
void test(int* p)
{}
int main()
{
int a = 10;
int* ptr = &a;
int arr[10] = { 0 };
test(&a);
test(ptr);
test(arr);
return 0;
}
4、二级指针传参
(一)形参为二级指针时,可以接收什么参数(举例如下)
void test(char** p)
{}
int main()
{
char ch = 'w';
char* p = &ch;
char** p = &p
char* arr[5];
test(arr);
test(&p);
test(pp);
test
return 0;
}
7、函数指针
int Add(int x, int y)
{
return x + y;
}
void test(char* str)
{}
int main()
{
int (*p)(int, int) = &Add;
//p是函数指针
void (*pt)(char*) = &test;
//pt是函数指针//调用例子
int sum = (*p)(2,3);
//函数调用
//int sum = p(2,3);
也可以这样调用
printf("%d\n", sum);
return 0;
}
趣味代码
int main()
{
//1、把0强制类型转换为 void (*)() 类型的函数指针
//2、再去调用0地址处这个参数为无参,返回类型是void的函数
( * ( void( * )( ) )0 )( );
//这是依次函数调用,调用0地址处的函数void ( * signal( int,void(*)(int) ) )(int);
//signal 是一个函数声明
//这个函数的参数有2个,第一个是int类型,第二个是函数指针void (*)(int)
//该void (*)(int)指针指向的函数参数int,返回类型是void//signal函数的返回类型也是函数指针void (*)(int)
//该指针指向的函数参数int,返回类型是void
return 0;
}
8、函数指针的数组 函数指针数组,存放函数指针的数组,每个元素都是函数指针类型
文章图片
9、回调函数(函数指针的真正用途) 回调函数是通过函数指针调用的函数
文章图片
小知识 一、无具体类型指针
void * 是一种无具体类型的指针,void*的指针变量可以存放任意类型的地址
1、但是值得注意的是void* 的指针不能直接进行解引用操作,这是因为void的指针变量可以存放任意类型的地址,所以解引用void的时候,编译器不知道应该访问几个字节
2、同时void* 的指针不能直接进行加减整数,原理同上。
3、arr [ 3 ] [ 4 ] ,可以改写成 * ( *(arr + 3)+4), 因为 arr是 二维数组 首元素地址,即第一行数组地址,+3后地址变为第3行数组地址,解引用后获得第三行数组的首元素地址,之后再 +4 获得第三行第四个元素的地址,再次解引用,获得第三行第四个元素。
4、小练习
int main()
{
char* c[] = { "ENTER","NEW","POINT","FIRST" };
char** cp[] = { c + 3,c + 2,c + 1,c };
char*** cpp = cp;
//2022.1.19字符串和内存函数
printf("%s\n", **++cpp);
printf("%s\n", *-- * ++cpp + 3);
printf("%s\n", *cpp[-2] + 3);
printf("%s\n", cpp[-1][-1] + 1);
return;
}
推荐阅读
- #yyds干货盘点# C语言数组与指针常考笔试题(原题+解析+原码)
- C语言从0到1|【C语言】指针进阶(字符指针&&数组指针&&函数指针)
- C语言算法
- c语言实现简单版扫雷
- C语言|程序员的你,有哪些炫技的代码写法()
- C语言|ASCII编码,将英文存储到计算机
- C++|如何系统地学习 C++ 语言()
- C++|十款真正的编程游戏软件
- c语言|C/C++新手入门教程(傻瓜都会的VS2013使用教程,成为程序员的第一步)