【C语言】指针与数组的例题详解:深入分析与高级用法


在这里插入图片描述

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳]
本文专栏: C语言

文章目录

  • 💯前言
  • 💯题目一
    • 详细分析与解答
      • 代码逐步解析
  • 💯进一步优化和拓展
    • 1. 指针与数组的关系
    • 2. 指针运算的注意事项
    • 3. 常见的错误和陷阱
    • 4. 拓展:指针操作的应用场景
    • 5. 指针与内存地址的深入理解
  • 💯题目二
    • 数组传递给函数时的特性
    • 数组退化为指针
    • 指针遍历字符串
    • 输出结果
    • 数组与指针的区别
    • 指针与函数参数的灵活性
  • 💯小结


在这里插入图片描述


💯前言

  • C语言作为一门经典的编程语言,以其高效灵活接近底层硬件的特点,广泛应用于嵌入式开发操作系统内核以及高性能计算等领域。然而,C语言的灵活性也带来了学习过程中的诸多挑战,特别是在指针与数组内存管理以及字符串处理等核心概念的掌握上。
    本文通过对经典题目的逐步解析,深入探讨 C语言关键特性,并结合代码实例详细讲解其底层原理实际应用。希望通过这样的方式,帮助读者更全面地理解 C语言的强大之处,从而在编程中更加得心应手
    C语言
    在这里插入图片描述

💯题目一

在这里插入图片描述
题目描述:

如下程序段的输出结果为:

unsigned long pulArray[] = {6, 7, 8, 9, 10};
unsigned long *pulPtr;
pulPtr = pulArray;
*(pulPtr + 3) += 3;
printf("%d, %d\n", *pulPtr, *(pulPtr + 3));

详细分析与解答

在这里插入图片描述
这道题考察的是指针和数组的操作,特别是指针的算术运算以及对数组元素的修改。接下来,我们逐步分析程序的执行过程,以得出正确的答案。


代码逐步解析

在这里插入图片描述
首先,我们逐行解释代码,并深入理解每一步的执行过程。

unsigned long pulArray[] = {6, 7, 8, 9, 10};

这一行定义了一个 unsigned long 类型的数组 pulArray,它包含 5 个元素,分别是 {6, 7, 8, 9, 10}。数组在内存中会被分配一块连续的存储空间,每个元素占据一个存储单元,内存地址按元素依次递增。

unsigned long *pulPtr;

这里定义了一个 unsigned long 类型的指针 pulPtr,它将用于指向数组中的元素。

pulPtr = pulArray;

这行代码将 pulPtr 指向数组 pulArray 的首地址。也就是说,pulPtr 现在指向 pulArray[0],即值为 6 的位置。

*(pulPtr + 3) += 3;

这一行代码对数组中的一个元素进行了修改。首先,我们来看 pulPtr + 3

  • pulPtr 是指向数组第一个元素的指针。
  • pulPtr + 3 表示将指针偏移到数组中第 4 个元素的地址(注意数组的索引是从 0 开始的)。

通过 *(pulPtr + 3) 取出该地址所指向的值,也就是数组的第 4 个元素 9。然后 += 3 操作将该值增加 3,变为 12。因此,数组 pulArray 现在的值变成了 {6, 7, 8, 12, 10}

printf("%d, %d\n", *pulPtr, *(pulPtr + 3));
  • *pulPtr 取出指针 pulPtr 所指向的值,即数组的第一个元素 6
  • *(pulPtr + 3) 取出指向第 4 个元素的值,现在这个值已经被修改为 12

因此,printf 最终输出的结果是:

6, 12

💯进一步优化和拓展

在这里插入图片描述
为了更好地理解这个题目,我们来探讨一些与此相关的重要概念,包括指针运算、数组与指针的关系,以及 C 语言中的一些常见错误和陷阱。


1. 指针与数组的关系

在这里插入图片描述
在 C 语言中,数组名在大多数情况下会退化为指向其首元素的指针。这意味着 pulArray 可以被看作是指向 pulArray[0] 的地址。因此,以下代码:

pulPtr = pulArray;

可以理解为让指针 pulPtr 指向数组的起始地址。此后,通过指针的偏移量我们可以访问数组中的其他元素,例如:

  • pulPtr + 1 指向 pulArray[1]
  • pulPtr + 3 指向 pulArray[3],即值为 9 的位置

