【C】初めてのC言語（18. 文字列の受け渡し）

# はじめに

* これまでの学習に続いて、今回は文字列の基本的な操作について学んだ結果をまとめてみました。
  * [【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)
  * [【C】初めてのC言語（15. sizeofの注意点）](https://qiita.com/nkojima/items/6c9a3ba04c6348219578)
  * [【C】初めてのC言語（16. 文字列の基本）](https://qiita.com/nkojima/items/d87ce0cb15dd1a26f21a)
  * [【C】初めてのC言語（17. 文字列リテラル）](https://qiita.com/nkojima/items/527ef37d84cf9b201dc5)

# 学習環境

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

# C言語の文字列に関する業界ルール

文字列を扱う際の基本ルールとして、以下の4箇条が挙げられていました。
今回新たに登場したのは3～4番目の内容です。

1. 先頭要素から順に1文字ずつ文字コードを格納して、文字列を表す。
1. 最後の文字の直後には、「文字コード0の文字」を必ず格納する。そして、それより後ろのメモリ空間は無視するものとし、利用しない。
1. **文字列情報を別関数などに渡す場合は、先頭文字のアドレスだけを渡す。**
1. **配列を実現するためのメモリ領域を確保する手段は問わない。**

# 文字列を別の関数に渡す

* 文字列を別の関数に渡す場合、先頭文字のアドレスを渡すのがルールとなりますが...
* char型配列で表された文字列の場合、配列変数が「配列の先頭要素の位置を示すアドレス」と等しいため、（表面的には）文字列をそのまま関数の引数として渡すことができます。

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

int main(void){
    char str[] = "Hello";
    
    // 関数の引数として、文字列の先頭要素のアドレスを渡すことができる。
    printf("%s\n", &str[0]);
    
    // 「配列＝先頭要素の位置を示すアドレス」のため、
    // 文字列（char型配列）をそのまま関数の引数として渡すことができる。
    printf("%s\n", str);
    
    return 0;
}
```

```text:実行結果
Hello
Hello
```

# 文字列の管理

* C言語の世界では、文字列は「先頭アドレスを使って管理する」のが一般的だそうです。
* そのため、先頭アドレスそのものについても「文字列」と呼ぶことが多いそうです。

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

int main(void){
    char str[20] = "Hello,world!";
    char* buff = str;  // 先頭アドレスを代入
    
    // どちらも同じ出力結果となる。
    printf("%s\n", str);
    printf("%s\n", buff);
    
    return 0;
}
```

```text:実行結果
Hello,world!
Hello,world!
```

# 文字列の実現手段

* 文字列は連続したメモリ領域さえ確保できれば良いので、様々な方法で文字列を作ることができます。
  * 以下の「方法3」では、malloc関数を使ってヒープにメモリ領域を確保して、そこに文字列を作っています。
* また、`str1`は内容変更があってはならない静的領域に置かれるため、文字列を`const char*`型としています。
  * 静的領域のデータに対して`const`を着けないと、組み込み機器などでは意図せずメモリアクセス違反になることがあるそうです。
* なお`str1`～`str3`は、それぞれ以下のメモリ領域に置かれます。
  * `str1`：静的領域に置かれる。
  * `str2`：スタック領域に置かれる。
  * `str3`：ヒープ領域に置かれる。

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

// p.409
// 
int main(void){
    // 方法1：文字列リテラルでメモリを確保する。
    const char* str1 = "Test";
    printf("%s\n", str1);
    
    // 方法2：char配列を使う。
    char str2[1024] = "Test";
    printf("%s\n", str2);
    
    // 方法3：mallocでメモリを確保する。
    char* str3 = (char*)malloc(1024);
    str3[0] = 'T';
    str3[1] = 'e';
    str3[2] = 's';
    str3[3] = 't';
    str3[4] = '\0';
    printf("%s\n", str3);
    free(str3);  // 最後にヒープ領域を解放する。

    return 0;
}
```

```text:実行結果
Test
Test
Test
```


# 参考URL

* [スッキリわかるC言語入門 第2版](https://www.amazon.co.jp/dp/4295012785/)
  * p.406～p.412
* [【C】初めてのC言語（12. 3つのからくり構文＋ポインタ演算）](https://qiita.com/nkojima/items/83cb40ec01cd6a6e6a87)
  * 配列変数の評価、添え字演算子の評価など。
* [【C】初めてのC言語（14. ヒープの利用）](https://qiita.com/nkojima/items/837557cc86ce9697611a)
  * malloc関数など