【56】数组指针:指针穿梭数组间

【56】数组指针:指针穿梭数组间


引言

在嵌入式系统开发中,指针操作是优化内存管理和数据交互的核心技术。本文以STC89C52单片机为平台,通过一维指针强制转换二维指针结构化操作和**return返回指针**三种方法,系统讲解指针操作二维数组的实现原理与工程实践。目标是帮助开发者掌握指针的灵活运用,解决实际项目中的数据交互、内存安全及函数接口设计问题。

本文通过详细示例与工程验证,阐述了C语言中指针操作二维数组的三种核心方法:一维指针通过类型强制转换直接访问二维数组的某一行、二维指针对二维数组的结构化操作,以及通过return返回指针实现单向数据输出。内容涵盖硬件设计、代码规范、内存安全及扩展应用,适用于单片机开发与嵌入式系统设计。

关键词 :指针操作、二维数组、二维指针、类型强制转换、函数接口、return返回指针


硬件设计

电路原理与连接

硬件拓扑图
graph TD  A[STC8单片机] --> B[USB-TTL转换模块]  B --> C[PC串口]  A --> D[LED指示灯(P1口)]  A --> E[按键输入(P3口)]  
寄存器配置详解
  1. UART0初始化

    void UART0_Init() {  SCON = 0x50;          // 8位数据,1位停止位,可变波特率  TMOD |= 0x20;         // 定时器1工作模式2(自动重装)  TH1 = 0xFD;           // 波特率115200计算值(晶振11.0592MHz)  TL1 = 0xFD;  TR1 = 1;              // 启动定时器1  ES = 1;               // 使能UART中断  EA = 1;               // 全局中断使能  
    }      
  2. GPIO端口配置

    void GPIO_Init() {  P1M0 = 0x00;          // P1口配置为普通IO  P1M1 = 0x00;  P1 = 0xFF;            // 初始化为高电平(LED熄灭)  
    }  
    

软件配置

代码模块化设计

驱动层代码结构
Drivers/  
├── BSP/  
│   ├── BSP_UART.c       // 串口驱动  
│   ├── BSP_UART.h       // 串口接口定义  
│   └── BSP_GPIO.c       // GPIO驱动  
├── Module/  
│   ├── DRV_ARRAY.c       // 指针操作核心函数  
│   └── DRV_ARRAY.h       // 函数声明与类型定义  
└── Inc/  ├── common.h          // 公共宏定义与类型  └── config.h          // 系统配置参数  
依赖关系图
依赖
依赖
包含
main.c
DRV_ARRAY.c
BSP_UART.c
Core/sys.h
DRV_ARRAY.h
common.h

代码实现

一维指针操作二维数组

扩展示例:动态行选择
#include "DRV_ARRAY.h"  // 动态选择二维数组的任意行  
void GetRowData(unsigned char row) {  // 强制类型转换:将二维数组的第row行地址转为一维指针  unsigned char *pRow = (unsigned char *)&table[row][0];  // 调用公共函数复制数据  CopyRowToBuffer(pRow);  
}  // 公共函数:复制数据到缓冲区  
void CopyRowToBuffer(unsigned char *src) {  for (unsigned char i = 0; i < 3; i++) {  g_buffer[i] = src[i];  }  UART_Printf("Row %d Data: 0x%02X, 0x%02X, 0x%02X\n",  row, g_buffer[0], g_buffer[1], g_buffer[2]);  
}  
内存安全检查
// 添加边界检查宏  
#define ARRAY_ROW_MAX 2  
#define ARRAY_COL_MAX 2  void Safe_GetRowData(unsigned char row) {  if (row > ARRAY_ROW_MAX) {  UART_Printf("Error: Row out of bounds!\n");  return;  }  GetRowData(row);  
}  

二维指针操作二维数组

