Linux講座にようこそ。このページは「C言語プログラミング入門 - 第14章.ライブラリ関数 - 文字列処理ライブラリ」です。

C言語プログラミング入門

14. ライブラリ関数(14/36) - 文字列処理ライブラリ(3/5)

14.19 文字列の連結関数

14.19.1 strcat関数

strcat関数は2つの文字列を連結します。(第1引数で指定した文字列の後に、第2引数で指定した文字列を追加した形になります)使用する場合は次の点に注意してください。

  • 連結元と連結する文字列は重なっていないこと。
  • 連結元の文字列は連結後の文字列が全部入るだけの大きさがあること。
【表14-2-9】 strcat関数
形式#include <string.h>
char *strcat(char *dest, const char *src);
返り値第1引数destの先頭アドレスを返します。
引数
const char *dest
連結元の文字列を指定します。
const char *src
連結する文字列を指定します。

14.19.2 strncat関数

strncat関数は2つの文字列を連結します。strcat関数との相違は第3引数で連結する文字列の文字数を指定できることです。使用上の注意点もstrcat関数と同じです。

【表14-2-10】 strncat関数
形式#include <string.h>
char *strncat(char *dest, const char *src, size_t n);
返り値strcat関数と同じです。
引数
const char *dest
連結元の文字列を指定します。
const char *src
連結する文字列を指定します。
size_t n
連結する文字列の文字数を指定します。

14.19.3 例題

任意の数のメッセージを入力して、入力し終わったら表示します。メッセージの入力は「end」が入力されるか、10個入力されるまで続きます。入力したメッセージは文字列に蓄積しておき、入力し終わった時点で表示します。

  1. #include <stdio.h>
  2. #include <string.h>
  3. #define BUFF_SIZE   4096
  4. #define LINE_MAX    1024
  5. #define MESSAGE_MAX 10
  6.  
  7. int main(void)
  8. {
  9.     char    buff[BUFF_SIZE];        /* メッセージ格納用文字列 */
  10.     char    line[LINE_MAX];
  11.     int     message_cnt;
  12.  
  13.     /* メッセージ格納用文字列を空にする */
  14.     buff[0] = '\0';
  15.     for(message_cnt = 0; message_cnt < MESSAGE_MAX; ++message_cnt)
  16.     {
  17.         printf("メッセージを入力してください ==> ");
  18.         fgets(line, LINE_MAX, stdin);
  19.         if(strncmp(line, "end", 3))
  20.         {
  21.             /* 入力メッセージがメッセージ格納用文字列に収まるかをチェック */
  22.             if((BUFF_SIZE - strlen(buff) - 1) >= strlen(line))
  23.             {
  24.                 strcat(buff, line);
  25.             }
  26.             else
  27.             {
  28.                 printf("メッセージが長すぎて、これ以上入力出来ません。\n");
  29.                 break;
  30.             }
  31.         }
  32.         else
  33.         {
  34.             break;
  35.         }
  36.     }
  37.  
  38.     printf("\n入力したメッセージを表示します。\n");
  39.     printf("%s", buff);
  40.  
  41.     return 0;
  42. }
$ ./ex14_2_4.prg
メッセージを入力してください ==> Hi.
メッセージを入力してください ==> Hello!
メッセージを入力してください ==> Bye.
メッセージを入力してください ==> Bye bye.
メッセージを入力してください ==> end

入力したメッセージを表示します。
Hi.
Hello!
Bye.
Bye bye.
$
24行目
入力したメッセージをメッセージ格納用文字列のbuffに連結します。これにより、入力したメッセージは全てbuffに蓄積されます。

14.20 文字及び、文字列の検索関数

14.20.1 strchr関数

strchr関数は文字列から指定された文字を検索して、その位置を結果として返します。指定された文字が複数あった場合は最初に現れた文字の位置を返します。

【表14-2-11】 strchr関数
形式#include <string.h>
char *strchr(const char *str, int c);
返り値探し出した文字のアドレスを返します。探し出せなかった場合はNULLを返します。
引数
const char *str
検索対象文字列を指定します。
int c
検索する文字を指定します。

14.20.2 strrchr関数

