めんくり

@menkuri

Don't be evil. C言語をメインに書いている趣味プログラマ。たまにRustも書きます。

公開投稿・作品

もちろん char hello[] = "hello"; char* hello_ptr = hello; // decay, hello = &hello[0] とした場合は hello_ptr の指す先はスタック領域の配列になっているので、 hello_ptr[2] = 'L'; のように書き換え可能であり、char* だからといって必ず const を付けるわけではない 3/3

もちろん char hello[] = "hello"; char* hello_ptr = hello; // dec

だからアクセス方法も違うし、中身を書き換えられるかどうかも違う (前者は静的領域の文字列リテラルなので書き換え不可、後者はスタック領域の配列なので書き換え可) 間接参照した先が書き換え不可能な上のケースは、必ずデータ型の方に const を付けるべき const char* hello = "hello"; こうすることで書き換えようとするとコンパイルエラーで止めることができる 2/n

だからアクセス方法も違うし、中身を書き換えられるかどうかも違う (前者は静的領域の文字列リテラルなので書き換え不可、後者

#Cプログラミングの落とし穴 char* hello = "hello"; char hello[] = "hello"; どっちも同じことをやってるように見えて全く違うのが怖いポイント 上は文字列のある静的領域へのポインタになってるけど、下は文字列が格納された配列を作ってる (なお、C言語の文字列は最後に \0 という文字を含むため、長さ6の配列が確保されていることに注意) 1/n

#Cプログラミングの落とし穴 char* hello = "hello"; char hello[] = "hello"

今度は別の引数で大本の配列のサイズ(先ほどの例では 8)を渡さないといけない(size_t len のように)ことを忘れがちになる(decay の影響で 8 は無視されているため) なので私は int a[][16][32] みたいな最初だけサイズを書いていないことを明示した書き方にしがち (書いていないから「別で渡せよ」という意味合いを持たせている) 4/n

今度は別の引数で大本の配列のサイズ(先ほどの例では 8)を渡さないといけない(size_t len のように)ことを忘れ

多次元配列は引数に渡す時も地味に複雑 配列がポインタに decay されてしまうので大本の配列のサイズはあっても意味がないけど、要素の配列のサイズは型の一部だから書かれていないとエラーになる とりあえず多次元配列を渡す時は全部サイズを書いておけば ex. int a[8][16][32] エラーは防げるのだけど、 3/n #Cプログラミングの落とし穴

多次元配列は引数に渡す時も地味に複雑 配列がポインタに decay されてしまうので大本の配列のサイズはあっても意味がな

int calender[12][31]; int (*monthp)[31]; monthp = calender; C言語では二次元配列は配列に配列が入ってる、配列型の配列になっている それをポインタで扱おうとすると要素となる配列のサイズが型名に含まれるというなかなかに気持ち悪いことになる 1/n #Cプログラミングの落とし穴

int calender[12][31]; int (*monthp)[31]; monthp = calender;