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方法进行调整。合理的分区数可以提高并行度,但过多的分区会增加管…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...

[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG
TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码:HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...

《Docker》架构
文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器,docker,镜像,k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...

FFmpeg avformat_open_input函数分析
函数内部的总体流程如下: avformat_open_input 精简后的代码如下: int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...

一些实用的chrome扩展0x01
简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序,无论是测试应用程序、搜寻漏洞还是收集情报,它们都能提升工作流程。 FoxyProxy 代理管理工具,此扩展简化了使用代理(如 Burp…...

负载均衡器》》LVS、Nginx、HAproxy 区别
虚拟主机 先4,后7...

归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...