Index

HOME > プログラムTOP > C++



C++の壺・文字列篇

 C++の基本テクニックのTipsです。C/C++の文字列の扱いはやや特殊ですが、慣れると非常に便利です。文字列篇では、文字列のしくみや、最も基本的な四つの標準関数の原理と使い方を扱っていきます。
[index] 文字列のしくみ ... C文字列の特徴と構造
strlen関数 ... 文字列の長さをはかる
strcpy関数 ... 文字列はコピーして代入
strcat関数 ... 文字列を結合する
strcmp関数 ... 文字列を比較する

sasaraan programming

Exposition

●文字列のしくみ

 文字列 (string) は、文字 (char) の配列からなります。そして、C/C++ では、文字列はヌル文字(\0)で終了する決まりがあります。これは実際には表示されない文字ですが、文字列の終わりを検知したりするために必要な文字です。通常、文字列として記述する時 ( " " ) は暗黙的にヌル文字は追加されますが、配列として扱う時は記述が必要です。ちなみに、文字列の変数名に "sz" (string - zero) という接頭辞が使われるのはこのためです。
文字列 "Hello World !"(末尾に\0が付加)
文字の配列Hello_World_!\0 ( _ は半角空白)
 文字列の初期化は、宣言と同時に行うことができます。この時、ヌル文字を考慮に入れて、格納する文字数+1の要素数を設定する必要があります。
 ただし、文字列は、計算式のように直接代入することはできません。これは他の型の配列と同様で、あくまでも配列の扱いとなります。この時は、一つ一つの要素(文字)に代入していく必要があります。
char sz1[] = "Hello";                      // 文字列として初期化(要素数指定時は sz1[6])
char sz2[] = {'H', 'e', 'l', 'l', 'o', '\0',};  // 要素として初期化(要素数指定時は sz2[6])
sz3 = "World";                              // 直接の代入は不可
sz1[0] = 'W'                                  // 代入は各要素に対して行う
sz1[1] = 'o';
sz1[2] = 'r';
sz1[3] = 'l';
sz1[4] = 'd';
sz1[5] = '\0';	
 配列はポインタとして扱うことができますので、文字列も以下のように記述することも可能です。他の型と同じように、配列の変数名は、先頭要素のアドレスを表します。
char *sz_1 = "Hello";       // ポインタとして宣言、同時に初期化
char *sz_2;                     // ポインタの宣言
char sz_3[]  = "World";    // 配列として宣言
sz_2 = sz_3;                    // ポインタに先頭要素のアドレスを代入
 文字列の処理には、いくつもの便利な関数が用意されています。以下に最も基本的な四つの関数を挙げておきます。原理さえ分かればいずれも簡単に自作できるので、チェック機能を強化したいときなど必要に応じて用意するとよいでしょう。

●strlen関数

 strlen関数を使うと、文字列の長さを取得することができます。文字列の末端は \0 であるという決まりがありますので、\0 を目当てに文字を数えていきます。この時、通常では2バイト文字は長さ2となります。また、末尾のヌル文字は数に入らないので注意が必要です。
strlen function
・書式size_t strlen( const char *str );
・機能文字列の長さを取得する
・引数string ... 対象文字列
・戻り値対象文字列の文字数 (末端の \0 は含まない)
・要件string.h のインクルード
 戻り値のデータ型 size_t は sizeof演算子の結果を表します。通常は unsigned int型 ですが、上限値をオーバーする心配がなければ、int型として扱っても問題ありません。
文字列Hello_World_!\0( _ は半角空白)
カウント12345678910111213_(=13, \0は数えない)
#include <stdio.h>   // printf使用
#include <string.h>  // strlen使用
#include <conio.h>  // getch使用

int main() 
{
    char s[] = "Hello World !";
    int n = strlen(s);     // =13
    printf("%d\n", n);    // 出力
    if (getch()) return 0;
} 
// strlen関数の動作イメージ
int strlen_ex(char *str)
{
    int n = 0;          // 文字数

    // *strが\0でない間、ループ
    while (*str++) { 
        n++;             // カウント
    }
    return n;
} 

●strcpy関数

 文字列を代入する時、一要素(一文字)づつ代入していくのは大変な作業となります。strcpy関数を使うと、簡単に変数に文字列をセットすることができます。この時、末端の \0 を検知するまでコピーは行われます。また、文字数オーバー(オーバーフロー)のチェックはしないので注意が必要です。
