学习嵌入式第十二天:深入理解指针与一维字符型数组传参 引言指针与数组的紧密联系在嵌入式C语言编程中指针和数组是密不可分的核心概念。第十二天的学习重点聚焦于指针与一维字符型数组的传参机制这是理解字符串处理、内存操作和函数接口设计的关键。掌握这部分内容意味着你能更高效地处理文本数据、优化内存使用并写出更健壮的嵌入式代码。一、 核心概念回顾1.1 什么是指针指针是一个变量其值为另一个变量的内存地址。在32位系统中指针通常占4字节。intnum10;int*pnum;// p 是指向整型变量 num 的指针1.2 什么是一维字符型数组一维字符型数组本质上是连续的内存空间用于存储一串字符字符串。在C语言中字符串以空字符\0结尾。charstr1[20]Hello, Embedded!;// 显式指定大小charstr2[]Hello, World!;// 编译器自动计算大小二、 数组名作为指针这是理解传参的基石在大多数表达式中数组名会被转换为指向其首元素的指针。chararr[10]test;// arr 的类型是 char[10]// 但在值上下文中如函数调用arr 等价于 arr[0]类型是 char*这意味着当你将数组名传递给函数时你传递的是数组首元素的地址而不是整个数组的副本。三、 一维字符型数组的传参方式3.1 形式参数声明为指针这是最常用、最直接的方式。函数接收一个指向字符的指针。voidprint_string(char*str){while(*str!\0){putchar(*str);str;}}// 调用charmy_string[]Embedded C;print_string(my_string);// 传递数组名即首地址优点灵活可以处理字符串字面量、数组甚至动态分配的内存。本质传递的是地址函数内通过该地址间接访问原数组内容。3.2 形式参数声明为数组带大小或不带大小这种写法看起来像数组但编译器仍然将其当作指针处理。// 以下三种函数声明是等价的voidfunc1(charstr[]);// 大小可省略voidfunc2(charstr[10]);// 大小会被忽略voidfunc3(char*str);// 明确的指针形式// 实现voidfunc1(charstr[]){// 在函数内部sizeof(str) 得到的是指针的大小如4或8字节而不是数组的大小printf(First char: %c\n,str[0]);// 下标访问依然有效}关键点即使写成char str[10]str在函数内部仍然是一个char*指针。中括号[]的写法更多是为了提高代码的可读性表明期望传入一个数组的起始地址。四、 传参的本质与内存模型理解传参必须结合内存来看。// 主调函数charbuffer[32]Initial Data;modify_string(buffer);// 被调函数voidmodify_string(char*ptr){// ptr 存储了 buffer 数组的首地址 0x2000 1000假设ptr[0]M;// 通过地址 0x2000 1000 修改了 buffer[0] 的内容// *(ptr 5) X; // 等价于 buffer[5] X}内存变化buffer在内存中占据一块连续空间例如地址0x2000 1000到0x2000 101F。调用modify_string(buffer)时将首地址0x2000 1000复制给了形参ptr。函数内通过ptr解引用或下标访问直接操作的是buffer的原始内存。这就是“传址”调用函数内部对数组元素的修改会直接影响主调函数中的原始数组。五、 关键区别sizeof运算符在函数内外使用sizeof获取数组大小时结果天差地别这是最容易出错的地方。voidtest_sizeof(chararr[]){printf(Inside function - sizeof(arr): %zu\n,sizeof(arr));// 输出 4 或 8指针大小printf(Inside function - sizeof(char*): %zu\n,sizeof(char*));// 输出相同}intmain(){charmy_array[100];printf(In main - sizeof(my_array): %zu\n,sizeof(my_array));// 输出 100数组总大小test_sizeof(my_array);return0;}结论在函数内部无法通过形参获得传入数组的原始长度。如果需要长度必须额外传递一个size_t length参数。六、 嵌入式开发中的实践与陷阱6.1 避免缓冲区溢出这是嵌入式安全的重中之重。函数内操作指针时必须确保不越界访问。// 危险假设不知道 dest 的大小voidunsafe_copy(char*dest,constchar*src){while(*src!\0){*dest*src;// 可能写穿 dest 的边界dest;src;}*dest\0;}// 安全做法显式传递目标缓冲区大小voidsafe_copy(char*dest,size_tdest_size,constchar*src){size_ti0;while(idest_size-1src[i]!\0){// 预留一个位置给 \0dest[i]src[i];i;}dest[i]\0;// 确保字符串正确终止}6.2 常量指针与指针常量const char *p指向常量字符的指针指针可变指向的内容不可变。常用于传递只读字符串参数防止函数内部意外修改。char *const p指针常量指针不可变指向的内容可变。较少用于传参。const char *const p指向常量字符的指针常量两者都不可变。// 良好的接口设计表明函数不会修改字符串内容intcalculate_string_length(constchar*str);6.3 返回字符串指针函数可以返回指向字符的指针但必须注意返回的地址所指向的内存生命周期。// 错误示例返回局部数组的地址函数结束数组被销毁地址无效char*bad_function(){charlocal_str[]Hello;returnlocal_str;// 严重错误返回悬空指针。}// 正确做法之一返回静态局部变量的地址但非线程安全char*get_static_string(){staticcharstatic_str[]Static Hello;returnstatic_str;// 静态变量生命周期贯穿程序始终}// 正确做法之二返回传入的缓冲区指针调用者负责内存char*format_string(char*buffer,size_tsize,intvalue){snprintf(buffer,size,Value: %d,value);returnbuffer;}

