わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

文字列と配列とポインタ

  • 文字列とは,「'\0'で終わるchar配列」のことです.
    • 配列の中に'\0'がなければ(「'\0'で終わらないchar配列」ともいう),文字列ではありません.
    • 配列の中に'\0'が複数ある場合,配列の先頭から,最初の'\0'の前の文字までを文字列とみなします.このことを積極的に活用して,文字列の途中に'\0'を代入すれば,文字列を「そこで終える」ことが可能です.
  • 上の定義に従うと,配列変数の宣言と初期化をするには,char a[6] = {'H', 'E', 'L', 'L', 'O', '\0'}; としなければなりません.
    • ここでa[5]と書くとコンパイルエラーです.
    • char a[] = = {'H', 'E', 'L', 'L', 'O', '\0'}; とすると,サイズを自動で決めてくれます.ここではa[6]となります.なので,もとの文と同じになります.
  • 中カッコとシングルクオートをいちいち書くのは面倒ですが,文字列の初期化に限っては,char a[] = "HELLO"; のように簡略化して書くことができ,これは上記と同じ挙動をします.
    • ただし,char a[6]; (処理) a = "HELLO"; と分けることはできません.
  • ダブルクオートでくくった文字列の表記を「文字列リテラル」といいます.「文字列」とは区別して覚えます.Cの文字列リテラルは,その中身を書き換えることができません.
  • char a[5] = "HELLO";は文法上問題ないのですが,これはchar a[5] = {'H', 'E', 'L', 'L', 'O'}; と同じになります.'\0'で終わっていないので,この配列aは文字列ではありません.
  • ここまでを整理すると,「配列に"HELLO"という文字列を格納したい」ときは,
    • char a[] = "HELLO"; と宣言するのが最善です.
    • [ と ] の間に6(またはそれより大きい数)を書くのが次善です.
    • [ と ] の間に5を書くのはダメです.
  • 文字列を「参照」するための変数であれば,配列ではなく,ポインタ変数でもかまいません.例えば,char *a = "HELLO"; と書いてよいのです.しかし意味は,配列の宣言と異なります.
    • 配列で宣言した場合はa[0] = 'h';と書いて問題ありませんが,ポインタの場合はa[0] = 'h'; とすると,実行時エラーとなるか,もしくは書き換えられません(たまたまうまく書き換えられたなら,処理系の不具合かもしれません.ただし実用上は,aが「書き換えられる領域」を指すよう,どこかで値の変更をしているのではないか,と疑うべきでしょう).この "HELLO" は,書き換えられない領域にあるためです.
    • aはポインタ変数なので,char *a; (処理) a = "HELLO"; としてもかいません.
  • 余談.
    • char a[ ]; はコンパイルエラーです.関数の仮引数では[]を使って書くこともできますが,ポインタ変数になります.
    • 固定長文字列の配列の初期化についても,文字列リテラルを使って char a[2][4] = {"ABC", "XYZ"}; と書けます.ここで 2 は省略可能ですが,4 は省略できません.
    • char a[7] = "HELLO"; は,char a[7] = {'H', 'E', 'L', 'L', 'O', '\0', 0}; と同じです.char a[7] = ""; は,char a[7] = {'\0', 0, 0, 0, 0, 0, 0}; と同じです.文字列に限らず,配列の宣言と初期化を同時にするとき,値の指定されていないところには 0 が格納されます.'\0' と 0 は同じ値であるが,文字列の末尾を強調するために '\0' を使用するといいでしょう.char a[7] = {}; が char a[7] = ""; と同じかどうかは,個人的に規格を読んだ限りで分かりません.char a[7]; と,宣言だけして初期化を書かなかったら,格納される値は不定です(aがstatic変数でない限り).

予告: 明日は「文字と文字列」です.あっと,quotationとcitationも,書いてかなきゃ.