strcpy function
・書式char *strcpy( char *str1, const char *str2 );
・機能文字列を他の文字列にコピーする
・引数str1...コピー先の文字列、 str2...コピー元の文字列
・戻り値コピー先の文字列へのポインタ (コピー時は末端の \0 を含む)
・要件string.h のインクルード
コピー先(\0の所までコピー)
コピー元Hello_World_!\0( _ は半角空白)
#include <stdio.h>   // printf使用
#include <string.h>  // strcpy使用
#include <conio.h>  // getch使用

int main() 
{
    char s1[30];
    char *s2 = "Hello World !";
    strcpy(s1, s2);          // コピー
    printf("%s1\n", s1);  // "Hello World !"
    if (getch()) return 0;
} 
// strcpy関数の動作イメージ
char *strcpy_ex(char *str1, char *str2) 
{
    // *str2が\0になるまで要素をコピー
    do {
        *str1++ = *str2; 
    } while (*str2++);

    return str1;
} 

●strcat関数

 文字列は演算(+)による文字列の結合ができません。通常は配列の要素ごとに一つづつ追加していく必要がありますが、strcat関数を使うと簡単に二つの文字列を連結できます。この時、追加先の末端の \0 は上書きされて消滅します。そのかわり、追加後の文字列の末端に、暗黙的に \0 が付加されます。
strcat function
・書式char *strcat( char *str1, const char *str2 );
・機能文字列を連結する
・引数str1...追加先の文字列、 str2...追加する文字列
・戻り値追加後の文字列へのポインタ (追加時に末端に \0 を付加)
・要件string.h のインクルード
 また、この関数は追加先の容量をチェックしません。追加先の文字列の容量を十分に確保して、文字数オーバー(オーバーフロー)に気を配る必要があります。
追加先Hello_\0_______(\0の所から開始)
追加元World_!\0(\0の所まで追加)
#include <stdio.h>   // printf使用
#include <string.h>  // strcat使用
#include <conio.h>  // getch使用

int main() 
{
    char s1[30] = "Hello ";
    char *s2 = "World !";
    strcat(s1, s2);          // 連結
    printf("%s1\n", s1);  // "Hello World !"
    if (getch()) return 0;
} 
// strcat関数の動作イメージ
char *strcat_ex(char *str1, char *str2) 
{
    // str1の末尾(\0)へ移動
    while (*str1) *str1++;

    // *str2が\0になるまで要素をコピー
    do 
    {
        *str1++ = *str2;
    } while (*str2++);
    return str1;
}	

●strcmp関数

 文字列を並べ替えるときなどは比較が必要となります。strcmp関数を使うと、簡単に二つの文字列を比較することができます。この時、先頭から一文字づつ比較を進めていき、文字コードに差が出た段階で、算出した差を返します。ただし、両者が同時に末端の \0 に至った時は同じ文字列ということになり、0を返します。
strcmp func
・書式int strcmp( const char *str1, const char *str2 );
・機能文字列を比較する
・引数str1...比較元の文字列、 str2...比較先の文字列
・戻り値 正の値 : str1 > str2 (str2が前、str1が後ろ)
 0  : str1 == str2 (両者は同じ文字列)
負の値 : str1 < str2 (str1が前、str2が後ろ)
・要件string.h のインクルード
 文字の比較は、使用している文字コード順に応じて行われます。コードが小さい方が前、大きい方が後ろ側に配置されていることを表します。また、文字コード順ですので、大文字と小文字を区別します。区別させない時は、tolower や toupper 関数などで大文字または小文字に統一させてから比較する必要があります。
#include <stdio.h>   // printf使用
#include <string.h>  // strcmp使用
#include <conio.h>  // getch使用

int main() 
{
    char *s1 = "Hello1";
    char *s2 = "Hello2";
    int n;
    n = strcmp(s1, s2);    // 比較
    printf("%d\n", n);      // =-1
    if (getch()) return 0;
} 
// strcmp関数の動作イメージ
int strcmp_ex(char *str1, char *str2) 
{
    int n = 0;
    // 先頭から一文字づつ比較
    while (*str1 || *str2) {
        n = *str1 - *str2; // 文字コードの差
        if (n) break;          // 0以外なら抜ける
        if (*str1) *str1++; // \0以外なら次へ
        if (*str2) *str2++; // \0以外なら次へ
    }
    return n;
}	

www.sasaraan.net

(c) morijoh