3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

メモリの動的確保の注意 malloc, calloc C言語

Last updated at Posted at 2020-07-01

はじめに

C言語だとメモリを動的確保する際に、mallocやcallocといったメモリを確保する関数を使うと思います。そのときの注意です。

基本的な使い方に関してはこちら

callocの返り値はアドレス

環境
gcc -v
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 11.0.3 (clang-1103.0.32.59)
Target: x86_64-apple-darwin19.5.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

本文

「stdlib.hを必ずインクルードすること」

mallocを使うためには、#include <stdlib.h>を魔法のように唱えると思います。

では唱えなかった場合はどうなるでしょうか。普通ならコンパイル(プリプロセス)の段階で落ちるはずです。ですがmallocに関してはwarningを吐くだけでコンパイルはできてしまいます。

この時のデメリットとして、返り値がint型になることが挙げられます

「想定した動作では64bitのlong*(long型ポインタ)として 返したいにもかかわらず、32bitのint型が返ってしまう。」というようなバグが起こるわけです。

参考:mallocのwiki > C言語での動的メモリアロケーション

「要素数 0 でcallocを呼ばないこと」

callocは通常、配列などの複数要素を動的に確保するために使用するケースが多いです。なので、本来要素数を0で呼ぶことは考えられないのですが、呼んでしまった場合どうなるでしょう

メモリ確保に失敗したとしてNULLポインタが返って...くるわけではありません。

実際には処理系定義ですが、返せる領域があればNULLポインタではなくアドレスが返ってくる場合が存在します。

その場合、NULLだと思って処理を進めるとバグを生む可能性があります。

参考:C 標準 [ISO/IEC 9899:2011] セクション 7.22.3 抜粋ページ

「確保した要素数以上へのアクセスはできてしまう」

先ほどに引き続き、callocは複数要素を動的に確保するために使用するケースが多いです。なのでint型の配列で3要素欲しければ(int*)calloc(3, sizeof(int))をint* の変数に代入するわけです。

配列の宣言としてint array[3]としたときarray[3]にアクセスするとどうなるかもちろん参照外アクセスで落ちますね。
ではcalloc関数の場合は?

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[]){

    int* ap;
    
    ap = calloc(3, sizeof(int));
    
    ap[2] = 1;
    ap[3] = 1;
    printf("%p\n", &ap[2]);   // アドレスを表示
    printf("%p\n", &ap[3]);
    printf("%p\n", &ap[4]);
    printf("%d\n", ap[2]);
    printf("%d\n", ap[3]);
    printf("%d\n", ap[4]);

    free(ap);    
    return 0;
}
出力結果
0x7fe2d3c05848
0x7fe2d3c0584c
0x7fe2d3c05850
1
1
0

普通にアクセスできるですね(ドン引き)。しかもコンパイラはwarning出しませんでした。

ここからは予想ですが、callocは起点となるアドレス(ar[0])を返すだけですから、連続領域として確保した要素数以上のところもアクセスできてしまうんですかね(謎)

いずれにしても、こういう想定外のことはバグの原因になるので注意しましょう。

3
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?