最近更新したページ
2013-10-20
2013-09-29
2013-09-23
2012-01-07
2011-11-09
2011-10-23
2011-10-09
2011-10-01
2011-09-29
2011-09-03
2011-08-07
2011-08-02
2011-07-29
2011-07-10
2011-05-05
2011-05-04
2011-04-24
2011-04-13
2011-04-05
2011-03-26
2011-02-18
2011-02-15
2010-12-26
2010-12-07
2010-12-05
2010-11-23
2010-09-28
2010-09-23
2010-08-26
2010-08-22
2010-07-16
2010-01-17
2010-01-11
2009-10-04
2009-08-21
2009-08-13
2009-06-18
2009-06-01
2009-04-29
2009-02-16
2009-02-11
2009-02-03
2008-07-22
2008-07-21
2008-07-15
2008-07-14
2008-07-13
2008-07-12
2008-07-08
2008-07-05
2008-06-28
2008-06-17
2008-06-05
2008-06-02
2008-06-01
2008-05-29
2008-05-26
2008-05-21
2008-05-19
2008-05-18
2007-10-31
2007-10-27
2007-09-28
2007-09-23
2007-09-17
2007-09-16
2007-09-14
2007-09-11
2007-06-18
2007-04-15
2006-12-21
2006-11-30
2006-11-22
2006-08-17
2006-03-29
2006-03-28
2006-03-27

C/C++ 文字列処理


C/C++ 文字列処理


 C言語の文字列処理は、char Array[] 等の文字配列とポインタを使用した面倒な物である。
 C++ では <string> ライブラリ が追加され、文字列をあたかも「string」型が追加された如く簡単に処理できる。

※<string>は、printf / sprintf 等書式指定子 %s / %c で表示不可。C/C++混在時要注意。

C言語の文字配列とポインタ


char型 と文字列


文字列:cat
文字:'c','a','t'

■配列に拠る文字列
char str[] = {'c','a','t','\0'};
// char str[] = "cat";    ・・・ でも良い。
printf("%c%c%c \n",str[0],str[1],str[2]);
// printf("%s \n",str);   ・・・ とすれば文字列が表示される。
・・・といった連続した文字を扱うことで文字列処理を実現している。

■ポインタに拠る文字列
char *p;
p = "cat";
printf(p);             
// printf("%s \n",str);   ・・・ とすれば文字列が表示される。
void main(void) {
   char *p;
   p="cat";
   printf("%s \n",p);   // 文字列 "cat" を表示する
   printf("%x \n",*p);  // 63 を表示
   printf("%x \n",&p);  // 12ff60 を表示(多分利用事に異なると思われる)
}

・・・といった連続した文字を扱うことで文字列処理を実現している。


C言語には、文字列の概念が原則無いため、

▲上へ

C++ の文字列処理


std::string と、printf();

 printf の書式 %s と string型は互換性無し。stringクラス メンバ関数 s.str() を使用し、char型へ 型変換(?)して表示可能とする。
 (char)string型 とかしても期待値は返らない。便宜上 string型と書きはするが、型ではなくクラスである。厳密には型でない。(詳細 STL 知識要)

sample1:std::string と printf()
#include <iostream>
#include <string>
void main(void) {
   std::string str1="C++";
   printf("%s \n",str1);         // (null) が返る。
   printf("%s \n",str1.c_str()); // 期待値が返る。
}
※c_str() で型変換しないと、(null)が表示され、期待値とならない。
※c_str() は C言語対応の char* 型文字列ポインタ値を返す。
※STL map<int,string>::iterator itr; (itr->second).c_str(); → イタレータで動作確認済。

▲上へ

std::string str(); の利用


sample1:C++ string の別の使い方
#include <iostream>
#include <string>
using namespace std;

void main(void) {
   string s = "東京特許許可局"; // これでも動く!
   string s1(3,'c');
   string s2("Use of string of C++ is various.");
   string s3(s2,17,3);
   cout << s  << endl;
   cout << s1 << endl;
   cout << s2 << endl;
   cout << s3 << endl;
}
・・・このように・・・すると以下のように表示される。
東京特許許可局
ccc
Use of string of C++ is various.
C++
・・・非常に機能が高いようである・・・

