C言語の基礎 - 文字列

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動

文字列を初期化する

C言語で文字列を初期化するには、string.hのmemset関数を使用する。

memset関数は、第1引数が指すオブジェクトの先頭から第3引数の文字数分だけ、第2引数の文字列をセットする関数である。
この関数を利用すれば、文字列を指定した文字で埋めることができる。

注意
memset関数は、文字列の終端'\0'を自動的に付加しないので、'\0'以外の文字で埋める場合は、文字列の最後に終端'\0'を付加する必要がある。

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #define N 16
 
 int main(void)
 {
    char s[N];
 
    /* 文字列 s を 15 文字分 'z' で埋める. */
    memset(s, 'z', N);
    s[N - 1] = '\0';
 
    printf("s: %s\n", s);
 
    return EXIT_SUCCESS;
 }



文字列をコピーする

文字列をコピーするには、string.hのstrcpy関数またはstrncpy関数を使用する。
ただし、strcpy関数はバッファオーバーフローを発生させやすい関数なので、ここでは、strncpy関数を記載する。

strncpy関数は、第2引数が指す文字列から、第1引数が指す文字列に最大で第3引数の文字数分をコピーする関数である。
なお、第2引数が指す文字列の終端'\0'に続く文字はコピーされない。

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #define N 256
 
 int main(void)
 {
    char s1[N] = {'\0'};
    char s2[] = "Snoopy!";
 
    printf("-- コピー前 --\n");
    printf("s1: %s\n", s1);
    printf("s2: %s\n", s2);
 
    /* s2の内容をN文字分だけs1にコピー */
    strncpy(s1, s2, N);
    if ( N > 0 )
    {
       s1[N - 1] = '\0';
    }
 
    printf("\n-- コピー後 --\n");
    printf("s1: %s\n", s1);
    printf("s2: %s\n", s2);
 
    return EXIT_SUCCESS;
 }


注意
strncpy関数は、第3引数の値が第2引数のサイズよりも大きい場合、第1引数に文字列をコピーした後、自動的に文字列の最後まで'\0'を付加する。
しかし、第3引数の値が第2引数のサイズよりも小さい場合、終端'\0'を付加しない。
したがって、第2引数のサイズが第3引数の値よりも大きい場合は、なんらかの対策が必要になる。
最も簡単な対策法としては、コピー後の文字列のn - 1番目の要素に'\0'をセットする方法がある。
具体的には以下のように実装する。

 strncpy(s1, s2, n);
 if (n > 0)
 {
    s1[n - 1] = '\0';
 }



文字列を連結する

文字列を連結するには、string.hのstrcat関数またはstrncat関数を使用する。
ただし、strcat関数はバッファオーバーフローを発生させやすい関数なので、ここでは、strncat関数を記載する。

strncat関数は、第2引数が指す文字列から最大で第3引数の文字数分の文字列を、第1引数が指す文字列の最後に付加する。
なお、文字列の終端'\0'は自動的に付加されるので、第3引数の値が第2引数のサイズよりも小さい場合でも、手動で'\0'を付加する必要はない。

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #define N 256
 
 int main(void)
 {
    char s1[] = "Snoopy";
    char s2[] = "Charlie Brown";
 
    /* 文字列の連結 */
    strncat(s1, s2, 7);
    printf("s1 + s2 (7文字分) : %s\n", s1);
 
    return EXIT_SUCCESS;
 }



文字列を指定文字で分割する

文字列を指定文字で分割するには、string.hのstrtok関数を使用する。
strtok関数は、第1引数が指す文字列を、第2引数が指す文字列の中のいずれかの文字で区切られる字句の列に分割する関数である。
strtok関数は、1回の呼び出しで複数の分割を行うことができない。文字列の分割は、strtok関数を呼び出すごとに1回ずつ行われる。
strtok関数の1回目の呼び出しには、第1引数に分割する対象の文字列を指定する。
2回目以降の呼び出しは、第1引数にNULLを指定することで、前回分割された場所の次から分割を開始する。
分割できる文字列がなくなると、strtok関数はNULLを返す。

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 int main(void)
 {
    char s1[] = "0055,Ichiro Suzuki,Seattle,090-9999-9999";
    char *code, *name, *address, *tel, *empty;
 
    /* 1回目の呼出し */
    code = strtok(s1, ",");
 
    /* 2回目以降の呼出し */
    name = strtok(NULL, ",");
    address = strtok(NULL, ",");
    tel = strtok(NULL, ",");
    empty = strtok(NULL, ",");
 
    printf("code: %s\n", code);
    printf("name: %s\n", name);
    printf("address: %s\n", address);
    printf("tel: %s\n", tel);
    printf("empty: %s\n", empty);
 
    return EXIT_SUCCESS;
 }



