引言指针与数组的紧密联系在嵌入式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;}