相关新闻

最新新闻

Multisim仿真:Buck降压开关电路设计与不同负载测试

Multisim仿真:Buck降压开关电路设计与不同负载测试

一、实验目的这次使用Multisim搭建一个Buck降压开关电路,输入电压为12V,并分别接入50Ω和100Ω负载,观察输出电压波形的变化。本次电路采用固定PWM信号控制MOS管,暂时没有加入反馈,因此它属于开环Buck电路。开环电路可…

2026/8/2 5:56:18
跨境电商为什么需要指纹浏览器?深入解析浏览器环境管理技术

跨境电商为什么需要指纹浏览器?深入解析浏览器环境管理技术

引言:跨境业务正在进入精细化运营阶段 随着全球电商市场不断发展,越来越多企业开始布局海外业务。 从跨境电商平台运营,到独立站建设,再到海外广告推广,企业通常需要同时处理多个业务环节: 不同国家和地区的…

2026/8/2 5:56:18
机器学习分类模型评估:从混淆矩阵到精准率、召回率与F1 Score

机器学习分类模型评估:从混淆矩阵到精准率、召回率与F1 Score

1. 项目概述:为什么我们需要这么多“率”?刚入行做机器学习分类项目时,我最常被问到的一个问题就是:“模型准确率多少?” 早期我也总是不假思索地报出一个数字,比如“准确率95%”,听起来相当不错…

2026/8/2 5:56:18
基于Clawdbot与Jetson的智能机器人视觉抓取开发全攻略

基于Clawdbot与Jetson的智能机器人视觉抓取开发全攻略

1. 项目概述:当Clawdbot遇上reComputer Jetson最近在边缘AI和机器人开发圈子里,一个组合开始频繁出现:Clawdbot 和 reComputer Jetson。如果你正在寻找一个能快速上手、开箱即用,并且性能足够强劲的机器人开发平台,那这…

2026/8/2 5:56:18
策略模式实战:从硬编码到灵活算法替换的设计模式指南

策略模式实战:从硬编码到灵活算法替换的设计模式指南

1. 从“硬编码”到“灵活切换”:为什么我们需要策略模式如果你写过一段处理不同支付方式的代码,或者遇到过根据用户等级计算不同折扣的逻辑,那你大概率已经踩过“硬编码”的坑了。我刚开始做项目时,就写过这样的代码:一…

2026/8/2 5:56:18
桁架、管桁架、网架区别

桁架、管桁架、网架区别

管桁架没有球节点,是相贯线形式,也就是你说的管件相互焊接。网架都有球节点。分空心的焊接球与实心的螺栓球。常用网架一般都有球,分螺栓球和焊接球节点。 管桁架一般直接相贯。 1、钢结构工程中相贯线管桁架:就是用钢管连接做成的 2、普通桁架就是用型钢连接做成的

2026/8/2 5:51:18