C言語覚書 (文字列)

2013/03/26


◆ 文字列の扱い

C言語には文字列の変数は存在しないらしい。初めは BASIC で当たり前のように文字列変数を使っていたので戸惑っていました。 

文字型の変数 char型は 1byte の変数で、char型の配列を文字列として扱います。宣言された配列数以内の文字を1文字ごと配列に格納します。気をつけなければならないのは、文字の終了コード \0 が最後に必要になるので、文字数+1の配列を宣言しなければいけません。


◆ 配列の宣言

 char text1[] = "hello world.";  // 変数宣言時の代入では配列要素数を省略可
 char text2[9];  // 8文字分確保

 text2 = "world";  // 宣言時以外では文字列の代入はエラーになる。
 text2[0] = 'w';  // 一文字ずつ代入
 text2[1] = 'o';
 text2[2] = 'r';
 text2[3] = 'l';
 text2[4] = 'd';
 text2[5] = \0;

◆ 文字列のコピー (strcpy,strncpy)

 #include <string.h>

 main() {
   char txt1[] = "abc";
   char *s;

   s = "efg";

   strcpy(txt1, s);  // strcpy(コピー先,コピー元)
 }

 txt1 = "efg"
   strncpy(txt1, s, 2);  // strncpy(コピー先,コピー元,文字数)

 txt1 = "efc" ← 2文字分上書きされる。

◆ 文字列の連結 (strcat,strncat)

 #include <string.h>

 main() {
   char txt1[] = "abc";
   char *s;

   s = "efg";

   strcat(txt1, s);  // strcat(連結先,コピー元)
 }

 txt1 = "abcefg"
   strncat(txt1,s,2);  // strncat(連結先,コピー元,文字数)

 txt1 = "abcef" ← 2文字分連結される。 

◆ 文字列の長さを調べる  (strlen)

 #include <string.h>

 main() {
   char txt1[] = "abc";
   int i;

   i = strlen(txt1);  // strlen(変数) 戻り値に \0 は含まれない
 }

 i = 3

◆ 文字列を分割する  (strtok)

  #include <string.h>

 main() {
   char txt1[] = "5,namae,tutomesaki";
   char *num, *name, *kaisya, *nokori;

   num    = strtok(txt1, ",");  // strtok(分割元,区切り文字)
   name   = strtok(NULL, ",");  // NULLは上記で分割された残りを示す
   kaisya = strtok(NULL, ",");  // 置き換える対象がない場合残りの文字列を返す
   nokori = strtok(NULL, ",");  // 返す文字がないときは NULL を返す

 }

 num = 5
 name = namae
 kaisya = tutomesaki
 変数の状態を命令毎に見てみると
 char txt1[] = "5,namae,tutomesaki";  txt1 = "5,namae,tutomesaki\0"

 num = strtok(txt1, ",");
   txt1 = "5\0namae,tutomesaki\0"
   num はポインタなので5のアドレスを示す。
   5以降の\0までが文字列と解釈される。
   この時 NULL ポインタには \0 の後ろの n を示す。
 
 name = strtok(NULL, ",");
   txt1 = "5\0namae\0tutomesaki\0"
   name は3文字目の n のアドレスを示す。
   n 以降の\0までが文字列と解釈される。
   この時 NULL ポインタには name\0 の後ろの t を示す。

 kaisya = strtok(NULL, ",");
   txt1 = "5\0namae\0tutomesaki\0"
   "," がもうないので残りの文字列を返す。
   kaisya は9文字目の t のアドレスを示す。

   t 以降の\0までが文字列と解釈される。
   この時 NULL ポインタには 示すものがないので NULL が入る。

 nokori = strtok(NULL, ",");
   NULL ポインタは NULL を示しているので戻り値は NULL となる。

◆ 文字列内の文字を検索する  (strstr)

 #include <string.h>

 main() {
   char txt1[] = "5,namae,tutomesaki";
   char *kaisya;

   kaisya = strstr(txt1,"tutomesaki");  // strlen(文字列,検索文字)
 }

 kaisya は tutomesaki の tの位置のアドレスを示す。
 excel や BASIC の様に○文字目の番号を返すわけではない。

