【C】初めてのC言語（13. メモリを扱う標準関数）

# はじめに

* これまでの学習に続いて、今回はメモリに関わる関数を学んだ結果をまとめてみました。
  * [【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言語入門 第2版のp.378～p.383となります。

# 学習環境

* 今回は[paiza.io](https://paiza.io/ja/projects/new)のC言語のエディタを使いました。

# memcpy関数

```c:
void* memcpy(void* addr1, const void* addr2, size_t len)

// addr1：コピー先の先頭アドレス
// addr2：コピー元の先頭アドレス
// len：コピーするバイト数
```

* メモリ領域をコピーするための関数です。
  * 第2引数の`const void*`型は、「指している先の情報を変更できないvoid*型」だそうです。
  * 第3引数の`size_t`型は、「長さ、大きさ、サイズを表現する型」となります。
* 以下のコードでは、配列`a`の中身を配列`b`に丸ごとコピーしています。
* `memcpy`関数によるコピーは、shallow copy（浅いコピー）と呼ばれます。
  * 「配列や構造体はコピーされるものの、それらが内部に持つポインタが指している先の領域までは複製されずに同じものを指す」という特徴があります。

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

int main(void){
    int a[3] = {2, 4, 6};
    int b[3];

    memcpy(b, a, sizeof(a));   
    printf("bの要素を出力...\n");
    
    int length = sizeof(a) / sizeof(int);
    for(int i=0; i<length; i++) {
        printf("%d番目の要素は%dです。\n", i+1, b[i]);
    }
}
```

```text:実行結果
bの要素を出力...
1番目の要素は2です。
2番目の要素は4です。
3番目の要素は6です。
```

# memcmp関数

```c:
int memcmp(const void* addr1, const void* addr2, size_t len)

// addr1：比較先の先頭アドレス
// addr2：比較元の先頭アドレス
// len：比較するバイト数
// 戻り値：2つのメモリ領域が同じ内容ならば0を返す。
```

* メモリ領域を比較するための関数です。
  * 第1引数および第2引数の`const void*`型は、「指している先の情報を変更できないvoid*型」だそうです。
  * 第3引数の`size_t`型は、「長さ、大きさ、サイズを表現する型」となります。
* 以下のコードでは、配列`a`の中身と配列`b`の中身を全て比較しています。
  * `sizeof(a)`の代わりに`4`を代入すれば、先頭から4バイト目まで、つまり配列の最初の要素だけを比較できます。

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

int main(void){
    int a[3] = {2, 4, 6};
    int b[3] = {2, 4, 6};
    
    int result = memcmp(a, b, sizeof(a));
    
    if (result==0) {
        printf("配列の中身は等しいです。\n");
    } else {
        printf("配列の中身は等しくないです。\n");
    }
}
```

```text:実行結果
配列の中身は等しいです。
```

# memset関数

```c:
void* memset(void* addr, int val, size_t len)

// addr：書き込み先の先頭アドレス
// val：書き込む値（0～255）
// len：書き込むバイト数
// 戻り値：addrと同じデータ（＝書き込み先の先頭アドレス）
```

* メモリ領域を初期化するための関数です。
  * 第3引数の`size_t`型は、「長さ、大きさ、サイズを表現する型」となります。
* 以下のコードでは、配列`a`の中身を「配列の先頭から4バイト目までを初期化」しています。
  * `4`の代わりに`sizeof(a)`を代入すれば、配列の最初から最後の要素までを初期化できます。

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

int main(void){
    int a[3];    
    memset(a, 1, 4);
    
    int length = sizeof(a) / sizeof(int);
    for(int i=0; i<length; i++) {
        printf("%d番目の要素は%dです。\n", i+1, a[i]);
    }
}
```

```text:実行結果
1番目の要素は16843009です。
2番目の要素は-125704384です。
3番目の要素は-125704384です。
```

# 参考資料

* [スッキリわかるC言語入門 第2版](https://www.amazon.co.jp/dp/4295012785/)
  * p.378～p.383
* [size_t型](http://manabu.quu.cc/up/3/e31555.htm)