2. 指针运算的注意事项

指针的运算是基于指针所指向的数据类型大小的。例如,对于一个 unsigned long 类型的指针,每次加 1 实际上会增加 sizeof(unsigned long) 个字节,而不是简单地增加 1 个字节。这种特性在访问数组元素时尤为重要,因为它能保证指针准确地指向下一个元素,而不是指向任意的中间位置。

在这里插入图片描述


3. 常见的错误和陷阱

  • 数组越界访问:在使用指针操作数组时,如果偏移量超出了数组的边界,就会发生越界访问,导致未定义行为。这种错误在 C 语言中非常常见且很难调试。
  • 未初始化指针:如果指针没有正确初始化(例如没有指向有效的内存地址),对其解引用会导致严重的错误,例如段错误(Segmentation Fault)。在这道题中,指针 pulPtr 在赋值之前指向了有效的数组,因此没有这个问题。

在这里插入图片描述


4. 拓展:指针操作的应用场景

指针的运算和数组的结合在许多场景中都非常有用,例如:

  • 遍历数组:通过指针偏移量来遍历数组中的元素,通常比使用数组索引更加高效,尤其是在嵌入式系统中,由于资源有限,高效地访问数据显得尤为重要。
  • 动态内存管理:在堆上分配内存时(例如使用 malloc),返回的是指向已分配内存的指针,之后对这块内存的操作大多需要通过指针进行。
  • 字符处理与字符串操作:指针在字符串处理方面非常高效,通过指针可以直接访问字符数组中的每一个字符,进行遍历、修改等操作。
    在这里插入图片描述

5. 指针与内存地址的深入理解

指针不仅仅是一个变量,它实际上是一个存储内存地址的变量。理解指针与内存地址之间的关系,对于掌握指针的高级用法至关重要。例如,指针的偏移量取决于它所指向的数据类型大小,这使得 C 语言中的指针非常灵活且强大。在涉及复杂数据结构(如链表、树结构)时,指针的使用必不可少,可以有效地管理和操纵动态数据。
在这里插入图片描述


💯题目二

在另一段代码中,定义了一个自定义的字符串长度函数 my_strlen,其目的是计算一个字符串的长度。

代码如下:

int my_strlen(char* arr) {int count = 0;while (*arr != '\0') {count++;arr++;}return count;
}int main3() {char arr[] = "今天是2024年11月26日";printf("%d", my_strlen(arr));return 0;
}

在这里插入图片描述


数组传递给函数时的特性

main3() 函数中,定义了一个字符数组 arr,并将其传递给了 my_strlen 函数。这个过程中,我们并不需要显式定义一个指针,原因在于 C 语言中的数组退化特性。
在这里插入图片描述


数组退化为指针

  • 在调用 my_strlen(arr) 时,数组名 arr 会自动退化为一个指向其首元素的指针。也就是说,my_strlen 实际上接收的是 arr 的首地址(一个 char* 类型的指针),这使得 my_strlen 可以遍历整个字符串直到遇到字符串的终止符 \0
  • 这种退化机制在 C 语言中被广泛使用,使得函数可以方便地操作数组数据,而不需要将整个数组拷贝传递,这样也提高了效率。
  • 此外,数组退化为指针的特性在很多场景下可以提高代码的通用性和复用性,因为指针可以指向不同的数组,从而实现对不同数据的操作。
    在这里插入图片描述

指针遍历字符串

my_strlen 函数中,使用指针 arr 来遍历整个字符串:

while (*arr != '\0') {count++;arr++;
}

这里,*arr 取出当前字符的值,并判断是否为终止符 \0。如果不是,就将 arr 向后移动一个字符位置,并增加计数器 count。这种方式让函数能够有效地计算出字符串的长度,直到遇到字符串的结束符。
在这里插入图片描述


输出结果

在这里插入图片描述

main3() 中,字符串为 "今天是2024年11月26日"my_strlen(arr) 返回 20,即字符串的长度。
在这里插入图片描述