文字列の先頭と末尾にある空白を削除する

C言語には、文字列の先頭と末尾にある空白を削除する関数やマクロは存在しない。
したがって、各自でこの機能を実装する必要がある。

実装は以下の手順で行うことが出来る。

  1. 文字列の末尾の位置を探す
  2. 手順 1 で探した末尾から順に,空白でない位置を探す
  3. 手順 2 で探した位置 + 1 に終端の '\0' を付加する
  4. 文字列の先頭から順番に空白でない位置を探す
  5. 手順 4 で探した位置から末尾まで文字列をコピーする


 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 int Trim(char *s);
 
 int main(void)
 {
    int ret;
    char snoopy[] = "   SNOOPY   ";
 
    ret = Trim(snoopy);
    printf("変換後: \"%s\"\n", snoopy);
    printf("削除した空白: %d文字\n", ret);
 
    return EXIT_SUCCESS;
 }
 
 /* 文字列の先頭と末尾にある空白を削除する */
 /* @param[in] s 対象文字列                */
 /* @return 削除した空白の数を返す         */
 int Trim(char *s)
 {
    int i;
    int count = 0;
 
    /* 空ポインタか? */
    if ( s == NULL )
    {
        return -1;
    }
 
    /* 文字列長を取得する */
    i = strlen(s);
 
    /* 末尾から順に空白でない位置を探す */
    while ( --i >= 0 && s[i] == ' ' ) count++;
 
    /* 終端ナル文字を付加する */
    s[i+1] = '\0';
 
    /* 先頭から順に空白でない位置を探す */
    i = 0;
    while ( s[i] != '\0' && s[i] == ' ' ) i++;
    strcpy(s, &s[i]);
 
    return i + count;
 }



文字列の先頭にある空白を削除する

C言語には、文字列の先頭にある空白を削除する関数やマクロは存在しないので、各自でこの機能を実装する必要がある。

実装は以下の手順で行うことが出来る。

  1. 文字列の先頭から順番に空白でない位置を探す
  2. 手順 1 で探した位置から末尾まで文字列をコピーする
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 int TrimStart(char *s);
 
 int main(void)
 {
    int ret;
    char snoopy[] = "   SNOOPY";
 
    ret = TrimStart(snoopy);
    printf("変換後: \"%s\"\n", snoopy);
    printf("削除した空白: %d文字\n", ret);
 
    return EXIT_SUCCESS;
 }
 
 /* 文字列の先頭にある空白を削除する */
 /* @param [in] s 対象文字列         */
 /* @return 削除した空白の数を返す   */
 int TrimStart(char *s)
 {
    int i = 0;
 
    /* 空ポインタか? */
    if ( s == NULL )
    {
        return -1;
    }
 
    /* 先頭から順に空白でない位置を探す */
    while ( s[i] != '\0' && s[i] == ' ' ) i++;
    strcpy(s, &s[i]);
 
    return i;
 }



文字列の末尾にある空白を削除する

C言語には、文字列の末尾にある空白を削除する関数やマクロは存在しないので、各自でこの機能を実装する必要がある。
実装は以下の手順で行うことが出来る。

  1. 文字列の末尾の位置を探す
  2. 手順1で探した末尾から順に、空白でない位置を探す
  3. 手順2で探した位置 + 1 に終端の'\0'を付加する
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 int TrimEnd(char *s);

 int main(void)
 {
    int ret;
    char snoopy[] = "SNOOPY   ";
 
    ret = TrimEnd(snoopy);
    printf("変換後: \"%s\"\n", snoopy);
    printf("削除した空白: %d文字\n", ret);

    return EXIT_SUCCESS;
 }
 
 /* 文字列の末尾にある空白を削除する */
 /* @param[in] s 対象文字列          */
 /* @return 削除した空白の数を返す   */
 int TrimEnd(char *s)
 {
    int i;
    int count = 0;
 
    /* 空ポインタか? */
    if ( s == NULL )
    {
       return -1;
    }
 
    /* 文字列長を取得する */
    i = strlen(s);
 
    /* 末尾から順に空白でない位置を探す */
    while ( --i >= 0 && s[i] == ' ' ) count++;
 
    /* 終端ナル文字を付加する */
    s[i + 1] = '\0';
 
    return count;
 }



文字列の長さを取得する

C言語で文字列の長さを取得するには、string.hのstrlen関数を使用する。
strlen関数は、第1引数が指す文字列の長さを取得する関数である。なお、文字列の長さに終端'\0'は含まない。

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 int main(void)
 {
    char s[] = "スヌーピー!";
    int length;
 
    length = (int)strlen(s);
    printf("%sの長さ: %d\n", s, length);

    return EXIT_SUCCESS;
 }



