C 文字列のソースを表示
新しいページはコチラ
移動:
案内
,
検索
※このページではC言語にも存在していたという意味で記事タイトルがC ポインタになっていますが、<br /> [[C PlusPlus|C++]]でも同様です。[[C PlusPlus|C++]]だけの機能がある場合は明記します。<br /> <br /> == '''文字列''' == 文字はChar型で1文字を表現できるのでした。<br /> 例 ※C++の場合のみcout関数が使えます。#include <iostream>が必要<br /> <syntaxhighlight lang="cpp"> #include <iostream> int main(){ char c; //文字型の変数定義 c = 'a'; //aという文字を変数cに代入。実際にはaの文字コード番号が代入される。 std::cout << c << "\n"; std::cout << std::hex << (int)c << "\n"; return 0; } </syntaxhighlight> 出力結果 <syntaxhighlight lang="cpp"> a 61 //16進数の61は10進数では97です。asciiコードですね。 </syntaxhighlight> という具合に半角の1文字を扱うことができました。私たちは日本人なので日本語を使いますから、<br /> 日本語を格納したりする変数を最終的には使いたいと思いますが、まずはこのasciiコードの範囲での処理にしぼって考えましょう。<br /> 日本語対応まで考えると基本を理解することが難しいと思います。基本がわかったら日本語対応へ向かうのです。<br /> <br /> 上記のとおり1文字を扱う変数の型があるのは理解できたとしても、<br /> 文字変数の1文字では文章が表現できないので、通常のプログラミングでは1文字では情報の表現に支障があります。<br /> やはり人間は人間らしくということで、複数の文字の集まりによって文章を構成できるのですから、<br /> その複数の文字を変数として処理するということで、文字列の扱い方について覚える必要があります。<br /> <br /> どうすればいいか? <br /> 文字変数の配列として考えることで、文字列の表現が実現され、文章を格納することが出来るようになります。<br /> <br /> C言語の面倒なところはこのあたりの厳密さ、多様性にあると自分は感じます。<br /> ここで記述するのは基本的なことだけになってしまいそうですが、文字列を変数に格納するという手法については<br /> 多種多様の手法が存在しているので、文字列の理解をするだけでも大変です。自分でプログラムを全部組むのであれば<br /> 一つのやり方を覚えればよいのですが、誰かが作ったプログラムを再利用する場合には、その多種多様な方法の中で<br /> どの手法が使われるかは定まっていません。ですから、あらゆる事態に備えるのであれば、その多種多様な方法を<br /> できるだけ網羅して理解する必要もあります。<br /> 更には、文字コード群もいっぱいあるし、文字列関係の操作はプログラム技術全体の大きな領域になります。<br /> <br /> とは、いったものの覚えることが多すぎると嘆いても仕方ないので、ひとつづつ覚えてみる覚悟を決めましょう。<br /> 文字列は以下のようにして変数を宣言したり、初期値を入力できます。<br /> <syntaxhighlight lang="cpp"> //★パターン1 char cStr1[10] = {'y','o','n','e','w','i','k','i'}; //このやり方はあまり使うことは無いですけど、配列の基礎的な代入方法かも。 //ちなみに配列の添え字は0から始まって9までが作られます。 //cStr1[8]とcStr1[9]には自動的に"\0"が代入されます。 //数字の0で初期化してくれるってこと。 cStr1[10] = {'y','o','r','u','w','i','k','i'};//初期化以外ではまとめて代入する記述はできないので、これはエラー cStr1 = {'y','o','r','u','w','i','k','i'};//配列の添え字がいらないんじゃねぇ?というのも間違い。これもエラーになります。 //★パターン2 char cStr2[10] = "yonewiki"; //このやり方は便利だね、文字型配列の優しさをちょっぴり感じます。 //同じくcStr2[8]とcStr2[9]には自動的に"\0"が代入されます。 //数字の0で初期化してくれるってこと。 cStr2[10] = "yonewiki";//この方法でも初期化以外ではまとめて代入する記述はできないので、エラー cStr2 = "yonewiki";//同じくエラー //でも以下のようにChar型の代入と同じやり方はできます。 cStr2[2] = 'r'; cStr2[3] = 'u'; //★パターン3 char cStr3[] = "yonewiki"; //変数宣言時に値の代入(初期化)の記述があれば、配列の大きさを省略してもOK。 //自動的にcStr3[0]からcStr2[8]までの9の大きさの配列が生成されて、cStr3[8]には自動的に"\0"が代入されます。 //パターン1のような面倒な方法での値の代入(初期化)でも同じ結果になります。 //★パターン4 char cStr4[][9] = {"yonewiki","wiki"}; //これは文字列の配列です。配列の大きさを明記した後ろ側の方が文字列の長さ。2つの文字列があるってのは自動で認識して //cStr4[0][0~8] //cStr4[1][0~8] //といった変数が定義されたことになります。 </syntaxhighlight> と、まずは4つのパターンを示しました。<br /> パターン3はいいよね。パターン4は応用です。だけどちょっと手抜きの手法なんです。<br /> なぜかっていうと最初の文字列のyonewikiは大きさ9の配列にぴったり格納できて、最後一文字のcStr4[0][8]には"\0"も格納できる。<br /> だけど2つめの文字列のwikiは大きさが5あれば十分でcStr4[1][5~8]は無駄に"\0"という文字のコードである値0が格納されてしまいます。<br /> それででてくるのが、メモリの使い方を厳密に支配できるポインタって奴による処理になります。ややこしくてうんざりって感じる人も多い。<br /> 今どきのPCには4GByteとか8GByteとかメモリつんでるんだし4Byteくらいでケチケチすんなよと思うプログラマもいるでしょう。<br /> 小さな規模のアプリを開発している人にとってはその感覚って正しいと思います。でも、大規模なアプリを開発している熟練プログラマは<br /> その小さな無駄を失くすことで資源を有効利用するし、動作速度の速いプログラムを提供しているわけで、それで飯を食ってる人もいる。<br /> あの人に、あの会社に頼めば最大限有効活用した素晴らしいアプリケーションが作成されるという評価をもって、経済社会で争っているのです。<br /> でも、まぁこのような無駄くらいは、許容している人は多いかもしれません。ときどき、理解しにくい程の、凄い実装をみかけます。<br /> <br /> 再利用可能なクラスやプログラムを提供している組織やプロジェクトでは、同じように資源の有効活用や動作速度の速いプログラムになるように<br /> 組み込まれているので、自分は規模の小さいアプリしか作らないから覚えなくてもいいと思っているとしたら、<br /> その難しい部分を理解しようとしなかったばかりに<br /> それらの有効な再利用すべきプログラムを使いこなすのに、苦労することになるし、C言語の基礎は抑えたのになんだかわかった気分で<br /> 満足して、より踏み込んだところへ行けずに終わってしまうケースにおちいっているのだと思います。自分も同じようなもんですが…<br /> <br /> というわけで、また一歩踏み込んでいきます。<br /> それにしても文字列は初期化のときはあんなに簡単に代入できるのに、それ以降の代入では cStr = "yonewiki"; みたいにして代入できないのか?<br /> 不便ですよね。<br /> <br /> そういった不便さも踏み込んでいけば一定の理解を得ることができると思います。<br /> <br /> 配列の性質から、文字列を出力する際は以下のように指定します。※C++の場合のみcout関数が使えます。#include <iostream>が必要<br /> <syntaxhighlight lang="cpp"> char cStr1[] = "yonewiki"; std::cout << "cStr1 =" << cStr1 << "\n"; std::cout << "&cStr1 =" << &cStr1 << "\n"; std::cout << "&cStr1[0] =" << &cStr1[0] << "\n"; </syntaxhighlight> <br /> cStr[]で定義された配列変数は初期化の再に配列の大きさが9になり、配列の番号0~8までを保持した状態になります。<br /> そして、配列要素を取り除いた記述で cStr1 すると先頭のアドレスを返します。<br /> したがって、アドレス演算子を使って、&cStr1[0] や[0]を省略して&cStrと指定したのと同じことになります。<br /> つまり、cStr1と&cStr1と&cStr1[0]は同じアドレスを保持しています。<br /> ただし、std::coutで出力処理をするときには、扱いが異なります。 <syntaxhighlight lang="cpp"> cStr1 =yonewiki &cStr1 =003AF914 &cStr1[0] =yonewiki </syntaxhighlight> となります。ありゃ、2つめの結果&cStr1がアドレスになるのは意外(汗。<br /> ちなみに、うけとったアドレスから\0が現れるまで出力してくれるprintf関数の書式指定演算子%sを使った場合は<br /> プログラミング部分 <syntaxhighlight lang="cpp"> printf("cStr1 = %s\n" , cStr1); printf("&cStr1 = %s\n" , &cStr1); printf("&cStr1[0] = %s\n" , &cStr1[0]); </syntaxhighlight> 出力結果 <syntaxhighlight lang="cpp"> cStr1 =yonewiki &cStr1 =yonewiki &cStr1[0] =yonewiki </syntaxhighlight> となります。std::cout << &cStr1でアドレスが表示されるっていうのは、実際に確かめて、初めて知った。普段、こういうことしないからね。<br /> で、どういうことなんだろうって調べてみた。それには数値データの配列の場合はどうなるん?って疑問から解消できないか試みてみる。 そうすると<br /> <syntaxhighlight lang="cpp"> int iInt1[] = {10,11,…,19}; std::cout << "iInt1 =" << iInt1 << "\n"; std::cout << "&iInt1 =" << &iIntr1 << "\n"; std::cout << "&iInt1[0] =" << &iInt[0] << "\n"; </syntaxhighlight> <br /> 出力結果は当然ですが、以下のようにすべてアドレス表記になる。 <syntaxhighlight lang="cpp"> iInt1 =003AD914 &iInt1 =003AD914 &iInt1[0] =003AD914 </syntaxhighlight> このことから、std::cout関数はcStr1[8]という配列変数に対して、cStr1という表記と&cStr1[0]という具合に指定した場合だけ、<br /> 先頭アドレスから文字列として出力してくれていることになる。つまり文字列を返してくれることの方が特別なのだ。<br /> 更に、この特別な処理の実態を知るために調査を進めるとなると少し難しいが配列番号も省略した癖にアドレス演算子までつけやがって、<br /> もう面倒見れきれませんわ。となっているのがcout関数の実情なのだろう。cout関数のソースコードを追ってみる?んや、やめとく。<br /> さすがに時間がかかりそうだ。ちょろっとWebで検索してみたが、ここまで追いかけた人もあまりいなさそう。<br /> <br /> 次はポインタを使った文字列操作についての記事を書こうと思います。なかなかやるきになんないすけどね。<br /> 最近はMediaWikiの中に文字を打ち込む時間も多く取れてるので、更新していけるような気がする。でも今日はここまでかな。<br /> <br /> [[C PlusPlus|C++]]へ戻る
C 文字列
に戻る。
個人用ツール
ログイン
名前空間
ページ
議論
変種
表示
閲覧
ソースを表示
履歴表示
操作
検索
案内
メインページ
コミュニティ・ポータル
最近の出来事
最近の更新
おまかせ表示
ヘルプ
ツールボックス
リンク元
関連ページの更新状況
特別ページ