数组与指针的区别

  • 数组是连续内存块arr 是一块连续的内存空间,包含所有字符。
  • 指针是地址变量:在传递给函数时,arr 自动退化为指针,这个指针指向数组的首元素。通过指针操作,可以灵活地遍历或操作数组中的每一个元素。
  • 指针的灵活性:指针可以指向任意内存地址(只要是有效的内存),这使得它在处理动态数据结构(如链表、树等)时特别有用。相比之下,数组的内存是固定的,数组名只能指向这一块特定的内存。
    在这里插入图片描述

指针与函数参数的灵活性

在许多情况下,使用指针来传递参数,可以更高效地操作数据。特别是在处理大型数据结构时,直接传递数组的首地址比拷贝整个数组更节省内存和时间。此外,通过指针,我们可以修改数组中的内容,而不仅仅是读取它们的值,这也是指针传递的一个重要优势。
在这里插入图片描述


💯小结

  • 在这里插入图片描述
    在第一段代码中,定义指针 pulPtr 让我们可以通过指针偏移来访问和修改数组中的元素。这种操作在 C 语言中非常灵活和常用

  • 在第二段代码中,数组 arr 被传递给 my_strlen 函数,数组名自动退化为指针,从而允许函数通过指针遍历整个字符串。这种机制使得字符串处理非常高效

  • 指针与数组C 语言中是非常重要且强大的工具,能够有效地进行内存操作数据处理。在使用时需要小心指针的边界和初始化问题,以避免常见的错误

  • 指针的灵活性使得它在许多场景下成为不可替代的工具,尤其是在涉及复杂数据结构动态内存管理时。


在这里插入图片描述


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

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

相关文章

Windows修复SSL/TLS协议信息泄露漏洞(CVE-2016-2183)

打开服务器,运行gpedit.msc,打开“本地组策略编辑器”,依次打开计算机配置-管理模板-网络-SSL配置设置。 打开“SSL密码套件顺序”,更改为已启用,并修改套件算法,去掉TLS1.1版本算法。 TLS_ECDHE_ECDSA_WIT…

go-zero(八) 中间件的使用

go-zero 中间件 一、中间件介绍 中间件(Middleware)是一个在请求和响应处理之间插入的程序或者函数,它可以用来处理、修改或者监控 HTTP 请求和响应的各个方面。 1.中间件的核心概念 请求拦截:中间件能够在请求到达目标处理器之…

vscode ctrl+/注释不了css

