C语言9 指针
目录
指针的声明与初始化
指针运算
指针的加法和减法
指针的比较
指针与数组
通过指针访问数组元素
指针与多维数组
声明指向多维数组的指针
访问多维数组元素
指针数组和数组指针
指针数组
数组指针
字符指针
字符串的定义和字符指针
直接使用字符指针初始化字符串
void指针
void指针的声明与使用
const修饰指针
修饰指针指向的内容
修饰指针本身
同时修饰指针和指针指向的内容
多级指针
二级指针
多级指针的使用
指向函数的指针
指针函数
指针传递
指针与动态内存分配
函数指针
回调函数
指针是一个变量,它的值是另一个变量的地址。它通过存储内存地址来间接访问变量。
指针的声明与初始化
指针的声明格式为:
类型 *指针名;
例如:
int *ptr; // 声明一个指向int类型的指针
指针的初始化可以通过取地址运算符&来完成:
int var = 10;
int *ptr = &var; // ptr现在指向变量var的地址
此时,ptr存储的是var的地址,而不是var的值。要访问var的值,可以使用解引用运算符*:
printf("%d\n", *ptr); // 输出10
指针运算
指针运算包括指针的加法和减法,这些运算在数组遍历和指针偏移中非常有用。
指针的加法和减法
指针加法和减法的本质是以指针所指向数据类型的大小为单位进行的。例如,对于int类型指针,每次加1实际上是加上sizeof(int)个字节。
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr; // ptr指向数组的第一个元素ptr++; // ptr现在指向数组的第二个元素
printf("%d\n", *ptr); // 输出20ptr--; // ptr现在指向数组的第一个元素
printf("%d\n", *ptr); // 输出10
指针的比较
指针还可以进行比较运算,常用于判断指针是否达到数组的末尾。
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr;while (ptr < arr + 5) {printf("%d ", *ptr);ptr++;
}
指针与数组
数组名在很多情况下可以看作是一个指向数组第一个元素的指针。例如:
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr; // 等同于int *ptr = &arr[0];
这意味着可以使用指针来遍历数组:
for (int i = 0; i < 5; i++) {printf("%d ", *(ptr + i)); // 输出数组的每个元素
}
通过指针访问数组元素
可以使用指针加偏移量的方式访问数组元素:
printf("%d\n", *(arr + 2)); // 输出30,与arr[2]等价
同样,可以使用下标运算符[]来访问指针所指向的数组元素:
printf("%d\n", ptr[2]); // 输出30,与arr[2]等价
指针与多维数组
多维数组的指针处理稍微复杂一些。以二维数组为例:
int arr[3][4] = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}
};
声明指向多维数组的指针
指向二维数组的指针的声明方式如下:
int (*ptr)[4] = arr; // ptr是一个指向包含4个int的数组的指针
访问多维数组元素
可以使用指针偏移来访问多维数组的元素:
printf("%d\n", *(*(ptr + 1) + 2)); // 输出7,相当于arr[1][2]
这表示:
ptr + 1移动到第二行,即指向arr[1]。*(ptr + 1)解引用得到第二行的数组,即arr[1]。*(ptr + 1) + 2移动到第二行的第三个元素,即arr[1][2]。- 最终,
*(*(ptr + 1) + 2)解引用得到该元素的值,即7。
指针数组和数组指针
指针数组和数组指针是两个容易混淆的概念。
指针数组
指针数组是一个数组,其元素是指针。例如:
int *arr[3];
int a = 1, b = 2, c = 3;
arr[0] = &a;
arr[1] = &b;
arr[2] = &c;
例如,可以创建一个字符指针数组来存储多个字符串:
char *names[] = {"Alice", "Bob", "Charlie"};for (int i = 0; i < 3; i++) {printf("%s\n", names[i]);
}
数组指针
数组指针是一个指向数组的指针。例如:
int *arr[3];
int a = 1, b = 2, c = 3;
arr[0] = &a;
arr[1] = &b;
arr[2] = &c;
字符指针
字符指针用于指向字符类型数据,常用于处理字符串。
字符串的定义和字符指针
在C语言中,字符串是以'\0'结尾的字符数组。字符指针可以指向字符串的第一个字符:
char str[] = "Hello, world!";
char *ptr = str; // ptr指向字符串的第一个字符
通过字符指针可以访问字符串中的各个字符:
while (*ptr != '\0') {printf("%c", *ptr);ptr++;
}
直接使用字符指针初始化字符串
可以直接使用字符指针指向字符串常量:
char *ptr = "Hello, world!";
需要注意的是,字符串常量是存储在只读内存中的,不能通过指针修改其内容:
char *ptr = "Hello, world!";
ptr[0] = 'h'; // 未定义行为,可能导致程序崩溃
void指针
void指针是一种通用指针类型,可以指向任何类型的数据,但不能直接解引用。需要先进行类型转换。
void指针的声明与使用
void *ptr;
int a = 10;
ptr = &a; // void指针指向int类型的变量// 需要进行类型转换后才能解引用
printf("%d\n", *(int *)ptr);
const修饰指针
const可以修饰指针,使指针或指针指向的内容不可修改。
修饰指针指向的内容
int a = 10;
const int *ptr = &a; // ptr指向的内容不可修改
// *ptr = 20; // 错误:尝试修改只读变量
ptr = &b; // 可以修改指针本身
本身
修饰指针本身
int a = 10;
int b = 20;
int *const ptr = &a; // ptr本身不可修改
*ptr = 20; // 可以修改指针指向的内容
// ptr = &b; // 错误:尝试修改const指针
同时修饰指针和指针指向的内容
int a = 10;
const int *const ptr = &a; // ptr本身和ptr指向的内容都不可修改
// *ptr = 20; // 错误:尝试修改只读变量
// ptr = &b; // 错误:尝试修改const指针
多级指针
多级指针是指指向指针的指针。它们可以用于间接访问变量,常用于处理复杂数据结构。
二级指针
二级指针是指向指针的指针:
int a = 10;
int *ptr = &a;
int **pptr = &ptr; // 二级指针指向一级指针printf("%d\n", **pptr); // 输出10,通过二级指针间接访问变量a
多级指针的使用
多级指针在处理动态内存分配和多维数组时非常有用:
int rows = 3, cols = 4;
int **matrix = malloc(rows * sizeof(int *));
for (int i = 0; i < rows; i++) {matrix[i] = malloc(cols * sizeof(int));
}// 使用matrix
for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {matrix[i][j] = i * cols + j;}
}// 释放matrix
for (int i = 0; i < rows; i++) {free(matrix[i]);
}
free(matrix);
指向函数的指针
指针不仅可以指向变量,还可以指向函数。函数指针用于实现回调函数和动态函数调用。
int add(int a, int b) {return a + b;
}int (*func_ptr)(int, int) = add; // 声明并初始化函数指针printf("%d\n", func_ptr(2, 3)); // 输出5,通过函数指针调用函数
指针函数
指针函数是指返回指针的函数。它在需要返回动态分配的内存块或者其他指针类型数据时非常有用。
示例
int* createArray(int size) {int *arr = malloc(size * sizeof(int));for (int i = 0; i < size; i++) {arr[i] = i;}return arr;
}int main() {int *array = createArray(5);for (int i = 0; i < 5; i++) {printf("%d ", array[i]);}free(array); // 记得释放内存return 0;
}
指针传递
在函数调用时传递指针,可以实现对原数据的修改。这是C语言实现传引用的方式。
示例
void increment(int *num) {(*num)++;
}int main() {int a = 5;increment(&a);printf("%d\n", a); // 输出6return 0;
}
指针与动态内存分配
C语言中使用malloc、calloc和realloc进行动态内存分配,使用free释放内存。
示例
int main() {int *arr = malloc(5 * sizeof(int));if (arr == NULL) {printf("Memory allocation failed");return 1;}for (int i = 0; i < 5; i++) {arr[i] = i * i;}for (int i = 0; i < 5; i++) {printf("%d ", arr[i]);}free(arr); // 释放内存return 0;
}
函数指针
函数指针是指向函数的指针,可以用于实现回调函数和动态函数调用。
示例
int add(int a, int b) {return a + b;
}int subtract(int a, int b) {return a - b;
}int main() {int (*operation)(int, int);operation = add;printf("Add: %d\n", operation(5, 3)); // 输出8operation = subtract;printf("Subtract: %d\n", operation(5, 3)); // 输出2return 0;
}
回调函数
回调函数是一种通过函数指针调用的函数,常用于事件驱动编程和异步编程。
示例
void processArray(int *arr, int size, void (*process)(int *))
相关文章:
C语言9 指针
目录 指针的声明与初始化 指针运算 指针的加法和减法 指针的比较 指针与数组 通过指针访问数组元素 指针与多维数组 声明指向多维数组的指针 访问多维数组元素 指针数组和数组指针 指针数组 数组指针 字符指针 字符串的定义和字符指针 直接使用字符指针初始化字…...
Floyd判圈算法——寻找重复数(C++)
287. 寻找重复数 - 力扣(LeetCode) 题目描述 给定一个包含 n 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。假设 nums 只有 一个重复的整数 ,返…...
面试题目分享
学习目标: 从面试了解自己的不足。 学习内容: 1.你会什么语言? 我该如何回答,我会java,c,c等,在工作中我会用到合适的语言。 牛逼吹的大话 尊敬的面试官,我精通Java和Python&…...
Solana开发之Anchor框架
文章目录 Solana开发之Anchor框架一、什么是Anchor二、安装和使用1. 安装rust2. 安装Solana下载预构建的二进制文件 3. 使用 Anchor 版本管理器 (avm) 进行安装(推荐) 四、Anchor 核心原理Anchor 程序由三部分组成程序的 ID 从哪里…...
界面组件Kendo UI for React 2024 Q2亮点 - 生成式AI集成、设计系统增强
随着最新的2024年第二季度发布,Kendo UI for React为应用程序开发设定了标准,包括生成式AI集成、增强的设计系统功能和可访问的数据可视化。新的2024年第二季度版本为应用程序界面提供了人工智能(AI)提示,从设计到代码的生产力增强、可访问性…...
python输出/sys/class/power_supply/BAT0/电池各项内容
读取 /sys/class/power_supply/BAT0/ 目录下的所有相关文件,并输出其内容: import os# 定义电池信息文件的路径 battery_path = "/sys/class/power_supply/BAT0/"# 读取文件内容的函数 def read_battery_info(file_name):try:with open(os.path.join(battery_path…...
HDFS体系架构文件写入/下载流程
HDFS体系架构 HDFS(Hadoop Distributed File System,Hadoop分布式文件系统)是Hadoop项目中的一个核心组件,旨在以高容错、高吞吐量来处理大规模数据集。它的体系架构由以下几个主要部分组成:Client,NameNo…...
大模型之战进入新赛季,开始卷应用
最近一段时间,国产大模型Kimi彻底火了,而这波爆火,某种意义上也展示了一个问题,即大模型的落地场景可能比技术比拼,更重要。 国产大模型Kimi突然爆火,与Kimi相关的产业链甚至被冠上“Kimi概念股”之名&…...
MySQL8.4.0 LTS安装教程 【小白轻松上手2024年最新长期支持版本MySQL手把手保姆级Windows超详细图文安装教程】
MySQL8.4.0 LTS安装教程 【小白轻松上手2024年最新长期支持版本MySQL手把手保姆级Windows超详细图文安装教程】 MySQL8.4.0前言(版本说明)官网下载MySQL1.访问MySQL官网2. 打开MySQL官网下载页面3. 选择下载类型Select Version【MySQL版本号】Select Ope…...
Linux 例题及详解
1.(yum)以下描述正确的是 A.在Centos中可以使用yum install 命令安装软件包 B.在Centos中可以使用yum uninstall 命令卸载软件包 C.在Centos中可以使用yum list 查看所有可安装软件包 D.在Centos中可以使用yum show查看所有可安装软件包 选项A、C是正确…...
爆款文案管理系统设计
设计一个爆款文案管理系统,目标是帮助营销团队高效地创建、管理并分析吸引人的文案,以提升产品或服务的市场吸引力和销售转化率。以下是一些关键功能和设计考量点: 1. 用户友好界面 简洁直观的界面:确保系统界面清晰,…...
FPGA-Verilog-Vivado-软件使用
这里写目录标题 1 软件配置2 FPGA-7000使用2.1 运行启动方式 1 软件配置 编辑器绑定为Vscode,粘贴VS code运行文件的目录,后缀参数保持不变: 如: D:/Users/xdwu/AppData/Local/Programs/Microsoft VS Code/Code.exe [file name]…...
Ambari Hive 创建函数无权限
作者:櫰木 1、创建udf函数 参考文档:https://blog.csdn.net/helloxiaozhe/article/details/102498567 如果已经编写好,请使用自己的。如果没有请参考以上链接进行udf函数编写。 2、创建函数遇到的问题 由于集群开启了kerberos࿰…...
ARM GEC6818 LCD绘图 实心圆 三角形 五角星 任意区域矩形以及旗帜
要在ARM上实现LCD绘图,可以按照以下步骤进行: 硬件初始化:初始化LCD控制器和相关引脚,配置时钟、分辨率和颜色深度等。 内存映射:将LCD显示区域映射到ARM的内存地址空间中,可以通过ARM的内存映射机制来实现…...
Sentinel-1 Level 1数据处理的详细算法定义(三)
《Sentinel-1 Level 1数据处理的详细算法定义》文档定义和描述了Sentinel-1实现的Level 1处理算法和方程,以便生成Level 1产品。这些算法适用于Sentinel-1的Stripmap、Interferometric Wide-swath (IW)、Extra-wide-swath (EW)和Wave模式。 今天介绍的内容如下&…...
一款永久免费的内网穿透工具——巴比达
近期,一款名为巴比达的内网穿透工具凭借其永久免费的特性,以及卓越的性能与安全性,引起了我的关注。本文将深入探讨巴比达如何通过其独创的技术方案,达到企业级数据通信要求。 WanGooe Tunnel协议 首先,巴比达的核心竞…...
翻译|解开LLMs的神秘面纱:他们怎么能做没有受过训练的事情?
大语言模型(LLMs)通过将深度学习技术与强大的计算资源结合起来,正在彻底改变我们与软件互动的方式。 虽然这项技术令人兴奋,但许多人也担忧LLMs可能生成虚假的、过时的或有问题的信息,他们有时甚至会产生令人信服的幻…...
代码随想录-DAY⑦-字符串——leetcode 344 | 541 | 151
344 思路 没啥好说的, 双指针头尾交换, 相遇结束。 时间复杂度:O(n) 空间复杂度:O(1) 代码 class Solution { public:void reverseString(vector<char>& s) {int left0, rights.size()-1;while(left<right){swa…...
JavaScript(7)——数组
JavaScript中数组的用法与Java差不多,但还是有一些区别 声明数组 语法: let 数组名 [数据1,数据2,数据...] let arr new Array(数据1,数据2,...数据n) 添加数据 数组.push()方法将一个或多个元素添加到数组末尾,并返回该数组新长度 <script>…...
Spark RDD优化
Spark RDD优化 一、分区优化二、持久化优化三、依赖优化四、共享变量优化五、提交模式与运行模式优化六、其他优化 一、分区优化 分区数调整:RDD的分区数可以通过repartition和coalesce方法进行调整。合理的分区数可以提高并行度,但过多的分区会增加管…...
Nanbeige 4.1-3B入门必看:PLAYER/NANBEIGE双角色气泡CSS定位原理
Nanbeige 4.1-3B入门必看:PLAYER/NANBEIGE双角色气泡CSS定位原理 1. 项目背景与设计理念 Nanbeige 4.1-3B是一款融合了复古游戏美学与现代AI技术的对话前端界面。这套系统最显著的特点是将传统AI对话界面转化为JRPG风格的冒险体验,通过精心设计的视觉元…...
动态图神经网络实战:用DySAT和自注意力机制搞定社交网络用户行为预测
动态图神经网络实战:用DySAT和自注意力机制搞定社交网络用户行为预测 社交网络中的用户行为预测一直是数据分析领域的核心挑战。传统静态图模型难以捕捉用户关系的动态演变,而基于时间序列的方法又无法有效建模复杂的网络结构。本文将深入解析如何利用动…...
Xilinx GT IP位置约束优化策略与实战技巧
1. Xilinx GT IP位置约束的核心逻辑 在FPGA设计中,GT(Gigabit Transceiver)IP核的位置约束一直是硬件工程师的痛点。很多新手会直接禁用IP自动生成的XDC文件,这其实是个典型的错误操作。Xilinx官方推荐的做法是通过优先级覆盖机制…...
XInference:解锁多模态模型推理的高效部署与实践
1. 为什么需要XInference? 在AI模型爆炸式增长的今天,企业面临三大核心痛点:模型部署复杂、硬件适配困难、多模态支持不足。传统部署流程往往需要手动处理依赖库、硬件驱动、模型转换等繁琐步骤,一个BERT模型的部署可能就要耗费工…...
结合DeOldify与3D建模软件:为黑白材质贴图智能赋予色彩
结合DeOldify与3D建模软件:为黑白材质贴图智能赋予色彩 你有没有遇到过这样的场景?在制作一个复古风格的游戏场景,或者还原某个历史时期的影视特效时,手头只有一堆老旧的黑白参考图,或者为了追求特定艺术效果…...
Uboot Flash支持全解析:从MX25L51245G到S25FL512S的配置指南
Uboot Flash支持全解析:从MX25L51245G到S25FL512S的配置指南 在嵌入式系统开发中,Flash存储器的正确配置是系统稳定运行的基础。对于使用MT7628等嵌入式处理器的开发者来说,理解Uboot中Flash支持的实现原理至关重要。本文将深入解析不同型号F…...
【软件工程】从伪码到蓝图:PDL语言如何重塑软件设计规约
1. 当伪码遇上工程:PDL语言的诞生背景 我第一次接触PDL语言是在2013年参与银行核心系统重构时。当时团队里资深架构师扔给我一份满是英文关键词夹杂中文注释的文档,看着像代码却又不能直接执行。他告诉我:"这是用PDL写的设计规约&#x…...
CNN架构优化提升LingBot-Depth深度估计精度的研究
CNN架构优化提升LingBot-Depth深度估计精度的研究 1. 引言 深度估计是计算机视觉领域的核心任务之一,它让机器能够"看见"三维世界。但在实际应用中,我们常常遇到这样的问题:透明物体、反光表面、复杂纹理区域等场景下,…...
C#源码解析:欧姆龙NX1P通讯DEMO的CIP通讯实现
C#编写CIP通讯源码,欧姆龙NX1P通讯DEMO一、概述 本代码是基于C#语言开发的CIP(Common Industrial Protocol)通讯Demo程序,专门用于与欧姆龙NX1P2系列PLC进行工业通讯交互。程序采用.NET Framework 4.8框架开发,通过TCP…...
K8S篇之什么是金丝雀发布? 在实际生产中如何应用?
一、什么是金丝雀发布?(一句话讲懂) 金丝雀发布 = 先给一小部分用户上新版本,观察没问题,再逐步全量发布。 为什么叫 “金丝雀”? 以前煤矿工人带金丝雀下井: 有毒气 → 金丝雀先出事 → 工人赶紧撤离。 放到发布里就是: 先放 5% 流量给新版本 监控错误率、响应时间、…...
