[C语言]进一步的来了解指针(多多多图详解)

news/2024/11/27 23:43:58/

        本文章进一步的来讲解指针,如果是第一次接触指针的可以先看一下对于指针的初步理解

         :

        [C语言]初步的来了解一下指针(多图详解)_HY_PIGIE的博客-CSDN博客

目录

        1.字符指针

        2.指针数组

                2.1指针数组:char*类型举例说明

                2.2指针数组:int*类型举例说明 

        3.数组指针            

                3.1数组指针的定义 

                3.2数组指针与指针数组的比较

                 3.3“&”数组名与数组名

                3.4数组指针的运用

                3.5数组指针代码解析         

        4.数组传参,指针传参

                4.1一级指针接收参数

                4.2二级指针接收参数

        5.函数指针

                5.1函数指针的定义

                5.2函数指针代码解析

        6.函数指针数组

                6.1函数指针数组的定义

                6.2函数指针数组的运用

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


         1.字符指针

                        字符指针:char*类型

                        对于char*类型的指针,之前所提到的是存放char类型变量地址的指针,或是本身为(1字节数)加上整数‘1’后跳过1个字节,解引用时同样的只有解锁1个字节的权限。

                        但char*类型还有另一个用法:用来存放字符串

                         对于这个常量字符串的打印:

printf("%s",a);//即可打印字符串“abcdef”

                         Q:可是指针为什么不用解引用呢?不应该是*a吗??

                          A:在char*类型指针中存放字符串,我们存放的是其首元素的地址,如果我们要打印字符串则是根据首元素的地址相应的打印整串字符。

                                既然a存放的是首元素‘a’的地址,那么相应的解引用*a则是根据a的地址找到对于的内容‘a’,打印的也只有a一个字符

                                第二个printf用%s打印会报错,更进一步证实了解引用*a得到的是‘a’单字符,而不是“abcdef”字符串

 

                        C/C++会把常量字符串存储到单独的一个内存区域,当几个指针。指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块

        2.指针数组

                                对于数组,我们之前认识的有:

                                int arr[]:整型数组,存放整型的数组

                                char arr[]:字符数组,存放字符的数组

                        而对于指针数组顾名思义,即是存放指针的数组:指针类型 arr[]

                2.1指针数组:char*类型举例说明

                        对于指针数组的打印,像其他数组同样的打印方式:

for(int i = 0;i < 4;i++)
{printf("%s\n",arr[i]);
}

                2.2指针数组:int*类型举例说明 

                 对于其的打印有两种方式:

方式一:
for (int i = 0; i < 4; i++){for (int j = 0; j < 6; j++){printf("%d", *(arr[i]+j));//指针数组寸的是每个数组首元素的地址}                            //我们得到首元素地址后不断+1就可以得到后面的元素printf("\n");}
方式二:
for (int i = 0; i < 4; i++){for (int j = 0; j < 6; j++){printf("%d", arr[i][j]);}printf("\n");}

                打印结果均为:

        3.数组指针            

                3.1数组指针的定义 

        指针数组为存放指针的数组,那相应的数组指针:是一个指向数组的指针

        注意:‘[ ]’中的个数不能被省略

                 注意:“数组”的地址和“数组首元素”的地址,在数值上是相同的,但意义却是不同的。在数组首元素的地址上+1,会跳过一个元素的字节,得到第二个元素的地址。在数组的地址上+1,直接跳过整个数组的字节。            

                3.2数组指针与指针数组的比较

                 3.3“&”数组名与数组名

                对于一个数组,我们知道arr是数组名,其还表示为一个数组首元素的地址。那&arr到底是什么呢??既然他有&取地址符号,是不是他也是一个地址呢??

int arr[4];

                 通过打印比较我们可以发现,他们所打印出的地址是一样的,都为数组首元素的地址,既然地址一样,就证明了他们是一样的吗??

                答案是,不是的。arr与&arr只是在数值上相同,而代表的意义却大不相同

                下面会通过举例证明:

                 通过对比我们可以发现,arr与arr+1相差了4个字节。

                                                 而&arr与&arr+1相差了16个字节

                 &arr,为取数组的指针,那么其类型就为数组指针:int(*)[4],数组指针类型+1跳过的是整个数组(即:4*4=16字节数)。所以arr与arr+1、&arr与&arr+1分别的差值就会不相同。

                3.4数组指针的运用

                数组指针在一维数组上的运用较少,主要服务于二维数组,下面将通过举例说明其运用

                二维数组函数传参,可以用使用指针接收,既然是接收数组的指针,自然是使用数组指针。

                二维数组数组名是首元素地址,第一行的地址,相应的arr+1跳过16个字节,跳过第一整行,到达第二行第一个元素的地址

                二维数组运用数组指针打印:

                二维数组的数组名表示为首元素的地址,即第一行的地址。在数组指针接收的时候,得到的也只是第一行的地址,arr[3][5]中一行有5个元素,所以数组指针为int(*p)[5],表明的是一个指针指向数组的数组有5个元素。               

   //二维数组的打印//
void Printf(int(*arr)[4],int r,int c)
{for (int i = 0; i < r; i++){for (int j = 0; j < c; j++){printf("%d ", (*(arr + i))[j]);//也可以写成arr[i][j]}                                  //(*(arr+i))等价于arr[i]printf("\n");}
}
int main()
{int arr[3][4] = { {1,2,3,4},{0,0,0,0},{2,3,3,3} };Printf(arr, 3, 4);return 0;
}

                3.5数组指针代码解析         

int(*parr[10])[5];

                此代码表示的是,

                parr[10]是一个数组,含有10个元素。

                每一个元素的类型是:int (*) [5]

                即为,一个parr[10]数组含有10个元素,每一个元素的类型是:int(*)[5],每一个元素都包含5个int类型         

        4.数组传参,指针传参

                4.1一级指针接收参数

                当函数的参数部分为一级指针的时候,函数能接收的参数有:

                一维数组,一级指针的变量,与函数参数中一级指针指向的类型相同的地址。

void test(int* p)
{return 0;
}
int main()
{int a = 0;int arr[4];int *P = &a;test(&a);//与函数参数部分指针指向的类型相同的地址test(arr);//一维数组test(p);//一级指针
}

                4.2二级指针接收参数

                当函数的参数部分为二级指针的时候,函数能接收的参数有:

                一级指针的变量的地址,二级指针的变量,指针数组。

void test(int** p)
{return 0;
}
int main()
{int *pa;int **ppaint* a[10];test(&pa);//一级指针的地址test(ppa);//二级指针的变量test(a);//指针数组
}

        5.函数指针

                5.1函数指针的定义

                与前面介绍的数组指针格式类似,数组指针是指向数组的指针,则函数指针是指向函数的指针

int add(int x,int y)
{return x + y;
}int main()
{int (*pa)(int,int) =&add;//函数指针int ret = (*pa)(3,2);printf("%d",ret);
}

                函数名为函数区域块的首地址,所以我们在定义函数指针将函数地址赋给指针的时候可以不用取地址符号,相应的在使用函数指针的时候也可以直接使用,并不需要解引用。

                下面举例证明:

int add(int x, int y)
{return x + y;
}int main()
{int (*pa)(int, int) = &add;int ret = (*pa)(3, 2);int (*pa2)(int, int) = add;int ret2 = pa(3, 2);printf("ret = %d\n", ret);printf("ret2 = %d\n", ret2);
}

                打印结果:

                5.2函数指针代码解析

                代码1:

(*(void (*)())0)();

                注意:void(*)()是一种类型 

                所以,此代码其实上是一个调用函数传参的。 

                代码2:

void (*signal(int , void(*)(int)))(int);

                本代码为,signal函数的声明,函数参数分别为(整型,函数指针类型),函数返回类型为函数指针类型

                函数指针类型:(指向函数的返回类型(*)(指向函数的参数类型);

                可以看成:(但绝对不可以写成这种形式,这是错误的形式!!!!!!!!!

void(*)(int) signal(int,void(*)(int));类型            函数

        6.函数指针数组

                看这个名字后缀,这东西肯定是一个数组,而且还是用来存放函地址的数组。

                6.1函数指针数组的定义

                函数指针数组,是一个函数指针类型的数组

                函数指针类型:(指向函数的返回类型)(*)(指向函数的参数类型)

                数组:数组名[存放元素个数]

                结合起来就是:

                (指向函数的返回类型)(*数组名[存放元素个数])(指向函数的参数类型)

                6.2函数指针数组的运用

                函数指针数组的用途:转移表

                因为篇幅的原因,关于函数指针数组的运用将链接在下方

                链接:[C语言]运用函数指针数组构建一个简单计算器_HY_PIGIE的博客-CSDN博客

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

                即指向函数指针数组的指针。函数指针数组,既然是数组就可以取其地址来用另一个指针变量存放

                其声明为: 

                定义其存放一个函数指针数组的指针:

int(*(*pp)[5])(int,int) = &p;

                 本文章完。

                如果文章内有不对的地方欢迎留言指正,觉得本文章对您有帮助的话还请收藏留言点赞!感谢您的支持!

                 


http://www.ppmy.cn/news/10919.html

相关文章

Qt 使用 Matlab函数

背景&#xff1a;个人的Qt项目中&#xff0c;需要一个图片分割算法。该算法之前在Matlab上实现过&#xff0c;同时转成C版本有点麻烦&#xff0c;因此尝试通过Qt与Matlab编程相结合的方式&#xff0c;实现该功能。 注意&#xff1a;以下所有功能及配置过程&#xff0c;默认已经…

直观理解--马氏距离

首先我们很了解欧氏距离了&#xff0c;就是用来计算欧式空间&#xff08;就是我们常见的坐标系&#xff09;中两个点的距离的。 比如点 x(x1,…,xn)x (x_1,…,x_n)x(x1​,…,xn​) 和 y(y1,…,yn)y (y_1,…,y_n)y(y1​,…,yn​) 的欧氏距离为&#xff1a; d(x,y)(x1−y1)2(x2…

ESXI8.0一键安装黑群晖DSM7

&#x1f388; 作者&#xff1a;互联网-小啊宇 &#x1f388; 简介&#xff1a; CSDN 运维领域创作者、阿里云专家博主。目前从事 Kubernetes运维相关工作&#xff0c;擅长Linux系统运维、开源监控软件维护、Kubernetes容器技术、CI/CD持续集成、自动化运维、开源软件部署维护…

KubeSphere使用外部ES进行日志收集(多行日志)

环境kubesphere &#xff1a; v3.3.1Docker&#xff1a;20.10.8Fluent-Bit&#xff1a;2.0.6-2.0.8ESKibana&#xff1a;7.9.3Docker日志示例{"log":"2023-01-10 11:32:50.021 - INFO --- [scheduling-1] traceId: p6spy : 1|conn-0|statement|SELECT fd_id A…

融合注意力模块SE基于轻量级yolov5s实践路面坑洼目标检测系统

在很多的项目实战中验证分析注意力机制的加入对于模型最终性能的提升发挥着积极正向的作用&#xff0c;在我之前的一些文章里面也做过了一些尝试&#xff0c;这里主要是想基于轻量级的s系列模型来开发构建路面坑洼检测系统&#xff0c;在模型中加入SE注意力模块&#xff0c;以期…

React相关扩展一(setState、lazyLoad、Hooks相关)(九)

系列文章目录 第一章&#xff1a;React基础知识&#xff08;React基本使用、JSX语法、React模块化与组件化&#xff09;&#xff08;一&#xff09; 第二章&#xff1a;React基础知识&#xff08;组件实例三大核心属性state、props、refs&#xff09;&#xff08;二&#xff0…

【寒假每日一题】DAY1.水仙花数

一、题目描述 求0&#xff5e;100000之间的所有“水仙花数”并输出。 什么是水仙花数&#xff1a; “水仙花数”是指一个n位数&#xff0c;其各位数字的n次方之和确好等于该数本身&#xff0c;如:153&#xff1d;1^3&#xff0b;5^3&#xff0b;3^3&#xff0c;则153是一个“水…

STM32 TIM PWM高阶操作:刹车及状态约束

STM32 TIM PWM高阶操作&#xff1a;刹车及状态约束 刹车及状态约束是STM32 TIM PWM控制里面比较复杂的一部分&#xff0c;涉及到PWM波形产生前&#xff0c;中&#xff0c;后的管脚状态输出。 这里先引入两个描述&#xff0c;一个是“半高阻”&#xff0c;意思是STM32管脚输出…