文字列を比較する

C言語で文字列を比較するには、string.hのstrcmp関数またはstrncmp関数を使用する。

strcmp関数は、第1引数が指す文字列と第2引数が指す文字列を比較する関数である。文字列を最初から最後まで比較したいときに使用する。
strncmp関数は、第1引数が指す文字列の始めの第3引数の文字数分と、第2引数が指す文字列の始めの第3引数の文字数分を比較する関数である。
(文字列の終端'\0'に続く文字の比較は行わない)
主に文字列の一部を比較したいときに使用する。

strcmp関数とstrncmp関数は、比較する文字列が同じなら0、第1引数 > 第2引数なら正の整数、第1引数 < 第2引数なら負の整数を返す。

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 int main(void)
 {
    char s1[] = "Hoge01";
    char s2[] = "Hoge02";
 
    puts("全文字比較");
    if ( strcmp(s1, s2) == 0 )
    {
       printf("%sと%sは同じ文字列です.\n", s1, s2);
    }
    else
    {
       printf("%sと%sは異なる文字列です.\n", s1, s2);
    }
 
    puts("先頭の4文字分比較");
    if ( strncmp(s1, s2, 4) == 0 )
    {
       printf("%sと%sは同じ文字列です.\n", s1, s2);
    }
    else
    {
       printf("%sと%sは異なる文字列です.\n", s1, s2);
    }
 
    return EXIT_SUCCESS;
 }



大文字小文字を区別せずに文字列を比較する

C言語には、大文字小文字を区別せずに文字列を比較する関数やマクロは存在しないので、各自でこの機能を実装する必要がある。
実装方法としては,文字列を構成する文字を1文字ずつ大文字に変換して比較を行えばよい。
なお、以下の例では文字を大文字に変換するためにctype.hのtoupper関数を使用している。

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
 
 #define N 256
 
 int strcmp_ignorecase(const char *, const char *);
 int strncmp_ignorecase(const char *, const char *, size_t);
 
 int main(void)
 {
    char s1[N] = {'\0'};
    char s2[N] = {'\0'};
 
    /* 入力 */
    printf("文字列1を入力してください.\n> ");
    scanf("%s", s1);
    printf("文字列2を入力してください.\n> ");
    scanf("%s", s2);
 
    puts("全文字比較");
    if ( strcmp_ignorecase(s1, s2) == 0 )
    {
       printf("%sと%sは同じ文字列です.\n", s1, s2);
    }
    else
    {
       printf("%sと%sは異なる文字列です.\n", s1, s2);
    }
 
    puts("先頭の4文字分比較");
    if ( strncmp_ignorecase(s1, s2, 4) == 0 )
    {
       printf("%sと%sは同じ文字列です.\n", s1, s2);
    }
    else
    {
       printf("%sと%sは異なる文字列です.\n", s1, s2);
    }
 
    return EXIT_SUCCESS;
 }
 
 /* 文字列を大文字小文字を区別せずに比較する */
 /* @param[in] s1 文字列1                    */
 /* @param[in] s2 文字列2                    */
 /* @retval 0 s1とs2が同じ文字列であるとき   */
 /* @retval 正の整数 s1 > s2であるとき       */
 /* @retval 負の整数 s2 < s2であるとき       */
 int strcmp_ignorecase(const char *s1, const char *s2)
 {
    int i = 0;
 
    /* 文字が等しい間繰り返す */
    while (toupper((unsigned char)s1[i]) == toupper((unsigned char)s2[i]))
    {
       if (s1[i] == '\0')
       {
          return 0;
       }
       i++;
    }
 
    return toupper((unsigned char)s1[i]) - toupper((unsigned char)s2[i]);
 }
/* 大文字小文字を区別せずに文字列をn文字分比較する */
/* @param[IN] s1 文字列1                           */
/* @param[IN] s2 文字列2                           */
/* @param[IN] n 比較する文字数                     */
/* @retval 0 s1とs2が同じ文字列であるとき          */
/* @retval 正の整数 s1 > s2であるとき              */
/* @retval 負の整数 s2 < s2であるとき              */
int strncmp_ignorecase(const char *s1, const char *s2, size_t n)
{
   int i = 0;

   /* 文字が等しい間繰り返す */
   while (toupper((unsigned char)s1[i]) == toupper((unsigned char)s2[i]))
   {
      if ( s1[i] == '\0' || i >= (int)(n - 1) )
      {
         return 0;
      }
      i++;
   }

   return toupper((unsigned char)s1[i]) - toupper((unsigned char)s2[i]);
}
</syntaxhighlight>



