組み込みC/C++

C/C++リテラシー向上のためのページ

ポインタでやってしまうミス①

ポインタのミスはやってしまいがちです。多くの場合はスコープの消滅に関連しているような気がします。というわけでポインタのミスのパターン化のために悪い例のプログラムを切り取っておこうかと思います。

 

Pattern 1 

#include <stdio.h>

char *foo;

char *sub_routin(char *bar);

int _tmain(int argc, _TCHAR* argv[ ])
{
    char *bar = "ab";
    
    foo = sub_routin(bar);
  
    printf("foo=%s\n", foo);  
  
    return 0;
}

char *sub_routin(char *bar)
{
    char baz[2];
    
    baz[0] = bar[0];
    baz[1] = bar[1];

    return baz;
}

このパターンはさすがに失敗しない気がしますがsub_routinで宣言した変数のアドレスは返却してはいけません。この場合の対処方法としてはchar baz[2]にstaticをつければいいのですが、 それでは資源の無駄遣いになりますので上位モジュールmainで返却用のBufferを用意してsub_routinに引数として渡すべきでしょう。

 

Pattern 2 

#include <stdio.h>

char *foo;

void sub_routin(char bar);

int _tmain(int argc, _TCHAR* argv[ ])
{
    char bar = 'a';
	
    sub_routin(bar);
  
    printf("foo=%d\n", foo);  
  
    return 0;
}

void sub_routin(char bar)
{
    foo = &bar;
}

 一見よさそうなんですがsub_routinでのbarはローカルスコープなのでmainでprintfする時にはそのアドレスの指す先は不定になります。引数で受けた変数だから大丈夫だろうと思ってしまいがちなのですが、引数で渡される場合はコピーです。ポインタであろうと、参照であろうとコピーなことを忘れてはいけません。(ポインタや参照でもアドレスをコピーするのであって、そのアドレスを格納する箱は従属関数の方で準備することになります。間違ってその箱のアドレスを戻してはいけません。)

 

二個目のエントリはコードレビューで僕が見逃してしまった内容を元にしています。実際は参照渡しでもっと複雑なパターンだったんですが簡略化して記載しました。以後、こういったミスパターンを見つけた場合はここで記そうかと思います。