2016-11-14 1 views
-1

この質問は、この1のようになります。Serial.println changes return value of function (Arduino)なぜSerial.println()は関数内の配列の値を変更するのですか?

私はバイト配列を受け取り、ローカルの一時的なバイト配列を使用して、その値を変更する機能、test(byte _b[])を、持っています。そのローカルバイト配列は、関数testが返ってきたときに破棄されるので、呼び出し側はそれにアクセスできなくてすみます。しかし、Serial.println()は、ローカル配列を呼び出し側がアクセスできるようにします。 なぜですか?これはメモリリークのようですか?

コード(アルドゥイーノ1.6.12、64ビットのDebianジェシーで試験):MARKEDなし

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

:標線と

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 
testing: 
--------- 
testing: 
--------- 
testing: 
--------- 
testing: 
--------- 
testing: 
--------- 
+1

まあ、 'char *'を表示するJavaプログラムは、予期せぬ動作を起こすことになっています。これを適切にタグ付けしてもよろしいですか? –

+0

どういう意味ですか?Stackoverflowは "Java"タグを提案しました。 Arduino IDEはJavaで書かれていませんか? –

+0

Stack Overflowの提案に従うことは義務ではありません。そしてArduino IDEが書かれている言語は無関係です。 ArduinoはCまたはC++で書かれたコードをサポートしているということを私が理解していれば間違いないかもしれません。だから、基本的に、あなたはCやC++の何かの助けを借りてスタックオーバーフローのJava開発者に尋ねました。 Javaタグを削除してCタグまたはC++タグを置くと、より良いヘルプが得られます。 –

答えて

0

あなたは関数に初期化されていないバイトを渡す:

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

これは、undefined behaviourを引き起こします。初期化されていない値を使用する一般的な効果の1つは、プログラムの別の部分で最近使用された他のコンテンツが含まれているように見えることです。

予期しない動作が発生すると特定の行をマークしましたが、その行は正しく動作することに注意してください。 _07を出力します。実行が未定義のビヘイビア行に達すると、このインスタンスの表現では_07も出力されます。機能testインサイド


は、あなたが見落としている可能性のものがあります:

  • Cスタイルの配列はポインタとして渡される - 機能はvoid test(byte * _b)と同じです。 _bは、testarrayの最初の要素を指すポインタです。
  • パラメータは、値渡しを使用します(特に、参照渡しとしてマークされている場合を除く)。パラメータは、引数値をコピーして初期化される関数のローカル変数です。したがって、_bを変更すると、何も引数がコピーされて_bを初期化するためには何の効果もありません。 (明確にするために、_bはポインタです - 私たちはポインターについて言及していますが、_bが指しているものではありません)。
  • ポインターでの代入演算子の使用は、ポインターがどこを指しているかを変更することを意味します。 (ポインターが指す2つの場所の間にいくつかのバイト数をコピーすることを意味すると思われるかもしれませんが、そうではありません)。だから、

ライン:

_b = c; 

ローカル変数の変更_bポイントを、そしてtestarrayについては何も変わりません。

+0

私は見る!だから、 'testarray'の値を変更するには、' _b [0]、_b [1]、_b [2] 'に値を代入することができます。 'それ自体、そうですか? 'test()'関数は、リンクリスト(pointer-to-pointer passing reference)のように考えずに、値を変更するだけでなく 'testarray'の値の数も変更できますか? –

+0

はい、 '_b [0]'などに割り当てることができます。配列サイズはコンパイル時に固定でなければならず、変更することはできません。 –

関連する問題