strrchr関数は文字列から指定された文字を検索して、その位置を結果として返します。strchr関数との相違は指定された文字が複数あった場合は最後に現れた文字の位置を返します。

【表14-2-12】 strrchr関数
形式#include <string.h>
char *strrchr(const char *s, int c);
返り値strchr関数と同じです。
引数
const char *str
検索対象文字列を指定します。
int c
検索する文字を指定します。

14.20.3 strstr関数

strstr関数は文字列から指定された文字列を検索して、その位置を結果として返します。指定された文字列が複数あった場合は最初に現れた文字列の位置を返します。

【表14-2-13】 strstr関数
形式#include <string.h>
char *strstr(const char *haystack, const char *needle);
返り値探し出した文字列のアドレスを返します。探し出せなかった場合はNULLを返します。
引数
const char *haystack
検索対象文字列を指定します。
const char *needle
検索する文字列を指定します。

14.20.4 memchr関数

memchr関数はメモリ領域の指定された範囲内から指定された文字を検索して、その位置を結果として返します。

【表14-2-14】 memchr関数
形式#include <string.h>
void *memchr(const void *mem, int c, size_t n);
返り値探し出した文字のアドレスを返します。探し出せなかった場合はNULLを返します。
引数
const void *mem
検索対象の領域を指定します。
int c
検索する文字を指定します。
size_t n
検索範囲(第1引数memの長さ)をバイト単位で指定します。

14.20.5 例題

実行時引数で指定したテキストファイル中のタブ文字を半角スペースに置換して表示します。

  1. #include <stdio.h>
  2. #include <string.h>
  3. #define LINE_MAX    1024
  4.  
  5. int main(int argc, char **argv)
  6. {
  7.     FILE    *fp;
  8.     char    line[LINE_MAX];
  9.     char    *line_p;
  10.  
  11.     if(argc != 2)
  12.     {
  13.         printf("実行時引数が不当です。\n");
  14.         return 1;
  15.     }
  16.  
  17.     if((fp = fopen(*(argv + 1), "r")) == NULL)
  18.     {
  19.         printf("%sがオープンできません。\n", *(argv + 1));
  20.         return 1;
  21.     }
  22.  
  23.     /* 実行時引数で指定されたファイルを入力 */
  24.     while(fgets(line, LINE_MAX, fp) != NULL)
  25.     {
  26.         line_p = line;
  27.         while((line_p = strchr(line_p, '\t')) != NULL)
  28.         {
  29.             /* タブ文字をスペースに置換 */
  30.             *line_p = ' ';
  31.             ++line_p;
  32.         }
  33.         /* 置換後の1行を出力 */
  34.         printf("%s", line);
  35.     }
  36.  
  37.     fclose(fp);
  38.  
  39.     return 0;
  40. }
$ cat -t ./DATA/ex14_2_5.dat ← -tはタブ文字を表示するオプションです。
main()
{
^Ishort^Ibango^I=^I12; ← ^Tはタブ文字を表します。
^Iint^Inenrei;
^Ifloat^Itaijyu^I=^I65.5;
^Idouble^Isintyo;
^Ichar^Iketueki^I=^I'A';
}
$
$ ./ex14_2_5.prg ./DATA/ex14_2_5.dat
main()
{
 short bango = 12;
 int nenrei;
 float taijyu = 65.5;
 double sintyo;
 char ketueki = 'A';
}
$
27行目
入力した行データ中からタブ文字('\t')を探して結果を変数line_pに求めます。
30行目
探しだしたタブ文字を半角スペース(' ')に置換します。

14.21 文字列から字句を取り出す関数

14.21.1 strtok関数

strtok関数は文字列中の区切り文字で区切られた字句(項目)を取り出します。例えば、CSV形式のテキストファイルから各項目を取り出すような時に使用すると便利です。ただし、使い方が少し複雑で次のような使用手順になります。

  1. 最初の呼び出しの時には2つの引数(解析対象文字列と区切り文字列)を指定します。これにより、解析対象文字列の解析を行うと共に、返り値として最初の項目の値が返ってきます。
  2. 2回目以降の呼び出し時には第1引数(解析対象文字列)にはNULLを指定します。これにより、返り値として次の項目の値が返ってきます。
  3. 返り値としてNULLが返ってきたら全ての項目を取り出したことになります。