▲上へ

文字列の比較


sample1:C++ による文字列の比較
std::string StrTrue  = "は なき声が同じだぁ!";
std::string StrFalse = " は なき声が違うョ!";
std::string str1 = "わん" , str2 = "ニャン" , str3 = "わん";
if (str1==str2) {
   cout << str1 << " と " << str2 + StrTrue << endl;
} else if (str1!=str2) {
   cout << str1 << " と " << str2 + StrFalse << endl;
} else {
   cout << "Err 1" << endl;
}
if (str1==str3) {
   cout << str1 << " と " << str3 + StrTrue << endl;
} else if (str1!=str3) {
   cout << str1 << " と " << str3 + StrFalse << endl;
} else {
   cout << "Err 2" << endl;
}
if (str2==str3) {
   cout << str2 << " と " << str3 + StrTrue << endl;
} else if (str2!=str3) {
   cout << str2 << " と " << str3 + StrFalse << endl;
} else {
   cout << "Err 3" << endl;
}
※冗長となったが、これも直感的コーディングが可能。
※全くポインタを使わなくて良くなっている・・・が、メモリ開放はどのようになってるのだろう?(不明)

sample2:C言語 strcmp(str1,str2) による文字列比較
#include <iostream>
//#include <string>
using namespace std;

void main(void) {
   char str1[] = "わん" , str2[] = "ピョ";
   // strcmp() は、一致で 0 を返し、文字の大小関係で -1 or 1 を返す。
   if (strcmp(str1,str2)==0) {
      printf("%s と %s は、鳴声が同じ\n",str1,str2);
   } else if (strcmp(str1,str2)!=0) {
      printf("%s と %s は、鳴声が違う\n",str1,str2);
   }
}
※文字列の長さ(空白の有無)も異なると違う文字として処理する。不要な全角半角空白は事前に処理しておかないと、意図した動作をしない可能性が高くなる。

▲上へ

文字列の連結


sample1:C++ による文字列連結と代入
std::string str1 = "わん" , str2 = "ニャン" , str3;
// 文字列変数の連結と代入
str3 = str1 + str1 + str2 + str2 + str1 + str2 + str2;
cout << str3 << endl;
※笑!配列の長さなど考慮する必要なし。

sample2:C言語 strcat(str1,str2) による文字列連結
char str1[10+1]="わん",str2[]="にゃん";
printf("str1=""%s"" str2=""%s""\n",str1,str2);
strcat(str1,str2);
printf("strcat(str1,str2)=""%s""\n",str1);
※泣!配列の長さなど考慮しないと実行時エラー。

sample3:C言語 strcat() による文字列の連結::その2
010:#include <iostream>
020://#include <string>
030://using namespace std;  cout,cin,string など使用無→不要
040:
050:void main(void) {
060:   char str1[30+1]="わん";
070:   char str2[]={'n','y','-','g','o','\0'};
080:   char *p="ピョピョ";
090:   printf("str1=%s str2=%s p=%s \n",str1,str2,p);
100:   strcat(str1,str2);
110:   printf("strcat(str1,str2)=%s \n",str1);
120:   strcat(str1,p);
130:   printf("strcat(str1,p)=%s \n",str1);
140:   strcat(str1,"ヒヒーン");
150:   printf("strcat(str1,string)=%s \n",str1);
160:}
※C++ 開発環境内で VB の ReDim のような配列サイズ変更はかなり難しいらしい。配列用途を考えてサイズを決定する必要がある。
※070:行のように文字単位で初期化可能だが、最後に \0 を追加する必要あり。"****" での代入では自動で行っている。
※配列の変わりに *p(ポインタ)利用も可能。
※動的配列長再定義は困難!ということ。

▲上へ

文字列の代入処理


