パスワードを忘れた? アカウント作成
452647 journal

mumumuの日記: 閑話休題: Cの配列とポインタ

日記 by mumumu
翻訳ばかりここに書いているのもなんなので。

最近Cを久々にいじってみたいと言う気になり、手持ちのPerlで
書かれたCGIをCで置き換えようとしています。

・・・と言えばカッコいいんですが、Cを触るのは入社の研修以
来なので、柴田先生の本C FAQとかを見ながら
いぢっていますが、、ポインタと配列わかりにくすぎ(´ー`;)

素直にJavaに戻れってか。いや、そうはいかんのですよ(謎
なにげにCの仕事も回ってきてたりしますし。

----

・Cの文字配列に対する注意
*初期化の際は特に注意を要する。一次元配列の際は以下の規
則が適用される

http://www.bohyoh.com/CandCPP/FAQ/FAQ00111.html

int a[] = {1, 2, 5}; /* これはOK */

だが、2重配列では以下のようにやるとコンパイルエラーが出る
( Red Hat Linux 9 : gcc 3.2.2 )

int a[][] = { { 12,23,33 },{12,11,23} }; /* NG */
int a[2][5] = { { 12,23,33 },{12,11,23} }; /* OK */

test.c:5: 配列 `a' の要素に不完全型があります
test.c:5: 警告: 配列 `a' は一要素を持っているものと見なされます
test.c:5: `a' の領域サイズがわかりません

配列の要素数を明示的に指定してやるとOKになる。

----

あと、

int a[][] = { { 12,23,33 },{12,11,23} }; /* NG */

がだめで

int *a[] = { { 12,23,33 },{12,11,23} }; /* OK */

となるのは何故?????? 現在調査中。

[ Update September 11th 13:39 JST by m ]

前者がNGとなる理由は、コンパイラが配列の要素数を把握でき
ないからである。

配列はデータ構造上連続してメモリに確保され、コンパイラが
それを順番に見ていく都合上、配列の要素数がわからないと配
列の境の区別がつかないのである。

*pascalさめありがとうございました。


----

*C、C++の配列一般にいえることだが、配列から配列へ、代入演算
子(=)を使用した直接コピーは仕様上できない。これはウルトラ
F・A・Qであり、配列が左辺値として代入できない要素としてCの仕
様となっていることによる。

http://www.bohyoh.com/CandCPP/FAQ/FAQ00023.html
http://www.catnet.ne.jp/kouno/c_faq/c6.html#7

----

・下のふたつの違いについては、以下のFAQを参照

char a[] = "string literal";
char *a = "string literal";

http://www.catnet.ne.jp/kouno/c_faq/c1.html#32
http://www.catnet.ne.jp/kouno/c_faq/c6.html
式中に現われる型「Tの配列」という左辺値は、3つの 例外を除い
て、配列の最初の要素を指すポインター に意味が格下げになる。
結果としてできるポインター の型は「Tへのポインター」となる。

(3つの例外とは、1)配列がsizeofの引数となるとき(このときの配
列は配列全体と解釈される 2)アドレス演算子&の引数となるとき、
3)char型の配列を文字列リテラルで初期値するとき)。

あと、添え字演算子([])を伴わない配列名も、原則として配列
への先頭ポインタとして解釈される


*pは"string literal"の先頭部分をさすポインタである。決し
て上の二つは等価ではない。これは、「charの配列が文字列リテ
ラルで初期化される場合、上のaはポインタとして扱われること
は無い。」

という配列=ポインタ の例外から来ていると考えられる。

----

・あと、配列へのポインタがそれの先頭を(上記の例外を除
いて)指しているとしても、以下のNGな操作も存在する。


void f()
{
char *a = "ABC"; /* "ABC"に対するポインタ */
char b[] = "DEF"; /* 配列そのもの。ポインタではない */
*a = '1'; /* NG → Aを書き換えることじゃないの? */
b[0] = '1'; /* OK */
}

実際*a = '1'とやると落ちるときもあるし、そうでないときもあ
るのは確認した。理由は↓にある。

文字列リテラルには2種類の少し違った使いみちがある。配列の初
期化指定子(char a[]の宣言で使うような)に使うときは、その配
列の各文字の初期値を指定する。その他の場所で使うときは、
文字の名無し のstaticの配列となる。このときは書き込み
禁止のメモリーに保存されるかもしれない。だから無事に値
を変更できない可能性がある。

http://www.cmagazine.jp/src/kinjite/c/variable.html#index15
この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
typodupeerror

人生の大半の問題はスルー力で解決する -- スルー力研究専門家

読み込み中...