◆ 文字列から数値への変換

 #include <stdlib.h>

 // int型の変換
 char txt[] = "12";
 int i;

 i = atoi(txt);  // atoi(文字列) i = 12

 // long型の変換
 char txt[] = "12345";
 long l;

 l = atol(txt);  // atol(文字列) l = 12345

 // double型の変換
 char txt[] = "123.45";
 double d;

 d = atof(txt);  // atof(文字列) d = 123.45

 // double型の変換 数値以外の文字が含まれている場合
 // atof では数値以外の文字がある場合には変換できない。

 char txt[] = "123.45a";
 double d;

 d = strtod(txt, NULL);  // strtod(文字列, 変換不能文字の先頭アドレス)
 d = 123.45
 NULL は a のアドレスを示す


◆ 数値から文字列への変換 (sscanf,sprintf)

自分的に最もC言語に関して検索する機会の多い命令です。 LCD等のディスプレイに表示できるのはasciiコードで示される文字なので数値の出力は存在せず、必ず文字にして表示しなければならない。

sscanf,sprintf の使い方よりも次項の書式文字列が重要となる

ちなみに sscanf は文字列からの入力を変数に代入する。 また printf は文字列を変数へ出力かの違いで、結果的に同じ動作となる。

 #include <stdio.h>

 // sscanf(変換後の文字列,書式文字列,数値)
 // sprint(変換後の文字列,書式文字列,数値)

 char str[] = "Answer=";
 char txt[40];
 int i = 12;

 sscanf(txt, "[%s%id]", str, i);

 txt = "[Answer=12]"

◆ 書式文字列 (書式指定子)

書式指定子は printf や scanf 等で使用され、その組み合わせで様々な表現ができる。

%[フラグ][フィールドサイズ][品数サイズ]変換文字 ※[]内は省略可、%,変換文字は必須

記号 変換文字
o   8進数で出力
d , i  10進数で出力 
x , X  16進数で出力、x だと小文字 X だと大文字
u  符号なし10進数で出力 
c  文字で出力 
s  文字列で出力 
f  浮動小数点で出力。標準で6桁 
e , E  指数形式で出力、e だと小文字 E だと大文字 
%  %%で % 自体を出力 

 

記号 フラグ
-   フィールド幅を指定したとき、空白を左に詰めて出力
+  +の場合、+を付けて出力 
(空白)  +の場合、空白を付けてマイナスの場合と数値の始まり位置を揃える
0 フィールド幅を指定したとき空白にあたる部分をゼロで埋める
#o  8進数の出力時、先頭にoを付ける 
#x, #X   16進数の出力時、先頭にx(X)を付ける

 

記号 フィールド幅
数値   出力の文字数を指定する。
 出力の桁が指定値に満たない場合には左を空白で埋める(右寄せ)
 出力の桁が指定値より大きい場合は指定値は無視され、出力の桁数となる。
 小数点ある場合には、小数点も一文字と数える。

書式文字列の例

 #include <stdio.h>

 char txt1[] = "X =";
 char txt2[] = "Y =";
 char tmp[20];

 double x = 12.3456;
 double y = -5.2269;

 sscanf(tmp, " %s%-11.3f ", txt1, x);
     %s で文字列 txt1
     %11.4f で x の値を 小数点以下3桁で小数点以下を含む11文字で右詰め
     [ X =      12.346 ] 指定桁で四捨五入される。

◆ 文字のチェック

 #include <ctype.h>

 isalpha('a');  // アルファベットでなければ0を返す。
 isdigit('a');  // 数値なければ0を返す。
 isalnum('a');  // 数値またはアルファベットでなければ0を返す。
 isupper('a');  // 大文字でなければ0を返す。
 islower('a');  // 小文字でなければ0を返す。
 issdigit('a'); // 16進数でなければ0を返す。
 isspace('a');  // 空白文字でなければ0を返す。
 ispunct('a');  // 区切り文字でなければ0を返す。
 iscntrl('a');  // 制御文字でなければ0を返す。

 tolower('a');  // 小文字に変換して返す、変換できなければそのまま返す。
 toupper('a');  // 大文字に変換して返す、変換できなければそのまま返す。