【C】初めてのC言語（15. sizeofの注意点）

# はじめに

* これまでの学習に続いて、今回はヒープに確保した領域のサイズについて学んだ結果をまとめてみました。
  * [【C】初めてのC言語（1. Hello world）](https://qiita.com/nkojima/items/518c1a4ec06861d74b3c)
  * [【C】初めてのC言語（2. 四則演算とフォーマット指定子）](https://qiita.com/nkojima/items/36ea93b7296ce9e8a55b)
  * [【C】初めてのC言語（3. ポインタ）](https://qiita.com/nkojima/items/825bb9f931016faccd68)
  * [【C】初めてのC言語（4. 構造体）](https://qiita.com/nkojima/items/40a1101f2f6f5800bc2d)
  * [【C】初めてのC言語（5. 関数）](https://qiita.com/nkojima/items/1fa3317c04f25fe24276)
  * [【C】初めてのC言語（6. 配列）](https://qiita.com/nkojima/items/eda3ff6675b47e7ab5f0)
  * [【C】初めてのC言語（7. for文）](https://qiita.com/nkojima/items/a5659098f7e5275a96ec)
  * [【C】初めてのC言語（8. 2次元配列）](https://qiita.com/nkojima/items/f5eb25a4f8d1725faa89)
  * [【C】初めてのC言語（9. 関数のプロトタイプ宣言）](https://qiita.com/nkojima/items/57318d74bdfa670bf72e)
  * [【C】初めてのC言語（10. 構造体配列）](https://qiita.com/nkojima/items/75530a3ca63924a14397)
  * [【C】初めてのC言語（11. ヘッダファイル）](https://qiita.com/nkojima/items/a10cd943ed66e0cea7fd)
  * [【C】初めてのC言語（12. 3つのからくり構文＋ポインタ演算）](https://qiita.com/nkojima/items/83cb40ec01cd6a6e6a87)
  * [【C】初めてのC言語（13. メモリを扱う標準関数）](https://qiita.com/nkojima/items/13c8d942f282beb3c212)
  * [【C】初めてのC言語（14. ヒープの利用）](https://qiita.com/nkojima/items/837557cc86ce9697611a)

# 学習環境

* 今回はpaiza.ioのC言語のエディタを使いました。

# 配列のサイズが変...

* [前回の記事](https://qiita.com/nkojima/items/837557cc86ce9697611a)のコードを作った際に、ヒープに作った配列のサイズを`sizeof()`で取得すると、本来は12バイトであるはずなのに8バイトになっていました。
* これは何か変だと思い、その理由を調べてみました。

```c:Main.c
#include <stdio.h>
#include <stdlib.h>

int main(void){
    int array1[3];
    int* array2 = (int*)malloc(sizeof(int) * 3);
    
    // int型は4バイトなので、2つの配列のサイズはともに12バイトとなるはず。
    printf("array1のサイズは%dです。\n", sizeof(array1));
    printf("array2のサイズは%dです。\n", sizeof(array2));
    
    free(array2);
}
```

```text:実行結果
array1のサイズは12です。
array2のサイズは8です。
```

# sizeof関数の仕様

## Wikipediaの記述

* sizeofは、データ型の大きさを求める単項の演算子である。
* sizeofは原則としてコンパイル時計算される演算子で、式もしくは括弧でくくった型指定子を与えるとその大きさをバイト単位で返す。

→1つ目は分かりましたが、2つ目の「原則として」というのが分からなかったので、さらに他のサイトを調べてみました。

## [mallocで確保した領域のサイズを得たい](https://teratail.com/questions/119123) 

* malloc関数で確保したエリアのサイズは、後付けでは取得できません。
* なので、この関数実行時のサイズを覚えておく必要がありますねー
 
→どうやらmallocやcallocで確保したメモリのサイズは、sizeofでは正しく取得できないようです...

## [sizeofで変数のサイズを取得するときの注意点](https://corgi-lab.com/programming/c-lang/sizeof/)

* sizeofはコード上では”sizeof(変数)”の形で書くので、関数っぽい見え方になっていますが、**実はその正体は「演算子」です。**「+」とか「/」とかの仲間ということですね。
* C言語の世界では、演算子はコンパイル時にその結果が決まります。
* つまり、**sizeofの結果は実行時に決まるわけではなく、コンパイルの時点ですでに決まっているのです。**

→関数だと思っていたsizeofが演算子で、その結果が実行時に決まるわけではなく、コンパイル時には既に決まっていました。
→上記のコードだと、「array1はコンパイル時にヒープ上に12バイト確保することが決まり、array2は実行時にはじめてヒープ上に12バイト確保することが決まる」ということですね。

## [sizeof演算子 - せりか式](http://www.kis-lab.com/serikashiki/C/C03.html)

* （mallocを使ってメモリを確保した変数に対してsizeofを使って得られる結果は、）**mallocで確保したサイズではなく，int \*のサイズを表しています。**
 
→上記のコードを実行した結果、array2のサイズが8バイトとなりましたが、これは「int*のサイズ」だったようです。

# mallocで確保したサイズをどのように求めるのか？

## malloc_usable_size関数の利用

* [sizeof演算子 - せりか式](http://www.kis-lab.com/serikashiki/C/C03.html)によると、以下の様に書かれていました。
  * ヘッダファイルmalloc.hをインクルードして、mallocで返されたポインタを引数として、malloc_usable_size関数を呼び出します。
  * `malloc(100)`を実行した場合、100かもう少し大きな値が返ってくるはずです。
* malloc_usable_sizeを実行すると24バイトという結果が得られましたが、これだと正しい結果とは言えませんね...
* また、malloc_usable_sizeはLinux環境でしか使えないそうです。

```c:Main.c
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

int main(void){
    int array1[3];
    int* array2 = (int*)malloc(sizeof(int) * 3);
    
    printf("array1のサイズは%dです。\n", sizeof(array1));
    printf("array2のサイズは%dです。\n", malloc_usable_size(array2));
    
    free(array2);
}
```

```text:実行結果
array1のサイズは12です。
array2のサイズは24です。
```

## その他の解決策

* [Yahoo知恵袋](https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q12227835747)に私と同じ疑問を持った方が質問されていますが、それに対する回答は「mallocで確保したサイズをどこかに保管しておくしかない」というものでした。
  * 何だかスマートではない方法に感じますが、標準Cライブラリだと致し方ないのかもしれませんね...

# 参考URL

* [mallocで確保した領域のサイズを得たい](https://teratail.com/questions/119123)
* [sizeofで変数のサイズを取得するときの注意点](https://corgi-lab.com/programming/c-lang/sizeof/)
* [sizeof - Wikipedia](https://ja.wikipedia.org/wiki/Sizeof)
* [sizeof演算子 - せりか式](http://www.kis-lab.com/serikashiki/C/C03.html)
* [C言語でint型のmallocで取った配列の全体の要素数を確認するにはどう書けば良いでしょうか - Yahoo知恵袋](https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q12227835747)