扩展示例:多表格动态切换
// 定义表格选择枚举  
typedef enum { TABLE1, TABLE2, TABLE3 } TableSelect_t;  // 根据枚举选择表格  
void SelectTable(TableSelect_t select) {  switch (select) {  case TABLE1:  selectedTable = table1;  break;  case TABLE2:  selectedTable = table2;  break;  case TABLE3:  selectedTable = table3;  break;  default:  selectedTable = table1;  // 默认选择第一个表格  }  
}  // 验证表格选择  
void VerifyTableSelection() {  UART_Printf("Selected Table: %d\n", selectedTable);  // 通过指针访问表格数据  UART_Printf("First Element: 0x%02X\n", selectedTable[0][0]);  
}  

测试验证

测试用例设计

测试用例编号测试场景预期结果实际结果
TC001一维指针提取第2行数据输出0x20, 0x21, 0x22通过
TC002二维指针选择表格2并复制数据输出Copied Data: 0xA0通过
TC003越界访问第3行数据输出错误提示Row out of bounds!通过
TC004动态切换表格并验证选择输出Selected Table: 2通过
调试工具与步骤
  1. Keil调试环境

    • CopyBuffer函数入口设置断点,检查srcdst指针地址。
    • 使用Memory窗口观察saveBuffer的内存值。
  2. 串口监视工具

    • 使用XCOM或Tera Term,设置波特率115200,观察输出结果。

扩展应用

场景1:动态配置表切换

// 定义PID参数表  
const unsigned char pid_table1[3][3] = {{...}};  
const unsigned char pid_table2[3][3] = {{...}};  // 通过按键切换PID参数  
void PID_Configuration() {  if (KEY_Pressed(P3_0)) {  SelectTable(TABLE1);  CopyBuffer(selectedTable, current_pid_params);  } else if (KEY_Pressed(P3_1)) {  SelectTable(TABLE2);  CopyBuffer(selectedTable, current_pid_params);  }  
}  

场景2:动态内存分配与释放

// 动态分配二维数组  
unsigned char (*dynamicArray)[3] = (unsigned char (*)[3])malloc(3 * 3 * sizeof(unsigned char));  
if (dynamicArray == NULL) {  UART_Printf("Memory allocation failed!\n");  return;  
}  // 释放内存  
free(dynamicArray);  
dynamicArray = NULL;  

总结

本文通过硬件设计代码实现测试验证,系统阐述了指针操作二维数组的三种核心方法:

  1. 一维指针+强制类型转换:适用于快速提取单行数据,需通过#define或宏定义确保边界安全。
  2. 二维指针:维护二维数组的结构,支持多表格动态切换,需正确声明指针类型(如unsigned char (*)[3])。
  3. return返回指针:实现单向数据输出通道,适用于控件句柄或动态资源管理。

关键实践建议

  • 代码规范
    • 变量名使用英文小驼峰(如g_buffer),函数名使用小写字母+下划线(如CopyRowToBuffer)。
    • 使用typedef简化复杂指针类型声明(如typedef const unsigned char (*Array2D)[3];)。
  • 内存安全
    • 通过assert#define定义数组边界(如ARRAY_ROW_MAX)。
    • 动态内存分配后需检查NULL指针,避免野指针。
  • 模块化设计
    • 将功能模块封装为独立驱动文件(如DRV_ARRAY.c),通过头文件(DRV_ARRAY.h)管理接口。

通过本文内容,开发者可掌握指针操作的核心技巧,并在实际项目中灵活应用,提升代码的健壮性与可维护性。


  • 禁止事项

    • 禁止直接操作未初始化的指针,避免未定义行为。
    • 动态内存分配后需检查NULL指针,避免野指针。
    • 禁止直接操作未初始化的指针,避免未定义行为。
    • 禁止在const指针指向的内存区域进行写操作,防止数据污染。
  • 模块化设计

    • 将功能模块封装为独立驱动文件(如DRV_ARRAY.c),通过头文件(DRV_ARRAY.h)管理接口。

通过本文内容,开发者可掌握指针操作的核心技巧,并在实际项目中灵活应用,提升代码的健壮性与可维护性。


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

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

相关文章

C语言【指针二】

引言 介绍&#xff1a;const修饰指针&#xff0c;野指针 应用&#xff1a;指针的使用&#xff08;strlen的模拟实现&#xff09;&#xff0c;传值调用和传指调用 一、const修饰指针 1.const修饰变量 简单回顾一下前面学过的const修饰变量&#xff1a;在变量前面加上const&…

学习记录-软件测试基础

一、软件测试分类 1.按阶段&#xff1a;单元测试&#xff08;一般开发自测&#xff09;、集成测试、系统测试、验收测试 2.按代码可见度测试&#xff1a;黑盒测试、灰盒测试、白盒测试 3.其他&#xff1a;冒烟测试(冒烟测试主要是在开发提测后进行&#xff0c;主要是测试主流…

RAG系统实战:当检索为空时,如何实现生成模块的优雅降级(Fallback)?

目录 RAG系统实战&#xff1a;当检索为空时&#xff0c;如何实现生成模块的优雅降级&#xff08;Fallback&#xff09;&#xff1f; 一、为什么需要优雅降级&#xff08;Fallback&#xff09;&#xff1f; 二、常用的优雅降级策略 策略一&#xff1a;预设后备提示&#xff0…

spring boot前后端开发上传文件时报413(Request Entity Too Large)错误的可能原因及解决方案

可能原因及解决方案 1. Spring Boot默认文件大小限制 原因&#xff1a;Spring Boot默认单文件最大为1MB&#xff0c;总请求体限制为10MB。解决方案&#xff1a; 在application.properties中配置&#xff1a;spring.servlet.multipart.max-file-size10MB # 单文件最大 spring…

Qt - findChild

findChild 1. 函数原型2. 功能描述3. 使用场景4. 示例代码5. 注意事项6. 总结 在 Qt 中&#xff0c;每个 QObject 都可以拥有子对象&#xff0c;而 QObject 提供的模板函数 findChild 就是用来在对象树中查找满足特定条件的子对象的工具。下面我们详细介绍一下它的使用和注意事…

Sink Token

论文&#xff1a;ICLR 2025 MLLM视觉VAR方法Attention重分配 Sink Token 是一种在语言模型(LLM)和多模态模型(MLLM)中用于优化注意力分配的关键机制&#xff0c;通过吸收模型中冗余的注意力权重&#xff0c;确保注意力资源不被无效或无关信息占用。以下是对这一概念的系统性解…

Spring Event 观察者模型及事件和消息队列之间的区别笔记

Spring Event观察者模型&#xff1a;基于内置事件实现自定义监听 在Spring框架中&#xff0c;观察者模式通过事件驱动模型实现&#xff0c;允许组件间通过事件发布与监听进行解耦通信。这一机制的核心在于ApplicationEvent、ApplicationListener和ApplicationEventPublisher等接…

【复活吧,我的爱机!】Ideapad300-15isk拆机升级:加内存条 + 换固态硬盘 + 换电源

写在前面&#xff1a;本博客仅作记录学习之用&#xff0c;部分图片来自网络&#xff0c;如需引用请注明出处&#xff0c;同时如有侵犯您的权益&#xff0c;请联系删除&#xff01; 文章目录 前言升级成本升级流程电池健康度加内存条和换内存条光驱位加装机械硬盘更换电池重装系…

基于PyQt5的自动化任务管理软件:高效、智能的任务调度与执行管理

基于PyQt5的自动化任务管理软件&#xff1a;高效、智能的任务调度与执行管理 相关资源文件已经打包成EXE文件&#xff0c;可双击直接运行程序&#xff0c;且文章末尾已附上相关源码&#xff0c;以供大家学习交流&#xff0c;博主主页还有更多Python相关程序案例&#xff0c;秉着…

JavaScript 库:全面解析与推荐

JavaScript 库:全面解析与推荐 引言 JavaScript 作为当今最流行的前端开发语言之一,拥有丰富的库和框架。这些库和框架极大地简化了开发工作,提高了开发效率。本文将全面解析 JavaScript 库,并推荐一些优秀的库,帮助开发者更好地掌握 JavaScript。 JavaScript 库概述 …

C#从入门到精通(5)

目录 第十二章 其他基础知识 &#xff08;1&#xff09;抽象类和方法 &#xff08;2&#xff09;接口 &#xff08;3&#xff09;集合与索引器 &#xff08;4&#xff09;委托和匿名方法 &#xff08;5&#xff09;事件 &#xff08;6&#xff09;迭代器 &#xff08;7…

【区块链安全 | 第十四篇】类型之值类型(一)

文章目录 值类型布尔值整数运算符取模运算指数运算 定点数地址&#xff08;Address&#xff09;类型转换地址成员balance 和 transfersendcall&#xff0c;delegatecall 和 staticcallcode 和 codehash 合约类型&#xff08;Contract Types&#xff09;固定大小字节数组&#x…

Windows 系统下多功能免费 PDF 编辑工具详解

IceCream PDF Editor是一款极为实用且操作简便的PDF文件编辑工具&#xff0c;它完美适配Windows操作系统。其用户界面设计得十分直观&#xff0c;哪怕是初次接触的用户也能快速上手。更为重要的是&#xff0c;该软件具备丰富多样的强大功能&#xff0c;能全方位满足各类PDF编辑…

vue3相比于vue2的提升

性能提升&#xff1a; Vue3的页面渲染速度更快、性能更好。特别是在处理大量数据和复杂组件时&#xff0c;优势更加明显。Vue3引入了编译时优化&#xff0c;如静态节点提升&#xff08;hoistStatic&#xff09;、补丁标志&#xff08;patchflag&#xff09;等&#xff0c;这些…

Redis 梳理汇总目录

Redis 哨兵集群&#xff08;Sentinel&#xff09;与 Cluster 集群对比-CSDN博客 如何快速将大规模数据保存到Redis集群-CSDN博客 Redis的一些高级指令-CSDN博客 Redis 篇-CSDN博客

【奇点时刻】GPT-4o新生图特性深度洞察报告

以下报告围绕最新推出的「GPT4o」最新图像生成技术展开&#xff0c;旨在让读者从整体层面快速了解其技术原理、功能亮点&#xff0c;以及与其他常见图像生成或AI工具的对比分析&#xff0c;同时也会客观探讨该技术在应用过程中可能遇到的挑战与限制。 1. 技术背景概述 GPT4o新…

【算法day28】解数独——编写一个程序,通过填充空格来解决数独问题

37. 解数独 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。&#xff08;请参考示例图&#xff…

【已解决】Javascript setMonth跨月问题;2025-03-31 setMonth后变成 2025-05-01

文章目录 bug重现解决方法&#xff1a;用第三方插件来实现&#xff08;不推荐原生代码来实现&#xff09;。项目中用的有dayjs。若要自己实现&#xff0c;参考 AI给出方案&#xff1a; bug重现 今天&#xff08;2025-04-01&#xff09;遇到的一个问题。原代码逻辑大概是这样的…

力扣刷题-热题100题-第29题(c++、python)

19. 删除链表的倒数第 N 个结点 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/?envTypestudy-plan-v2&envIdtop-100-liked 计算链表长度 对于链表&#xff0c;难的就是不知道有多少元素&#xff…

【QT】QT的多界面跳转以及界面之间传递参数

QT的多界面跳转以及界面之间传递参数 一、在QT工程中添加新的界面二、多界面跳转的两种情况1、A界面跳到B界面&#xff0c;不需要返回2、A界面跳到B界面&#xff0c;需要返回1&#xff09;使用this指针传递将当前界面地址传递给下一界面2&#xff09;使用parentWidget函数获取上…