文字列の先頭から文字を検索する

C言語で文字列の先頭から文字を検索するには、string.hのstrchr関数を使用する。
strchr関数は、第1引数が指す文字列の先頭から、第2引数が指す文字を検索する関数である。
strchr関数は、文字が見つかった場合は探し出した文字へのポインタを返し、文字が見つからなかったときにはNULLを返す。
探し出した文字へのポインタから文字列の先頭アドレスを引くことで、指定した文字が最初に現れる位置を求めることができる。

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 int main(void)
 {
    char s[] = "I don't want to march as much as possible.";
    char *ret;
    int c;
 
    puts("文字を入力してください.");
    c = getchar();
 
    /* s が指す文字列に c があるか? */
    if ((ret = strchr(s, c)) != NULL )
    {
       printf("'%c'は%d番目にありました.\n", c, ret - s);
    }
    else
    {
       printf("'%c'はありませんでした.\n", c);
    }
 
    return EXIT_SUCCESS;
 }



文字列の最後から文字を検索する

C言語で文字列の最後から文字を検索するには、string.hのstrrchr関数を使用する。
strrchr関数は、第1引数が指す文字列の後ろから第2引数が指す文字を検索する関数である。
strrchr関数は、文字が見つかった場合は探し出した文字へのポインタを返し、文字が見つからなかった場合はNULLを返す。
探し出した文字へのポインタから文字列の先頭アドレスを引くことで,指定した文字が最後に現れる位置を求めることができる。

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 int main(void)
 {
    char s[] = "I don't want to march as much as possible.";
    char *ret;
    int c;
 
    puts("文字を入力してください.");
    c = getchar();
 
    /* s が指す文字列に c があるか? */
    if ((ret = strrchr(s, c)) != NULL )
    {
       printf("'%c'が一番最後に見つかった位置は%d番目です.\n", c, ret - s);
    }
    else
    {
       printf("'%c'はありませんでした.\n", c);
    }
 
    return EXIT_SUCCESS;
 }



文字列から大文字小文字を区別せずに文字を検索する

C言語には、文字列から大文字小文字を区別せずに文字を検索する関数やマクロは存在しないので、各自でこの機能を実装する必要がある。
実装方法としては、文字列を構成する文字と検索する文字を一端大文字に変換して、1文字ずつ比較を行えばよい。
以下の例では、文字を大文字に変換するためにctype.hのtoupper関数を使用する。

 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
 
 char *strchr_ignorecase(const char *, char);
 
 int main(void)
 {
    char s[] = "I don't want to march as much as possible.";
    char *ret;
    int c;
 
    puts("文字を入力してください.");
    c = getchar();
 
    /* s が指す文字列に c があるか? */
    if ((ret = strchr_ignorecase(s, c)) != NULL )
    {
       printf("'%c'は%d番目にありました.\n", c, ret - s);
    }
    else
    {
       printf("'%c'はありませんでした.\n", c);
    }
 
    return EXIT_SUCCESS;
 }
 
 /* 文字列から文字を大文字小文字を区別せずに検索する        */
 /* @param[in] s 検索対象文字列                             */
 /* @param[in] c 変換する文字                               */
 /* @retval 探し出した文字へのポインタ 文字が見つかったとき */
 /* @retval 空ポインタ 見つからなかったとき                 */
 char *strchr_ignorecase(const char *s, char c)
 {
    int i = 0;
 
    while ( s[i] != '\0' )
    {
       if ( toupper((unsigned char)s[i]) == toupper((unsigned char)c) )
       {
          return (char *)(s + i);
       }
       i++;
    }
 
    return NULL;
 }



文字列から指定したいずれかの文字を検索する

C言語で文字列から指定したいずれかの文字を検索するには、string.hのstrpbrk関数を使用する。
strpbrk関数は、第1引数が指す文字列の中で第2引数が指す文字列中のいずれかの文字を検索する関数である。
strpbrk関数は、文字が見つかった場合は探し出した文字へのポインタを返し、文字が見つからなかった場合はNULLを返す。
strpbrk関数を利用すると、文字列の中で指定した文字が現れる位置を探すことができる。

以下の例では、探し出した文字へのポインタから文字列の先頭アドレスを引くことで、指定した文字が最初に現れる位置を求めている。

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 int main(void)
 {
    char s1[] = "abcdefghijklmnopqrstuvwxyz";
    char s2[] = "fgh";
    char *c;
 
    /* s1が指す文字列に'f','g','h'のいずれかがあるか? */
    if ((c = strpbrk(s1, s2)) != NULL )
    {
       printf("'%c'は%d番目にありました.\n", *c, c - s1);
    }
    else
    {
       printf("'%c'はありませんでした.\n", *c);
    }
 
    return EXIT_SUCCESS;
 }



