【C言語】難解なポインタに挑む「忍法写し身の術？」その４

●はじめに

　こんにちは。
　今回は、C言語で皆さんが最もつまずくとされているポインタで文字列を用いたプログラムの説明をしていきたいと思います。
　私もポインタは概念が難しく理解するのに時間がかかりましたがわかりやすく解説していきます。

「え、そもそもC言語とか初めてなんだけど。。。」
「プログラミングの基礎がわからない。」

という方向けの記事ではないので以下のサイトの基本編を学んでからこの記事を読んでください。
[→一週間で身につくC言語の基本](https://c-lang.sevendays-study.com/)

「C言語の関数くらいまでならできるよー」
って方でポインタにつまずいている方は是非、読んでください。

また、前回はポインタで配列変数と組み合わせたプログラムの説明をしたので読んでいない方はこちらをご覧ください。
[→【C言語】難解なポインタに挑む「忍法写し身の術！」その３](https://qiita.com/hiroyuki-tabuchi/items/a0b2cb4fbdbf1fb5672d)
　
　
●文字列を操作する関数（前回の答え合わせ）

　前回の最後に、以下のサンプルプログラムを載せたと思いますので解説していきます。

```C:main.c
#include <stdio.h>
#include <string.h>

int main(int argc, char** argv) {
    char s[8];
    int len;
    // 文字列のコピー
    strcpy(s, "ABC");
    printf("s=%s\n", s);
    // 文字列の結合
    strcat(s, "DEF");
    printf("s=%s\n", s);
    // 文字列の長さ
    len = strlen(s);
    printf("文字列の長さ:%d\n", len);
    return 0;
}
```

```C:実行結果
s=ABC
s=ABCDEF
文字列の長さ:6
```

　C言語で文字列を扱う場合、char型の配列変数を使います。C言語には文字列を操作するさまざまな関数が存在します。C言語では文字列操作は頻繁に行われるため、ライブラリとしてstring.hが用意されています。ここでは、その中で比較的使用頻度が高い関数と、その使い方についてのプログラムを解説していくことにします。
　プログラムの#include \<string.h> によって、文字列の操作を行う関数が利用可能になります。ここでは、文字列のコピーや結合、および文字列の長さを求める関数を使用しているので、それぞれ詳細を紹介していきます。

　まずは、文字列のコピー関数と結合関数を見てみましょう。使用されている関数は以下のとおりです。

・文字列のコピーと結合の関数
| 関数 | 書式 | 意味 | 使用例 |
|:-:|:-:|:-:|:-:|
| strcpy  | strcpy(char* s1, char* s2);  | 第2引数の文字列を第1引数の文字列変数にコピーする  | strcpy(s, "Hello");  |
| strcat  | strcat(char* s1, char* s2);  | 第2引数の文字列を第1引数の文字列変数に追加する  | strcat(s, "World");  |

　このサンプルでは、まず長さ8のchar型の配列変数sを用意しています。

・長さ9のchar型配列変数s
| 添字 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| 配列の要素  |   |   |   |   |   |   |   |   |

　そして、strcpy関数で、配列変数sに"ABC"という文字列をコピーしています。ところでstrcpyの引数はポインタを指定するルールになっていますが配列変数sや"ABC"はポインタなのでしょうか？ここが少しわかりづらいところですが、前回に配列変数sは&s[0]と等しいと学びました。また、文字列"ABC"は'A','B','C','\0'に分解でき一種の配列変数と考えることができます。これは、s[0]からs[2]まで、それぞれ'A'から'C'までのASCIIコードが入り、最後に文字列の終端を示す'\0'が、s[3]に代入された状態となります。

・配列変数sに文字列"ABC"をコピーした状態（strcpy(s, "ABC");）
| 添字 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| 配列の要素  | 'A'  | 'B'  | 'C'  | '\0'  |   |   |   |   |

　そのあと、配列変数sにstrcat関数を使って"DEF"という文字列を追加しているので、最終的に配列変数sに入っている文字列は、"ABCDEF"となります。
　これは、文字列の終端であるs[3]からs[5]までに'D'から'F'までのASCIIコードが入り、文字列の終端の'0\'が、s[6]にまで移動した状態になります。

・配列変数sに文字列"DEF"が追加された状態（strcat(s, "DEF");）
| 添字 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| 配列の要素  | 'A'  | 'B'  | 'C'  | 'D'  | 'E'  | 'F'  | '\0'  |   |

　このプログラムでは最後に配列変数sの長さをstrlen関数で取得しています。strlen関数は、以下のような処理をする関数です。

・文字列の長さを調べる関数
| 関数 | 書式 | 意味 | 使用例 |
|:-:|:-:|:-:|:-:|
| strlen  | strlen(char* s);  | ()に文字列を与えると、戻り値として長さを得られる  | int n = strlen("Hello");  |

　文字列の長さとは、char型の配列の0番も文字から、最後に'\0'にたどり着くまでに入っている文字の数を指します。そのため、配列変数sとしての大きさは10ですが、文字列部分は「ABCDEF」だけなので、文字列の長さとして6が得られるわけです。

　ところで、このstrlen関数に関しては1つ気を付けなくてはならない場合があります。それは次のサンプルのようなケースです。

```C:main.c
#include <stdio.h>
#include <string.h>

int main(int argc, char** argv) {
    char s[] = "日本語の文字列";
    int len;
    len = strlen(s);
    printf("「%s」の長さは%dです。\n", s, len);
    return 0;
}
```

```C:実行結果
「日本語の文字列」の長さは14です。
```

　このサンプルでは、配列変数sには、「日本語の文字列」という日本語で書かれた文字列が入っています。常識から考えれば、この文字数は7文字なので、strlen関数の結果が代入される変数lenの値は7になりそうなものです。
　ところが、実行結果はその2倍の14となっています。これは、日本語が2バイトコード（Windows環境ではShift_JIS）で表されているためで、日本語の1文字が2文字とカウントされているのです。
　つまり、strlen関数は、ASCIIコードの場合の文字列の長さ=バイト数を取得するものであって、日本語等の2バイトコードの場合は、値はその倍になるということを注意する必要があります。

　ところで今回もポインタを扱ったのでわかりやすく忍法写し身の術！を使いたかったのですが当てはまる部分がなかったのでできませんでした。悪しからず。また、これで一度ポインタについての説明は以上とします。機会があったら再度ポインタについて投稿します。
　
　
【投稿者】
エンジニアファーストの会社 [株式会社CRE-CO](https://www.cre-co.jp/#top)　田渕浩之

【参考文献】
[→1週間でC言語の基礎が学べる本](https://www.amazon.co.jp/1%E9%80%B1%E9%96%93%E3%81%A7C%E8%A8%80%E8%AA%9E%E3%81%AE%E5%9F%BA%E7%A4%8E%E3%81%8C%E5%AD%A6%E3%81%B9%E3%82%8B%E6%9C%AC-1%E9%80%B1%E9%96%93%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E4%BA%80%E7%94%B0-%E5%81%A5%E5%8F%B8/dp/4295009873)