C语言进阶第二课-----------指针的进阶----------升级版
作者前言
🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂
🎂 作者介绍: 🎂🎂
🎂 🎉🎉🎉🎉🎉🎉🎉 🎂
🎂作者id:老秦包你会, 🎂
简单介绍:🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂
喜欢学习C语言和python等编程语言,是一位爱分享的博主,有兴趣的小可爱可以来互讨 🎂🎂🎂🎂🎂🎂🎂🎂
🎂个人主页::小小页面🎂
🎂gitee页面:秦大大🎂
🎂🎂🎂🎂🎂🎂🎂🎂
🎂 一个爱分享的小博主 欢迎小可爱们前来借鉴🎂
指针进阶
- **作者前言**
- 前提复习
- 字符指针
- 指针数组
- 数组指针
- 数组传参和指针传参
- 函数指针
前提复习
- 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。
- 指针(指针变量)的大小是固定的4/8个字节(32位平台/64位平台)。
- 指针是有类型,指针的类型决定了指针的±整数的步长,指针解引用操作的时候的权限。
- 指针的运算。(数组元素指针相减等于两者之间的元素个数)
- 内存单元是有编号的,编号 == 地址 ==指针
字符指针
用法一:
#include<stdio.h>
int main()
{char a = 'w';char* p = &a;return 0;
}
这里的地址使用很简单,下面还有一种用法
#include<stdio.h>
int main()
{const char* p = "abcdef";printf("%c", *p);printf("%s", p);return 0;
}
这里的p存储的是字符a的地址,我们可以想象成"abcdef"储存在一个数组中,传入p的值为数组名,也就是首元素的地址,就是a
还有一点需要注意的是"abcdef"是一个常量字符串,不能修改,但是会有些人通过*p来修改,这会造成程序崩溃,但是却不会报出警告,往往我们会加一个const 来把错误显示出来
指针数组
指针数组本质上就是一个数组,只是类型不一样而已
比如 字符数组–存放字符的数组
整形数组—存放整形的数组
指针数组—存放指针的数组,存放在数组中的元素都是指针类型
应用1:
#include<stdio.h>
int main()
{int arr[] = { 1,2,3,4,5,6 };int arr1[] = { 2,3,4,5,6,7 };int arr2[] = { 3,4,5,6,7,8 };int arr3[] = { 4,5,6,7,8,9 };int arr4[] = { 5,6,7,8,9,10 };int* arr5[] = { arr,arr1,arr2,arr3,arr4 };//指针数组int i = 0;for (i = 0; i < 5; i++){int j = 0;for (j = 0; j < 6; j++){printf("%d ", arr5[i][j]);}printf("\n");}return 0;
}
这种效果相当于写出了一个二维数组的效果
应用2:
```cpp
#include<stdio.h>
int main()
{char* arr[5] = { "hello bit", "hehe", "penggeC","nitejiuyeke", "C++" };int i = 0;for (i = 0; i < 5; i++){printf("%s\n", arr[i]);}return 0;
}
这里的效果就相当于写成了一个字符串组成的数组,原理就是数组arr元素保存的是字符串首字符地址,通过遍历取出来,然后一一打印出来
数组指针
指针数组是存放指针的数组,
数组指针是啥呢?,
我们可以想象一下,字符指针就是指向字符的指针, 整形指针就是指向整形的指针,所以,数组指针就是指向数组的指针
#include<stdio.h>
int main()
{int a = 10;int* p = &a;char b = 'q';char* pr = &b;int arr[10];int* pa = arr;//数组名是首元素的地址//存在两个例外//sizeof (arr) 这里的arr表示的是整个数组,sizeof(数组名)计算的是整个数组的大小// &arr 取出的是整个数组的地址return 0;
}
//数组名是首元素的地址
//存在两个例外
//sizeof (arr) 这里的arr表示的是整个数组,sizeof(数组名)计算的是整个数组的大小
// &arr 取出的是整个数组的地址,如果从值的方向考虑就会发现arr和&arr的值是一样的
可以看出数组名和 &数组名的差别,指针类型决定了指针+1 加了几个字节
#include<stdio.h>
int main()
{int arr[5] = { 1,2,3,4,5 };int(*p)[5] = &arr;//数组指针,里面的大小必须写 !!!!char arr1[100] = "123456";char(*pa)[100] = &arr1;//告诉我们pa是一个指针,指向的是char类型的数组地址char* arr2[5];char* (*pa2)[5] = &arr2;//告诉我们pa2是一个指针,指向的是char*类型的数组地址printf("%p\n", p);printf("%p\n", arr);return 0;
}
数组指针的写法就是 类型 (p)[数组大小,为了好理解我们可以理解为 char p[10],如果写出这样就会变成指针数组了,为了区分开来,才加()区分,指针类似还是char* 没有改变,只是写法不同而已
#include<stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int(*pa)[10] = &arr;int* p = arr;int i = 0;for (i = 0; i < 10; i++){printf("%d", (*pa)[i]);//如果使用pa[i] 等价于*(pa + i)}for (i = 0; i < 10; i++){printf("%d", p[i]);}return 0;
输出的时候我们可以这样理解 arr[i] 可以访问元素, p = arr 所以p[i]可以访问元素
但是pa是数组指针 *pa可以消除& 得到arr , (*pa)[i]可以访问元素
一般我们使用数组指针是在二维数组使用的
在使用之前我们回忆一下一维数组传参给函数时
#include<stdio.h>
void print(int* p, int len)
{int i = 0;for (i = 0; i < len; i++){printf("%d ", p[i]); //p[i] == *(p + i)}}
int main()
{int arr[5] = { 1,2,3,4,50 };print(arr, 5);return 0;
}
p[i] 等价于*(p + i), 所以打印地址一般用 arr + i 或者 &arr[i] 或者 &arr[0] + i
二维数组的应用
#include<stdio.h>
void print(int arr[][3], int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){printf("%d ", arr[i][j]);}printf("\n");}
}
void print1(int (*pa)[3], int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){printf("%d ", pa[i][j]);//pa[i] == *(pa + i)}printf("\n");}
}
int main()
{int arr[3][3] = { {1,2,3},{2,3,4},{3,4,5} };print(arr, 3, 3);print1(arr, 3, 3);return 0;
}
二维数组是一维数组的数组,我们可以想象一下二维数组arr里面的元素是一维数组,传参arr是首元素的地址,也就是把一维数组的整个地址传进去,
这里使用了数组指针pa ,如果要访问第二个元素可以写成 pa[1]
那我们就再扩展一下
int (*parr2)[10];
int (*parr3[10])[5];
第一行的意思就是,parr2是一个数组指针,指向的数组有10个元素,每个元素为整形
第二行代码的意思就是parr3是一个数组,进行存放数组指针的,可以存放10个数组指针,每个数组指针指向一个元素个数为5的数组,并且这个数组的元素类型为int
总结:这里我们要清楚数组指针的使用,及写法,比如 int (*pa)[10] = &arr
如果arr是一维数组,访问每个元素可以写成(pa)[i],不能写成pa[i],因为pa[i]
等价于(pa + i) ,如果arr为二维数组,我们可以写成pa[i][j]访问每一个元素
数组传参和指针传参
一维数组传参
,数组传参本质上是,传递了首元素的地址数组传参,形参也可以是指针
数组传参,形参接收,形参的形式可以写成arr[] 或者 arr[大小] 或者 指针变量
如果碰见指针传参指针,我们就要思考要使用哪级指针接收,上图就是二级指针接收arr2数组首元素的地址,arr2数组首元素也是存储地址的
二维数传参
一级指针传参
二级指针传参
int* arr[5] int ** p = arr ,这个也可以
总结:指针传参有很多种传入方法,但是传入的意思是一样的
函数指针
数组指针是指向数组的指针,存放的是整个数组的地址 ----&数组名
那么函数指针是指向函数的指针,存放的是函数的地址,
那怎么得到函数的地址呢?
#include<stdio.h>
int Add(int x, int y)
{return x + y;
}
int main()
{//&函数名就是函数的地址//函数名也是函数的地址//这两者没有区别printf("%p\n", &Add);printf("%p\n", Add);//函数指针int (*pA)(int, int) = Add;//意思就是pA为函数指针 ,指向的函数的类型为int 参数的类型也为intint (*pA1)(int, int) = &Add;printf("%p\n", pA);printf("%p\n", pA1);int tr = (*pA)(2, 3);// 解引用pA找到函数,并传入参数int re = pA(2, 3);printf("%d\n", tr);printf("%d\n", re);//这种写法是因为Add和&Add是一样的 ,我们调用函数是Add(2,3),所以pA存储Add,我们也可以使用pA(2,3)效果和调用函数是一样的return 0;
}
可以看出获取函数的地址有两种 &函数名或者函数名
我们调用函数除了使用函数名,还可以使用函数指针调用,使用函数指针调用,我们要熟悉函数调用的写法,Add(2,3),因为函数指针存储的是函数名 Add,所以通过函数指针调用函数,可以写成 pA (2,3),或者(*pA)(2,3)(可以理解为解引用找到函数并传参给函数)
从这个图中我们可以看出函数指针变量的类型
我们从这张图可以看出
代码1的意思就是 把0 强制类型转换成函数指针类型 ,并且解引用找到函数调用,这个函数没有参数
代码2 是一个函数声明,看到这里是不是很吃惊,那我们分析一下,
signal函数有两个参数,第一个参数的类型为int 第二个参数的类型是void()(int),因为不可能是函数调用,当我们吧函数去掉就会发现 void ()(int)是一个函数指针类型,如果我们换个类型就很好理解了 int signal( int, void(*)(int) ); 平时我们函数声明就是这样的,只是这个函数指针类型有写法有点特殊,但不改变这就是一个函数指针类型,
如果觉得这样写很麻烦,我们可以把这个函数指针类型重定义
typedef void(vi_int)(int);注意一下不要写成typedef void()(int) vi_int;这样是不行的
总结:这里我们要熟悉函数指针类型和指针传参 方式有很多但是意思是一样的
相关文章:

C语言进阶第二课-----------指针的进阶----------升级版
作者前言 🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂 🎂 作者介绍: 🎂🎂 🎂 🎉🎉🎉…...

若依vue -【 111 ~ 更 ~ 127 完 】
【更】111 3.5.0版本更新介绍 112 使用docker实现一键部署 1、安装docker yum install https://download.docker.com/linux/fedora/30/x86_64/stable/Packages/containerd.io-1.2.6-3.3.fc30.x86_64.rpm yum install -y yum-utils device-mapper-persistent-data lvm2 yum-c…...

vue-pc端实现按钮防抖处理-自定义指令
前言 我们经常在移动端会处理按钮和输入框的防抖和节流处理,在pc端很少进行这样的操作 但是在pc端也是可以进行按钮的防抖操作,这样也是比较合理,可以不用但不可以不会 我们只要配合vue项目自定义指令加上全局注册,就可以实现按…...
python解决8皇后问题
def is_valid(queens, row, col):for i in range(row):if queens[i] == col or abs(queens[i] - col) == abs(i - row):return Falsereturn Truedef solve_n_queens(n, row, queens, result):if row == n:result.append(queens[:]) # 将当前解添加到结果中returnfor col in ra…...

xcode打包导出ipa
转载:xcode打包导出ipa 目录 转载:xcode打包导出ipa 第一步:注册苹果开发者账号 第二步:下载APP Uploader 第三步:使用xcode打包导出ipa文件,供其他人内测 众所周知,在开发苹果应用时需要使…...
更优雅地调试SwiftUI—借助LLDB
更优雅地调试SwiftUI—借助LLDB 概述 你是否写过这样的代码: struct ContentView: View {@State private var mySize: CGFloat = 15.0var myString: String = "Hi LLDB"var myArray: [Int] = [1, 2, 3]var body: some View {VStack {Text("Hello World"…...

2.4 网络安全新技术
数据参考:CISP官方 目录 云计算安全大数据安全移动互联网安全物联网安全工业互联网安全 一、云计算安全 1、云计算定义 云计算是指通过网络访问可扩展的、灵活的物理或虚拟共享资源池,并按需自助获取和管理资源的模式。在云计算中,计算资…...
人生天地之间,若白驹之过隙,忽然而已
人生天地之间,若白驹之过隙,忽然而已 这段时间有个同事离职了,其实身边不断有老人走、有新人来,但这回走的同事和别的有些不同,当时我入职面试的时候就是他面试的我,工作中有啥问题都会请教他,…...

MySQL — MVCC
文章目录 MVCCMVCC 实现原理隐藏字段undo logundo log的用途undo log类型 版本链ReadView MVCC InnoDB是一个多版本的存储引擎。它保留有关已更改行的旧版本的信息,以支持并发和回滚等事务性特性。这些信息存储在undo表空间中的数据结构称为回滚段。InnoDB使用回滚…...

Android模板设计模式之 - 构建整个应用的BaseActivity
1. 模式介绍 模式的定义 定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 模式的使用场景 1.多个子类有公有的方法,并且逻辑基本相同时。 2.重要、复杂的算法,可…...
浏览器缓存技术--localStorage和sessionStorage原理与使用
localStorage和sessionStorage LocalStorageLocalStorage的特点存入/读取数据使用场景 sessionStoragesessionStorage的特点存入/读取数据使用场景sessionStorage 、localStorage 和 cookie 之间的区别 测试localStorage和sessionStorageIndexedDB LocalStorage 为了弥补 Cook…...

无涯教程-Perl - endservent函数
描述 此功能告诉系统您不再期望使用getservent从服务文件中读取条目。 语法 以下是此函数的简单语法- endservent返回值 此函数不返回任何值。 例 以下是显示其基本用法的示例代码- #!/usr/bin/perlwhile(($name, $aliases, $port_number,$protocol_name)getservent())…...
MRO工业品采购过程中,采购人员要注意哪些事项
MRO工业品指工厂或企业对其生产和工作设施、设备进行保养、维修,保证其运行所需要的非生产性物料,这些物料可能是用于设备保养、维修的备品备件,也可能是保证企业正常运行的相关设备,耗材等物资,如安全防护、传媒广电、…...
Jaeger 教程,OpenTelemetry 教程
ywanbing/otelToJaeger: opentelemetry 的链路追踪写入Jaeger中,使用的例子,拉下来就能跑(你已经部署好Jaeger的环境) (github.com) 上面是一个使用 OpenTelemetry trace 的一个源码。...
P1597 语句解析
题目背景 木有背景…… 题目描述 一串长度不超过 255 255 255 的 PASCAL 语言代码,只有 a , b , c a,b,c a,b,c 三个变量,而且只有赋值语句,赋值只能是一个一位的数字或一个变量,每条赋值语句的格式是 [变量]:[变量或一位整数…...

Java课题笔记~ Request请求
1.请求消息格式 客户端发送一个HTTP请求到服务器的请求消息包括以下格式: 请求行(request line)、请求头部(header)、空行和请求数据四个部分组成。下图给出了请求报文的一般格式。 GET请求: POST请求&am…...

Untiy Json和Xml的序列化和反序列化
Json的序列化和反序列化 1.定义数据类 [Serializable] public class ZoomPoint {// 点名称, 将作为Key被字典存储public string name;// 轴心X坐标public Vector2 pivot Vector2.one / 2;// 放大倍率,小于1是为缩小倍率,小于0是取绝对值,不…...

springboot在线小说阅读网站的设计与实现
网站首页: 用户登录/注册:用户注册时进行用户名及笔名存在的限制热门小说推荐:显示小说名及作者名,点击进入对应小说小说类别:玄幻,武侠,言情,历史等,点击对用分类到分类…...

整理mongodb文档:改
个人博客 整理mongodb文档:改 求关注,求批评,求进步 文章概叙 本文主要讲的是mongodb的updateOne以及updateMany,主要还是在shell下进行操作,也讲解下主要的参数upsert以及更新的参数。 数据准备 本次需要准备的数据不是很多…...

【设计模式】单例模式
什么是单例模式? 保证一个类仅有一个实例,并提供一个访问它的全局访问点 单例模式的应用场景 1.整个程序的运行中只允许有一个类的实例; 2.需要频繁实例化然后销毁的对象。 3.创建对象时耗时过多或者耗资源过多,但又经常用到…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...

边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...