文字列から文字列を検索する

C言語で文字列から文字列を検索するには、string.hのstrstr関数を使用する。

strstr関数は、第1引数が指す文字列の最初から第2引数が指す文字列の文字の並びを検索する関数である。
strstr関数は、文字列が見つかった場合は探し出した文字列へのポインタを返し、文字列が見つからなかった場合はNULLを返す。
探し出した文字列へのポインタから検索対象の文字列の先頭アドレスを引くことで、指定した文字列が最初に現れる位置を求めることができる。

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 int main(void)
 {
    char s1[] = "abcdefgij";
    char s2[] = "def";
    char *ret;
 
    if ((ret = strstr(s1, s2)) != NULL )
    {
       printf("%sは%d番目にありました.\n", s2, ret - s1);
    }
    else
    {
       printf("%sはありませんでした.\n", s2);
    }
 
    return EXIT_SUCCESS;
 }



数値を文字列に変換する

C言語で数値を文字列に変換するには、stdio.hのsprintf関数またはsnprintf関数を使用する。

sprintf関数は、第2引数が指す書式文字列に従って第1引数が指す文字配列へ書き込む関数である。
なお、文字配列に書き込んだ文字列の後には'\0'が自動的に書き込まれる。

snprintf関数は、基本的にはsprintf関数と同じであるが、第2引数に最大文字数分を指定する。
(第2引数の値 - 1番目より後の出力文字は第1引数に書き込まずに破棄される)

sprintf関数とsnprintf関数は共に、第2引数が指す書式文字列はprintf関数と同様のフォーマットで指定する。
変換指定子に%dや%fを指定することで、数値から文字列に変換することができる。

 #include <stdio.h>
 #include <stdlib.h>
 
 #define N 256
 
 int main(void)
 {
    char s1[N] = {'\0'};
    char s2[N] = {'\0'};
    int i = 10000;
    double x = 200.123;
 
    sprintf(s1, "%d", i);
    snprintf(s2, N, "%.4f", x);
 
    fprintf(stdout, "s1: %s\n", s1);
    fprintf(stdout, "s2: %s\n", s2);
 
    return EXIT_SUCCESS;
 }



文字列中の小文字を大文字に変換する

C言語の標準ライブラリ関数の中には、アルファベットの小文字を大文字に変換するtoupper関数がある。
文字列を構成するすべての文字に対して、toupper関数を適応させれば文字列中のすべての小文字を大文字に変換することができる。
具体的には以下のように実装する。

 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
 
 #define N 256
 
 char *ToUpperString(char *s);
 
 int main(void)
 {
    char s[N] = {'\0'};
 
    /* 入力 */
    printf("文字列を入力してください.\n> ");
    scanf("%s", s);
 
    /* 比較 */
    ToUpperString(s);
    printf("変換後の文字列: %s\n", s);
 
    return EXIT_SUCCESS;
 }
 
 /* 文字列中の小文字を大文字に変換する        */
 /* @param[in,out] s 変換したい文字列         */
 /* @return 変換後の文字列 (s) の先頭アドレス */
 char *ToUpperString(char *s)
 {
    int i = 0;
 
    while ( s[i] != '\0' )
    {
       s[i] = toupper((unsigned char)s[i]);
       i++;
    }
 
    return s;
 }



文字列中の大文字を小文字に変換する

C言語の標準ライブラリ関数には、アルファベットの大文字を小文字に変換するtolower関数がある。
文字列を構成するすべての文字に対して、tolower関数を適応させれば文字列中のすべての大文字を小文字に変換することができる。
具体的には以下のように実装する。

 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
 
 #define N 256
 
 char *ToLowerString(char *s);
 
 int main(void)
 {
    char s[N] = {'\0'};
 
    /* 入力 */
    printf("文字列を入力してください.\n> ");
    scanf("%s", s);
 
    /* 比較 */
    ToLowerString(s);
    printf("変換後の文字列: %s\n", s);
 
    return EXIT_SUCCESS;
 }
 
 /* 文字列中の大文字を小文字に変換する        */
 /* @param[in,out] s 変換したい文字列         */
 /* @return 変換後の文字列sの先頭アドレス     */
 char *ToLowerString(char *s)
 {
    int i = 0;
 
    while ( s[i] != '\0' )
    {
       s[i] = tolower((unsigned char)s[i]);
       i++;
    }
 
    return s;
 }