なお、解析対象文字列の先頭や末尾にある区切り文字は無視し、2つ以上の区切り文字が連続している場合には1つの区切り文字とみなします。

【表14-2-15】 strtok関数
形式#include <string.h>
char *strtok(char *str, const char *delim);
返り値取り出した項目の先頭アドレスを返します。取り出す項目がない場合はNULLを返します。
引数
char *str
解析対象文字列を指定します。ただし、2回目以降の呼び出し時にはNULLを指定します。
const char *delim
区切り文字を文字列として指定します。複数の区切り文字を指定できます。

14.21.2 例題

下記のような,(コンマ)で区切って、番号・名前・体重・身長・血液型のデータが登録されているex14_2_6.datファイルを入力して標準出力に出力します。なお、各項目の最大文字数はヌル文字を含めて21文字とします。

このデータの場合、名前は半角スペースを含んでいますし血液型は省略可能ですので、scanf関数で入力するのは難しいため、ここではfgets関数で1行入力後、strtok関数で各項目を取り出しています。

1,Merry Husky,67,188,A
2,Kuma Mix,98,176.5
3,Hana Shiba,43.2,156.5,AB
4,ken Mix,55.5,167.5
5,Taro Bull,75.7,166.5,A
  1. #include <stdio.h>
  2. #include <string.h>
  3. #define LINE_MAX    1024
  4. #define ITEM_MAX    5
  5.  
  6. int main(void)
  7. {
  8.     FILE    *fp;
  9.     char    in_file[] = "./DATA/ex14_2_6.dat";
  10.     char    line[LINE_MAX];
  11.     char    format[] = "%-4s %-20s %-8s %-8s %s\n";
  12.     char    delmit[] = ",\n";        /* 項目の区切り */
  13.     char    item[ITEM_MAX][21];       /* 取り出した項目の格納用 */
  14.     char    *item_p;
  15.     int     item_idx;
  16.  
  17.     if((fp = fopen(in_file, "r")) != NULL)
  18.     {
  19.         printf(format, "No.", "NAME", "WEIGHT", "HEIGHT", "BLOOD");
  20.         /* EOFでない間、繰り返す */
  21.         while(fgets(line, LINE_MAX, fp) != NULL)
  22.         {
  23.             /* 最初の項目取り出し */
  24.             if((item_p = strtok(line, delmit)) != NULL)
  25.             {
  26.                 strcpy(&item[0][0], item_p);
  27.  
  28.                 for(item_idx = 1; item_idx < ITEM_MAX; ++item_idx)
  29.                 {
  30.                     /* 2個目以降の項目取り出し */
  31.                     if((item_p = strtok(NULL, delmit)) != NULL)
  32.                     {
  33.                         strcpy(&item[item_idx][0], item_p);
  34.                     }
  35.                     else
  36.                     {
  37.                         item[item_idx][0] = '\0';        /* 項目なし */
  38.                     }
  39.                 }
  40.  
  41.                 printf(format,
  42.                     &item[0][0], &item[1][0], &item[2][0], &item[3][0], &item[4][0]);
  43.             }
  44.         }
  45.         fclose(fp);
  46.     }
  47.     else
  48.     {
  49.         printf("%sがオープン出来ませんでした。", in_file);
  50.     }
  51.  
  52.     return 0;
  53. }
$ ./ex14_2_6.prg
No.  NAME                 WEIGHT   HEIGHT   BLOOD
1    Merry Husky          67       188      A
2    Kuma Mix             98       176.5
3    Hana Shiba           43.2     156.5    AB
4    ken Mix              55.5     167.5
5    Taro Bull            75.7     166.5    A
$
12行目
項目の区切り文字を格納しておくための配列を宣言します。内容は,(コンマ)と改行('\n')です。
13行目
strtok関数で取り出した項目を格納しておくための配列を宣言します。5行21列の二次元配列です
24行目
最初の項目取り出しのためのstrtok関数の呼び出しです。項目がなかった(返り値がNULL)場合は直ちに次の行を入力します。
31行目
2個目以降の項目取り出しのためのstrtok関数の呼び出しです。項目がなかった場合は項目として空文字列('\0'だけの文字列)を格納しておきます。