方式一.全部禁用插件排查问题. 方式二.打开首选项的json文件,注释掉setting.json,排查是哪一行配置有问题. 我的最终问题:需要将 "*.vue": "vue",改成"*.vue": "html", "files.associations": { // "*.vue": &qu…

使用 Jina Embeddings v2 在 Elasticsearch 中进行后期分块

作者:来自 Elastic Gustavo Llermaly 在 Elasticsearch 中使用 Jina Embeddings v2 模型并探索长上下文嵌入模型的优缺点。 在本文中,我们将配置和使用 jina-embeddings-v2,这是第一个开源 8K 上下文长度嵌入模型,首先使用 semant…

电视网络机顶盒恢复出厂超级密码大全汇总

部分电视机顶盒在按遥控器设置键打开设置时,会弹出设置密码弹窗,需输入密码才能操作其中内容。 如下图所示: 部分电视机顶盒在选择恢复出厂设置时,会出现设置密码弹窗,只有输入操作密码后才能进行恢复出厂设置的操作。…

cmake原理

CMake原理与快速入门 CMake是一个跨平台的构建(build)工具,完成代码编译、链接、打包过程。在开发AI应用平台时,由于开发的平台是在边缘设备运行的,而边缘设备的算力不高,所以对平台的效率要求比较高&…

SFTP全解析:深入了解组件功能与适用场景

文章目录 一、组件功能二、适用场景三、SFTP优势四、SFTP原理五.SFTP与同类产品对比六、部署方案1.裸金属部署2.k8s容器化部署 七、高可用方案八、监控方案九、常见问题及解决方法 一、组件功能 安全文件传输协议SFTP(SSH File Transfer Protocol)是文件传输协议(F…

java——Spring MVC的工作流程

Spring MVC的工作流程是基于模型-视图-控制器(MVC)设计模式的一个典型实现,以下是其主要工作流程步骤: 客户端请求提交: 用户通过浏览器向服务器发送请求,该请求首先到达Spring MVC的前端控制器DispatcherS…

Mutex::Autolock 和 std::lock_guard 的区别

Mutex::Autolock 和 std::lock_guard 都是 C 中用于管理互斥锁(mutex)的一种方式,它们的目标是自动获取和释放锁,避免手动管理锁的复杂性,从而防止死锁和遗漏解锁等问题。尽管它们有相似的功能,但二者也存在…

<项目代码>YOLOv8 红绿灯识别<目标检测>

YOLOv8是一种单阶段(one-stage)检测算法,它将目标检测问题转化为一个回归问题,能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法(如Faster R-CNN),YOLOv8具有更高的…

mac下安装Ollama + Open WebUI + Llama3.1

本文介绍mac下安装Ollama Open WebUI Llama3.1 8b具体步骤。 目录 推荐配置Ollama Open WebUI Llama3.1简介安装Ollama安装Open WebUI 推荐配置 m1以上芯片,16g内存,20g以上硬盘空间 Ollama Open WebUI Llama3.1简介 Ollama: 下载,管理…

Linux 无图形界面磁盘空间排查与优化实践20241127

Linux 无图形界面磁盘空间排查与优化实践 引言:磁盘空间问题的痛点与挑战 🔍 常见问题 当系统磁盘空间超过 90% 时,不仅可能导致性能下降,还可能让关键操作无法正常完成。这种情况下,如何高效且精准地排查磁盘占用来…

【AI】JetsonNano启动时报错:soctherm OC ALARM

1、问题描述 将JetsonNano烧写SD卡镜像为Ubuntu20.04后,启动时报错:soctherm OC ALARM,启动失败;然后系统一直重启 2、原因分析 “soctherm OC ALARM”是检测到系统温度超过安全阈值时发出的过热警告。 “soctherm”代表系统…

SycoTec 4060 ER-S德国高精密主轴电机如何支持模具的自动化加工?

SycoTec 4060 ER-S高速电主轴在模具自动化加工中的支持体现在以下几个关键方面: 1.高精度与稳定性:SycoTec 4060 ER-S锥面跳动小于1微米,确保了加工过程中的极高精度,这对于模具的复杂几何形状和严格公差要求至关重要。高精度加工…

d3-contour 生成等高线图

D3.js 是一个强大的 JavaScript 库,用于创建动态、交互式数据可视化。d3-contour 是 D3.js 的一个扩展模块,用于生成等高线图(contour plots)。 属性和方法 属性 x: 一个函数,用于从数据点中提取 x 坐标。y: 一个函…

Docker 部署 MongoDB

🚀 作者主页: 有来技术 🔥 开源项目: youlai-mall 🍃 vue3-element-admin 🍃 youlai-boot 🍃 vue-uniapp-template 🌺 仓库主页: GitCode💫 Gitee &#x1f…

鸿蒙MVVM模式介绍与使用

文章目录 鸿蒙MVVM模式介绍与使用背景MVVM模式介绍相关装饰器介绍State状态变量Prop、Link的作用 MVVM架构模式的实现以及相关装饰器的使用具体实现效果 总结 鸿蒙MVVM模式介绍与使用 背景 最近在学习鸿蒙开发,想到了以前写安卓移动端应用时经常会用到的MVVM架构模式,就想着能…

解决SpringBoot连接Websocket报:请求路径 404 No static resource websocket.

问题发现 最近在工作中用到了WebSocket进行前后端的消息通信,后端代码编写完后,测试一下是否连接成功,发现报No static resource websocket.,看这个错貌似将接口变成了静态资源来访问了,第一时间觉得是端点没有注册成…

【RISC-V CPU 专栏 -- 香山处理器介绍】

文章目录 RISC-V 香山处理器介绍雁栖湖处理器南湖处理器RISC-V 香山处理器介绍 相信很多小伙伴对于“香山”都不陌生,它是一款开源RISC-V处理器核,香山的每一代架构,都是采用了湖的名字,第一代架构被命名为雁栖湖,第二代架构则叫做 “南湖”。 “雁栖湖”这款处理器的 R…

网络安全原理与技术思考题/简答题

作业1(第1章、第2章、第8章) 1. 网络安全的基本属性有哪些?简单解释每个基本属性的含义。网络安全的扩展属性包括哪些? 基本属性: 1.机密性(Confidentiality): 含义:确保信息不被未授权的用户…