sample1:C++ による文字列代入例
// c++ string を使用する
std::string str1 = "わんわん";
std::string str2 = "ニャンニャン";
cout << "犬は " << str1 << "、猫は " << str2 << "。" << endl;
// 文字列変数への代入処理
std::string tmpStr;
tmpStr = str1;
str1   = str2;
str2   = tmpStr;
cout << "犬は " << str1 << "、猫は " << str2 << "。" << endl;
※他の数値変数、他言語と同じように代入可能である。

sample1:C言語にによる文字列配列の代入(コピー)
#include <iostream>
//#include <string>
using namespace std;

void main(void) {
   char str1[]="わんわんわん", str2[]= "にゃんにゃん";
   char tmpStr[12+1];
   strcpy(tmpStr,str1);
   strcpy(str1,  str2);
   strcpy(str2,  tmpStr);
   printf("犬は %s 猫は %s 。\n",str1,str2);
}
※str1[],str2[] の配列数は、文字の byte数+1 となる。tmpStr[] のサイズも代入される文字 byte数+1 にしないと実行時エラーが発生する。

▲上へ

文字列処理の基本


sample1:C++ basic_string class を利用した文字列処理
#include <iostream>
#include <string>
using namespace std;
// using namespace std; を指定してれば std:: は不要である。
oid main(void) {
   std::string str1 = "bow bow";
   std::string str2 = "niya-go";
   cout << "犬は " << Str1 << "、猫は " << str2 << "。" << endl;
}
※全く普通に文字列処理が出来る。(・・・ように見えている・・・)
※今更気づいたが、using namespace std; を指定してるので std::string でなく、string のみで問題無い。cout,cin も本来、std::cout , std::cin となる文法のようである。

C言語では、同じことを行う場合、以下のようになる。
sample2:C言語の配列を利用した文字列処理
※#include <string> 又は、<string.h> が無くても動くようであるが、どっちか入れて置いたほうが無難な感じ。
#include <iostream>
using namespace std;
void main(void) {
   char str1[10];             // char str1[]="bow bow"; で初期設定可。
   char str2[10];             // char str2[]="niya-go"; で初期設定可。
   strcpy(str1,"bow bow");    // strcpy(str1,str2); で配列コピー可。
   strcpy(str2,"niya-go");    // str1 = str2; で配列コピーは出来ないので注意
   printf("犬は %s 猫は %s 。\n",str1,str2);
   // cout << "犬は " << Str1 << "、猫は " << str2 << "。" << endl; でも ok.
}
※この場合、何れも文字配列の長さが固定となる。指定配列数を超えた文字代入を行うと、デバックエラーは出ず、実行時エラーが発生する。文字列長取得と ReDem など配列長を代入文字列に合わせ再調整する必要がある。または、文字入力数チェック、制限文字数内での運用とするのも一つの手。


C++ string型利用要件
#include <string> を追加する。
std 名前空間を使って string 型指定。

※string str = "bow bow"; と std:: 名前空間省略でも VC++2005 では動く。(ただし、複数名前空間併用時の不具合発生を考慮すれば、省略しないが吉である。)
※#include <string> は追加しないとエラー。
※std::string での、日本語、半角カタカナ、ANK など適当に混在させても取り合えず問題発生はしなかった。

string は、 C++ の標準クラスに含まれるライブラリで実現とのことで、ほぼ他言語同様な感覚で文字列を扱うことが出来るようになっているらしい。(実際の動作は以前と変わらず、文字列配列操作をこねくり回しすブラックボックス処理で、あれこれ巧く動くように工夫されている。他言語同様の使い勝手提供程度と理解すればよい。)

理屈は、basic_string を利用して 宣言された string型 変数の実態作成(コンストラクタ呼出→オブジェクト作成、初期化)・・・といった、オブジェクト指向言語の説明に良くある手順を取っているようである。

▲上へ

リンク


内部リンク


外部リンク


  • 現在ありません

▲上へ
2008年06月01日(日) 09:15:06 Modified by cafeboy1




スマートフォン版で見る