为什么Serial.println()会改变函数内部数组的值

Why does Serial.println() change the value of an array inside a function?

本文关键字:内部 函数 数组 改变 Serial println 为什么      更新时间:2023-10-16

这个问题类似于这个问题:Serial。println改变函数(Arduino)返回值

我有一个函数test(byte _b[]),它接收字节数组并使用本地临时字节数组更改其值。当函数test返回时,本地字节数组将被销毁,因此调用者应该无法访问它。但是,Serial.println()使调用者可以访问本地数组。为什么呢?这是不是有点像内存泄漏?

代码(在Arduino 1.6.12, 64位Debian Jessie中测试):

uint32_t timer;
void setup () {
  Serial.begin(57600);
  Serial.println("init");
}
void loop () {
  if (millis() > timer) {
    timer = millis() + 1000;
    // many bytes need escaping, so we better use the URLencode function
    byte testarray[3];
    test(testarray);
    Serial.print("testing: ");
    Serial.println((char *) testarray);
    Serial.println("---------");
  }
}
void test(byte _b[]) {
  byte c[4];
  c[0] = 95; c[1] = 48; c[2] = 55; c[3] = 0;
  _b = c;
  Serial.println((char *) c); // MARKED: this is the line that causes the unexpected behaviour
}
使用标记行,我得到以下输出:
init
_07
testing: _07
---------
_07
testing: _07
---------

没有标记行,我得到这个:

init
testing: 
---------
testing: 
---------
testing: 
---------
testing: 
---------
testing: 
---------

将未初始化的字节传递给函数:

byte testarray[3];
// ... code that does not write to testarray ...
Serial.println((char *) testarray);

这会导致未定义的行为;使用未初始化值的一个常见影响是,它们可能包含最近被程序的另一部分使用过的其他内容。

请注意,您标记了导致意外行为的特定行,但该行正常工作。输出_07。然后,当执行到未定义的行为行时,在本例中表现为也输出_07


在函数test中有一些你可能忽略了的东西:

  • c风格数组作为指针传递-函数与void test(byte * _b)相同。_b是指向testarray的第一个元素的指针。
  • 形参使用值传递(除非特别标记为引用传递):形参是通过复制实参值进行初始化的函数的局部变量。因此,更改_b不会对复制的初始化_b的参数产生任何影响。(需要明确的是,_b是一个指针-我们谈论的是指针,而不是_b可能指向的任何东西)。对指针使用赋值操作符意味着改变指针指向的位置。(也许你认为这意味着在指针指向的两个位置之间复制一些字节——但它不是)。

所以这行:

_b = c;

改变了局部变量_b的位置,而不改变testarray的位置。