🌟菜鸟主页:@晨非辰的主页

👀学习专栏《C语言学习》

💪学习阶段:C语言方向初学者

名言欣赏:"暴力解法是上帝给的,优化解法是魔鬼教的。"


目录

1. 字符指针变量

1.1 使用方式

1.2 例题解释

2. 数组指针变量

2.1 数组指针变量定义        

 2.2 数组指针变量的初始化

3. 二维数组传参本质

4. 函数指针变量

4.1 函数指针变量的创建

4.2 函数指针变量的使用

4.3 有趣的代码

4.3.1 typedef关键词

5. 函数指针数组


1. 字符指针变量

1.1 使用方式

--已经知道有一种指针类型为字符指针:char*,一般有两种使用方式:

int main()
{//第一种char ch = 'w';char* pc = &ch;//第二种char arr[] = "abcdef";char* pc = arr;return 0;
}

--当然还有另外方式:

int main()
{const char* pc = "abcdef";//这里代表把整个字符串放进了指针嘛?//结果显而易见,字符串为常量字符串,只是将首字符的地址存放printf("%c\n", *pc);//打印aprintf("%s\n", pc);//打印abcdef//%s打印字符串需要的是地址才能找到下一个字符,所以用pcreturn 0;
}

--对于方式3和方式2对比,方式3略过了数组,这就导致了无法通过*pc来改变字符串,也就是上面说的常量字符串。

1.2 例题解释

--经典笔试题:

int main()
{char str1[] = "hello bit.";char str2[] = "hello bit.";const char* str3 = "hello bit.";const char* str4 = "hello bit.";if (str1 == str2)printf("str1 and str2 are same\n");//1elseprintf("str1 and str2 are not same\n")//2;if (str3 == str4)printf("str3 and str4 are same\n");//3elseprintf("str3 and str4 are not same\n");//4return 0;
}

--代码打印;2、3;

        --首先请注意,根据博客指针(三)的内容,这里比较的都是数组首元素地址而不是数组内容;所以因为str1与str2虽然内容相同但为不同数组,首元素地址自然也不同;

        --对于str3与str4,都指向同一个字符串"abcdef"且为常量字符串,内容不会被修改,C/C++会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串时,他们实际会指向同一块内存,所以str3和str4相同。

--特别注意,比较字符串内容要使用strcmp函数


2. 数组指针变量

2.1 数组指针变量定义        

--在上一篇博客,学习了指针数组,数组存放的是指针;那下面也进行类比:

  • 整型指针变量:int* p,存放的整型变量地址,指向整型数据;
  • 字符指针变量;char* p,存放的字符型变量地址(字符串,存放的是首字符地址),指向字符型数据

--可知,数组指针存放的是数组地址,指向数组数据;

--下面对数据指针变量进行辨析:

1. int* p1[10]; --首先p1与[10]结合,那么p1就成了数组名,这也就是前面学的指针数组

2. int(*p2)[10]; --首先p2与*结合,p2成为指针变量名,[10]代表指针所指向的是大小为10的数组;所以是数组指针(必须确保加上(),使p先于和*结合)

 2.2 数组指针变量的初始化

--数组指针变量用来存放数组地址,那么初始化就要获取数组地址:&数组名。

int(*p) [10] = &arr; --&arr得到数组地址

--数组类型解释:

int  (*p)  [10]  =  &arr

  |      |        |

  |      |     p指向数组的元素个数

  |    p为指针变量名

p指向的数组的元素类型


3. 二维数组传参本质

--认识了数组指针,下面来理解二维数组是如何传参的吧:

//构建函数
void test(int arr[][5], int a, int b)
{int i = 0;int j = 0;for (i = 0; i < a; i++){for (j = 0; j < b; j++){printf("%d ", arr[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);//将数组名,行列数传过去return 0;
}

--哎,在前面说一维数组传参时,形参可以写成数组也可以写成指针,那二位可以吗?

        --首先来看二维数组,可以看成每个元素都是一维数组,也就是每一行就是一个一维数组:

 

 --所以根据数组名含义来说,二维数组的数组名代表的是首元素地址也就是第一行这个一维数组的地址:类型就是int  [5]、数组指针类型是int(*) [5]。

--就意味着二维数组传参本质上也是传递地址,传递的是第一行⼀维数组地址,那么形参也是可以写成指针形式的:

void test(int(*arr) [5], int a, int b)
{int i = 0;int j = 0;for (i = 0; i < a; i++){for (j = 0; j < b; j++){printf("%d ", *(*(arr+i)+j));//*(arr + i) 解引用得到 arr[i](第 i 行的数组名)//+j再解引用是访问一维数组的内容,等价于arr[][]}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);//将数组名,行列数传过去return 0;

总结:二维数组传参,形参的部分可以写成数组,也可以写成指针形式。


4. 函数指针变量

4.1 函数指针变量的创建

--同样类比其他指针,函数指针就是存放函数地址的,通过地址调用函数,那函数地址怎么获取呢?

void test()
{printf("hehe\n");
}
int main()
{printf("test:  %p\n", test);printf("&test: %p\n", &test);return 0;
}

        --可见函数是有地址的,函数名就是地址(与数组不一样)。

--下面就要开始创建变量来存放地址:


int* test(int n, char* p)
{(...);
}int* (*pf)(int, char*) = test;int Add(int x, int y)
{return x + y;
}//参数可写可不写
int(*pf)(int, int) = Add;

--函数指针类型图解:

4.2 函数指针变量的使用

--通过函数指针调用指针指向的函数

int Add(int x, int y)
{return x + y;
}
int main()
{int(*pf)(int, int) = Add;printf("%d\n", (*pf)(10, 20));printf("%d\n", pf(10, 20));//解不解引用都可以,因为pf在这里等价于Addreturn 0;
}

--  注意:C 语言标准规定,函数指针的解引用会自动转换回函数地址,因此 *pf 仍然等同于 pf。

4.3 有趣的代码

--代码1

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

--解释:这段代码是在调用0地址处的函数

  1.  void(*)()是一个函数指针类型,这个指针指向的函数没有参数,返回类型void;
  2.  (void (*)())0 是将0强转为这种函数指针类型,意味着0处有这么一个函数;
  3. (* (void (*)())0)();对0地址进行解引用,调用函数;

--来自《C陷阱和缺陷》

 --代码2

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

--解释:是一次函数声明,函数名叫signal

  1. signal函数有两个参数,第一个参数是int类型,第二个参数是函数指针类型 void(*)(int),该指针指向的函数参数是int,返回类型是void;
  2. signal函数的返回类型也是一个函数指针类型 void(*)(int) ,指针指向的函数参数是int,返回类型是void;
  3. 直观表达:void * (int) signal (int , void(*)(int)) ;//但是不能这么写

--来自《C陷阱和缺陷》

4.3.1 typedef关键词

--显而易见,typedef用来类型重命名的,可以将复杂的类型简单化。

 --比如:

unsigned int 太长不方便,可以用关键词重定义为uint :typedef  unsigned int  uint;

         --指针类型也可以简化命名的,将int *重命名

typedef  int*  ptr_t;

        --但是对于数组指针和函数指针就有不同:

       -- 数组指针类型 int (*) [5] ,需要重命名为parr_t,要这样写:

typedef int(*parr_t)[5]; --新的类型名必须在*的右边

        --函数指针类型重命名是一样的,将 void(*) (int) 类型重命名为pfun_t,可以这样写:

typedef void(*pfun_t)(int); --新的类型名必须在*的右边

 --那么为了更好理解上面的代码2,这样命名:

typedef void(*pfun_t)(int); ——> pfun_t signal(int, pfun_t);


5. 函数指针数组

--在上一篇博客分享了指针数组,那么把函数的地址放到数组中,就成为了函数指针数组,如何定义呢?

int (*parr1[3])();

 --parr1先和 [ ] 结合,说明parr1是数组,内容是 int (*)()类型的指针;

--对于函数指针的用途:转移表,小子会在下一篇进行分享,千万别急~~ 


往期复习:

1. #C语言——学习攻略:深挖指针路线(一)--指针变量、地址、意义与指针运算

2. #C语言——学习攻略:深挖指针路线(二)--const修饰、野指针分析、断言和指针的作用

3. #C语言——学习攻略:深挖指针路线(三)--数组与指针的结合、冒泡排序


结语:本篇内容就到这里了,主要分享了指针变量类型的一些内容,后续仍会分享指针的相关知识;指针的内容需要反复研读 ,如果这篇文章对你的学习有帮助的话,欢迎一起讨论学习,你这么帅、这么美给个三连吧~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/91359.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/91359.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/91359.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot收尾+myBatis plus

一、数据传递返回值为:字符串package com.apesource.springboot_web_04.controller;import com.apesource.springboot_web_04.pojo.Emp; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;/*** 返回值为:字符…

基于 Spring Boot 实现动态路由加载:从数据库到前端菜单的完整方案

在后台管理系统中&#xff0c;不同用户角色往往拥有不同的操作权限&#xff0c;对应的菜单展示也需动态调整。动态路由加载正是解决这一问题的核心方案 —— 根据登录用户的权限&#xff0c;从数据库查询其可访问的菜单&#xff0c;封装成前端所需的路由结构并返回。本文将详细…

VitePress学习-自定义主题

VitePress-自定义主题 代码仓库 基础了解 初始化项目的时候选择 custom theme 运行后会发现页面挺丑的。 如果想要用默认主题怎么办呢&#xff0c;修改Layout。 使用默认主题的Layout <script setup lang"ts"> import { useData } from vitepress; impo…

【GEO从入门到精通】生成式引擎与其他 AI 技术的关系

2.1.3 生成式引擎与其他 AI 技术的关系生成式引擎作为人工智能领域的创新力量&#xff0c;与其他 AI 技术紧密相连&#xff0c;相互促进&#xff0c;共同推动 生成式引擎优化&#xff08;GEO&#xff09; 的发展。这些技术使生成式引擎能够为消费者提供更加个性化和精准的内容。…

JAVAEE--4.多线程案例

设计模式1.单例模式1.1饿汉模式1.2懒汉模式(单线程版)1.3懒汉模式(多线程版本)1.4懒汉模式(多线程版本进阶版)2.阻塞队列3.定时器4.线程池1.单例模式设计模式是"软性约束",不是强制的,可以遵守也可以不遵守,按照设计模式写代码使代码不会太差框架是"硬性约束&qu…

量化感知训练(QAT)流程

WHAT&#xff1a;量化感知训练&#xff08;Quantization-Aware Training, QAT&#xff09; 是一种在模型训练阶段引入量化误差的技术。它的核心思想是&#xff1a;通过在前向传播时插入“伪量化节点”引入量化误差&#xff0c;将权重和激活模拟为低精度&#xff08;如 int8&…

docker 用于将镜像打包为 tar 文件

docker save 是 Docker 中用于将镜像打包为 tar 文件的命令&#xff0c;常用于镜像的备份、迁移或离线传输。以下是其核心用法和注意事项&#xff1a;一、基本语法bashdocker save [选项] IMAGE [IMAGE...] > 文件名.tar # 或 docker save -o 文件名.tar IMAGE [IMAGE...]IM…

设计模式(六)创建型:单例模式详解

设计模式&#xff08;六&#xff09;创建型&#xff1a;单例模式详解单例模式&#xff08;Singleton Pattern&#xff09;是 GoF 23 种设计模式中最简单却最常被误用的创建型模式。其核心价值在于确保一个类在整个应用程序生命周期中仅存在一个实例&#xff0c;并提供一个全局访…

PostgreSQL AND OR 操作符详解

PostgreSQL AND & OR 操作符详解 在数据库查询中,AND 和 OR 是两种常见的逻辑操作符,用于组合多个查询条件。PostgreSQL 作为一款功能强大的开源关系型数据库管理系统,同样支持这些操作符。本文将详细介绍 PostgreSQL 中的 AND 和 OR 操作符,并探讨它们在查询中的应用…

RabbiteMQ安装-ubuntu

Ubuntu 1.安装Erlang RabbitMQ需要Erlang语言的支持&#xff0c;在安装RabbitMQ之前需要安装Erlang #更新软件包 sudo apt-get update#安装erlang sudo apt-get install erlang查看erlang版本 roothcss-ecs-027f:/# erl Erlang/OTP 24 [erts-12.2.1] [source] [64-bit] [sm…

Linux驱动20 --- FFMPEG视频API

目录 一、FFMPEG 视频 API 的使用 1.1 介绍 1.2 整体编程过程 获取核心上下文指针 打开输入流文件 获取输入流 获取编码器 初始化解码器 申请输出流指针 获取显示数据空间大小 申请输出显示空间 绑定输出流和输出显示空间 申请格式转换上下文 申请输入流指针 读取一帧数据 发…

OpenBayes 一周速览丨Self Forcing 实现亚秒级延迟实时流视频生成;边缘AI新秀,LFM2-1.2B采用创新性架构超越传统模型

公共资源速递 This Weekly Snapshots &#xff01; 5 个公共数据集&#xff1a; * AF-Chat 音频对话文本数据集 * ArtVIP 机器交互式图像数据集 * Updesh 印度语合成文本数据集 * Medical Information 药品信息数据集 * Nemotron-Math-HumanReasoning 数学推理数据集…

[NOIP2002 提高组] 均分纸牌

题目描述有N堆纸牌&#xff0c;编号分别为 1,2,…,N。每堆上有若干张&#xff0c;但纸牌总数必为N的倍数。可以在任一堆上取若干张纸牌&#xff0c;然后移动。移牌规则为&#xff1a;在编号为1堆上取的纸牌&#xff0c;只能移到编号为2的堆上&#xff1b;在编号为N的堆上取的纸…

【音视频】WebRTC-Web 音视频采集与播放

一、打开摄像头 打开摄像头首先需要有一个html的video标签&#xff1a; id "local-video"&#xff0c;是为了后续的js脚本调用这个对象autoplay是设置打开后自动播放&#xff0c;playsinline则是为了兼容移动端 <video id "local-video" autoplay p…

数据治理平台如何选?深度解析国产化全栈方案与行业落地实践

“数据治理平台厂商有哪些&#xff1f;”国内主流厂商包括阿里云、华为、百分点科技等&#xff0c;各有所长。其中&#xff0c;百分点科技凭借在应急管理、智慧公安及央国企数字化领域的深度实践&#xff0c;打造了行业特色鲜明的数据治理解决方案。百分点科技的数据治理解决方…

限流算法详解:固定窗口、滑动窗口、令牌桶与漏桶算法全面对比

限流&#xff08;Rate Limiting&#xff09;是保障系统稳定性和服务质量的关键机制&#xff0c;尤其在高并发、突发流量、攻击防护等场景中至关重要。本文将详细介绍四种主流限流算法&#xff1a;固定窗口&#xff08;Fixed Window&#xff09;滑动窗口&#xff08;Sliding Win…

Sentinel 搭建应用层面与网关层面的流控保护

源码&#xff1a;妖精的尾巴/spring-cloud-alibaba Nacos 和 Sentinel Dashboard 我这里全是使用window 本地运行的&#xff0c;需要自行下载运行 服务层面&#xff1a; 当你在某个具体的服务上使用Sentinel时&#xff0c;更多的是关注该服务内部资源的保护。例如&#xff0c…

纯血鸿蒙 AudioRenderer+AudioCapturer+RingBuffer 实现麦克风采集+发声

总共两个类&#xff0c;放到代码里&#xff0c;就可以快速完成K歌的效果&#xff0c;但应用层这么做延迟是比较高的&#xff0c;只是做一个分享。 类代码 import { audio } from kit.AudioKit; import { BusinessError } from kit.BasicServicesKit; import { AudioBufferFlow,…

洛谷 P1601 A+B Problem(高精)普及-

题目描述 高精度加法&#xff0c;相当于 ab problem&#xff0c;不用考虑负数。 输入格式 分两行输入。a,b≤10500a,b \leq 10^{500}a,b≤10500。 输出格式 输出只有一行&#xff0c;代表 ababab 的值。 输入输出样例 #1 输入 #1 1 1输出 #1 2输入输出样例 #2 输入 #2 1001 909…

Matrix Theory study notes[6]

文章目录linear spacereferenceslinear space a basis of linear space VkV^kVk,which is x1,x2,...xkx_1,x_2,...x_kx1​,x2​,...xk​,can be called as a coordinate system.let vector v∈Vkv \in V^kv∈Vk and it can be linear expressed on this basis as va1x1a2x2...…