自転車は歩道側の自転車レーンを走れだって? 無理を言うな

先日はてな匿名ダイアリーに上がったこの記事。

anond.hatelabo.jpスマホとかイヤホンとか信号無視とか逆走とか、複数台横並びとかその他無灯火とかはまったく同意するのですが、以下の点については同意しかねます。

6. 一番左のレーン以外を走る(チャリに自信ニキへ)

どちらかというとこれは、「U○er Eats」や「チャリに自信ニキ」に向けてや。頼むから車と張り合わんといてくれ。速度差は歴然やねん。

例えば、車道外にチャリのレーンがあるときはそっちを通ってくれへんかな?なんでわざわざ50km/h、60km/h出てる車がバンバン走ってる車道の方を選ぶん?

 「車道外にチャリのレーン」というからには、これは歩道内に区切られた自転車レーンを指すのでしょうか。たとえばこんなの。

f:id:kmaebashi:20140920142806j:plain

 広い歩道を、歩行者のエリアと自転車のエリアに分けている、ように見えますが、実態として、歩行者が普通に自転車のところを歩いてる。これでは自転車側は、ろくにスピードを出すことができません。いやゆっくり走れよ、と言われそうですが、自転車に乗るからには少なくとも歩くよりは早く走りたいでしょう。こうやって、歩道を分けただけの「自転車レーン」は法的拘束力は何もないのでここは実際には歩道と同じですし、そうである以上自転車には徐行義務(時速7kmとか)がありますし、歩行者がいたら歩行者と同じ速度で走るか押して歩くかしなければいけません(ベルを鳴らすなどもってのほか)。さすがにそれでは自転車に乗っている意味がないというものでしょう。

また、このような「歩道」を走ることは、歩行者の安全を脅かすだけでなく、自転車にとっても必ずしも安全ではありません。歩道を走ると街路樹等でクルマから見えにくくなりますし、ドライバーの意識からも外れます。私は、ファミレスの駐車場に入ろうといきなり左折してきたクルマとぶつかりかけた*1ことがあります。それに、こういう歩道は、交差点では横断歩道の自転車横断帯に誘導されるわけですが、細い道から出てくるクルマは横断歩道なんか平気でまたいできますから、それもまた怖い。ママチャリ時代、何度ぶつかりかけたことか。これはクルマ側の事情もわからないでもなくて、両側に建物が建っている細い道だと横断歩道まで乗り出さないと左右が見えないのでしょう。しかし自転車から見れば実に危険な話です。

歩道を歩行者と自転車のエリアに分ける、とは言っても、本当に分ける気あるのかいこれ? みたいな歩道もありますし、

f:id:kmaebashi:20141019083854j:plain

植え込みなどで、明確に自転車の走るところを分離している道だと、たいていこんな有様です。

f:id:kmaebashi:20140920140827j:plain

 

f:id:kmaebashi:20140920173652j:plain

こんなところ、ロードバイクで疾走どころか、ママチャリでも満足には走れないでしょう。

ではこんなふうに歩道を区切ったものではなくて、もうちょっと「ちゃんとした」自転車道ではどうか。一部で有名な名古屋は伏見の伏見通です。

f:id:kmaebashi:20141019172352j:plain

今や順次撤去されてるとかいう自転車横断帯に何が何でも誘導しようとしたり、

f:id:kmaebashi:20180419162828j:plain

 交差点の手前で、どういうつもりか自転車を歩道側に放り出したり。

以前は、バス停の手前でも同様に自転車を歩道側に放り出していたのですが、さすがにそれはまずいと思ったのか、現在工事中のようです。

f:id:kmaebashi:20180419163728j:plain

これ、工事が完成したとして、いずれにしても自転車と歩行者の動線が交わってそうなのですが……

これは伏見通ではなく桜通沿いになりますが、この幅で対面通行は無理があると思います。

f:id:kmaebashi:20180504171527j:plain

だいたいがだ、自転車は車道を走るな、歩道に上がれ、と言う人は多いけれども、そもそも歩道はこんな風に看板に塞がれたり、

f:id:kmaebashi:20150501074536j:plain

突然なくなったりするわけです。

f:id:kmaebashi:20160502103025j:plain

こんなんじゃ、自転車以前に、歩行者にも、車椅子やシニアカーにも不便かつ危険極まりないでしょう。いかに今の(愛知県の?)行政が「クルマだけ」を優先しているかということです*2

さて、元の匿名ダイアリーに戻ると、

50km/hや60km/h道路に一番左車線にチャリのレーンをちょこんとつけとる国もどうかしとる。

こんなやつな。先日出張で埼玉に行ったときに撮影。

f:id:kmaebashi:20180402115725j:plain

私は今はロードバイク乗りですし、ママチャリ時代も基本的には車道を走るようにしていたので、この車道上の自転車レーンが実のところ一番走りやすいと思います。ただし路上駐車さえなければですが。実際、路駐の車をパスしようとしたら、車道側のドアをいきなり90度開きやがったということがあってあれは怖かった。

まして、子供を前後に乗せてたり、買い物袋を満載したママチャリにいきなり車道を走れというのは難しいかとは思います。

じゃあどこを走ればよいのか。私自身について言えば、まあロードバイク乗りなので、基本「車道の左側」を走っています*3。「遅いのがうろうろして邪魔だ」というクルマ側の意見はあるかと思いますが、それはまあ、そういうものだと思ってもらうしかない。少なくとも法律的には自転車は基本車道を走るものですし、車道はそのようにシェアして使うものでしょう。たとえば耕運機だって公道を走る場合は車道を走りますわな。

 車道に下りるのが怖い、というママチャリについては…… 現状、どうすべきかという思いはありませんが、ただ、ある程度の速度(時速15kmくらい?)を出したいのなら、やはり車道に下りるべきだとは思います。

おまけ。この連休に(また)京都に行った際、琵琶湖の湖岸道路で撮ったもの。

f:id:kmaebashi:20180501104824j:plain

ピクトグラムがママチャリなんですよね。湖岸道路ぐらい誰も歩いていない歩道なら、ビワイチ(琵琶湖一周)やってるロードはともかく、ママチャリは歩道でもよいかなあ、とは思った。

*1:最終的に相手の車に手をついて止まったので「ぶつかった」と言ったほうがよいかもしれない。

*2:上の、突然途切れる歩道の写真は京都の写真だけどな。

*3:伏見通について言えば、あそこは自転車道なので、ぶつくさいいながらも自転車道を走っている。

やっぱりポインタの話

少し前、以下の記事がホットエントリに上がっていました。

givemegohan.pigboat.jp

タイミング的にかなり遅れてしまいましたが、せっかくCの話題が出たことですし、宣伝しますよ。

メモリとアドレスの話

 ポインタの話をするにあたり「例え話をしない」というスタンスには共感しますし、ポインタを理解したいなら結局メモリを理解しないといけない、ということにも同意します。

ただ、拙著「C言語 ポインタ完全制覇」の旧版では、メモリとはどういうものかについてあまり説明しませんでした。17年も前の本ですから、当時は、プログラムを書こうというような人はある程度メモリの概念ぐらいはわかっているだろう、と仮定していたのだと思います。その仮定が正しかったかどうかはわかりませんけれども。

今となってはメモリの概念とか考えたこともない、という初心者も多そうなので、「C言語 ポインタ完全制覇」の改訂版では以下のような説明を入れました(1-2-1 メモリとアドレス)。

現在のコンピュータで主記憶として主に使われているのは、ダイナミックRAM(DRAM)と呼ばれるもので、非常に小さな蓄電器(コンデンサとかキャパシタとか呼ばれます)の充電の有無*1で、0か1かのいずれかの状態(これをビット(bit)と呼びます)を表現します。

(中略)

そして、メモリの内容を読み書きするためには、膨大にあるメモリのうちのどこの情報にアクセスするのか、ということを指定しなければなりません。この時に使う数値がアドレス(address)です。メモリ中の各バイトに、0から順に「番地」が振ってある、と今のところは考えておいてください*2

f:id:kmaebashi:20180213002945p:plain

「(中略)」のあたりには、2進数の説明が書いてあったりします。

 

――ただ、問題は、これで「メモリとアドレス」を理解したからといって、Cのポインタを理解できるとは限らない、ということです。

上記の記事に、私は以下のブックマークコメントを付けました。

例え話をしないC言語のポインタの説明 | 右や左の旦那様

ポインタは、「メモリ上の他のアドレスを指す変数」ではなくて派生型の一種。Cのポインタが難しいのは主に宣言の構文がクソだから。この辺のことは拙著「C言語 ポインタ完全制覇」をどうぞ。C99対応の改訂版出たよ!

2018/02/01 20:41

b.hatena.ne.jpそしたら以下のように書かれた。(´・ω・`)

例え話をしないC言語のポインタの説明 | 右や左の旦那様

↓kmaebashiのような説明がポインタの理解を阻害していると思う。/「緑の板に黒い四角いのが付いたアレ」これも余計な話。

2018/02/03 13:47

b.hatena.ne.jp

まあこんなことを100文字しか書けないブクマコメントで説明しようというのはどだい無理な話なので、ここでちょっと補足します。

ポインタは派生型の一種である

上記リンク先の記事には、

ポインタは、「メモリ上の他のアドレスを指す変数」です。

とあります。

Cのバイブルと言われる「プログラミング言語C」(通称K&R)においても、ポインタについて同様の説明をしています。

これについて、「C言語 ポインタ完全制覇」では以下のように書きました。

 

「ポインタ」という言葉について,K&R では以下のように説明しています(p.113 第5 章「ポインタと配列」冒頭部分)。

ポインタは,他の変数のアドレスを内容とする変数であり,C では頻繁に使用される。

「アドレス」については前項で説明しましたので、「他の変数のアドレス」とは何か、ということについては、なんとなくイメージが付くのではないでしょうか。

ただ、この説明、バイブルにケチをつけるようでなんですが、かなり問題のある表現だと思います。この説明では,まるでポインタといえば「変数」であるかのようですが、実際には必ずしもそうではないからです。

一方、規格のほうでは「ポインタ」という言葉を以下のように定義しています(6.2.5「型」)。

ポインタ型(pointer type)は,被参照型(referenced type)と呼ぶ関数型,オブジェクト型又は不完全型から派生することができる。ポインタ型は,被参照型の実体を参照するための値をもつオブジェクトを表す。被参照型T から派生されるポインタ型は,“T へのポインタ”と呼ぶ。被参照型からポインタ型を構成することを“ポインタ型派生”と呼ぶ。

派生型を構成するこれらの方法は,再帰的に適用できる。

何のことだかさっぱりかもしれませんが(なにしろ規格書なので、そう読みやすいものではありません)、とりあえず、最初の一句に注目してください。「ポインタ」と書いてありますね。

型、といえば,int型やdouble型が思い浮かびますが、Cには、それと同様に「ポインタ型」という型があるのです。

ただし、大急ぎで付け加えますが、「ポインタ型」という型が単独で存在するわけではなくて、他の型から派生することにより作り出されます。上記の引用でも、後ろのほうに「被参照型T から派生されるポインタ型は“T へのポインタ”と呼ぶ」と書いてあります。

つまり,実際に存在する型は「int へのポインタ型」や「doubleへのポインタ型」だということになります。

「ポインタ型」は型ですから、int型やdouble型がそうであるように「ポインタ型の変数」も「ポインタ型の値」もあります.そして――厄介なことに、世間では「ポインタ型」も「ポインタ型の変数」も「ポインタ型の値」も,単に「ポインタ」と呼んでしまうことが多いので、混同しないように気をつけてください。

POINT

最初に「ポインタ型」がある.

「ポインタ型」があるんだから「ポインタ型の変数」も「ポインタ型の値」もある.

たとえば,C では、int という型は整数を表します。int は「型」ですから、int型を格納するための変数もありますし、int型の値もあります(「5」とか)。

ポインタ型もそれと同じで、ポインタ型の変数もあり、ポインタ型の値もあります。

そして、「ポインタ型の値」は、実際にはメモリのアドレスのことです。

 

バイブルに楯突いてでもこのような説明をした意図はふたつあります。ひとつは、実際に「ポインタ型変数」と「ポインタ値」を混同してしまう人がそれなりにいること、もうひとつは、ポインタが「型」であることがわからなければ結局Cの宣言からして理解できないからです。

よく、たとえばintへのポインタを宣言する際、

int *a;

ではなく

int* a;

 のように*をintに寄せて書こう、という人がいます。これは、そう書いたほうが、「int*という型の変数aを宣言している」ということが明確になるからですよね。まあ、この書き方は一度に複数のポインタ型変数を宣言しようとすると破綻しますし、Cでは配列も派生型の一種なのに(これも重要!)配列を示す[]はintに寄せて書きようがない、という点で不完全ではありますが、「int*という型」を強調したいという気持ちはわかります。

そして、この宣言の構文こそがCのポインタを奇ッ怪なものにしている主犯だと私は思うわけでして――

Cの宣言の構文はクソである

えー、ここから先は本を読んでください、と言いたいところですが、何もたとえば

void (*signal(int sig, void (*func)(int)))(int);

みたいな極端な例を出さずとも、それこそ前述のとおり

int *a;

という宣言からして「int*という型の変数aを宣言している」ということがたいがいわかりにくいですし、

char *color_name[] = {"red", "green", "blue"};

とあったら、このcolor_nameは「charへのポインタの配列」です。

二次元配列を関数に受け渡すなら、

/* 3×3の行列をfuncに渡したい */
void func(double (*matrix)[3])

といった書き方もします。まあこれは

void func(double matrix[3][3])

と書くこともできますが、こうして受け取ったmatrixを別変数に退避したり、malloc()で領域を確保しようと思ったら、いずれにしても「double (*matrix)[3]」という謎の表記から逃げることはできません。

実のところ、Cを何年も書いているようなプログラマでも、このあたりのことをちゃんとわかっていない人は多いものです(というか私自身、理解に数年かかりました)。

だからといって、どうでもいいようなトリビアだとは私は思いません。実際に実用のプログラムで十分使う知識だからです。ちゃんと理解しないでなんとなく既存プログラムから写して使うんじゃ、コピペプログラマじゃないですか。

C言語 ポインタ完全制覇」は、こういった宣言の読み方をはじめ、実行時に変数のアドレスがどう決まるのかとか(コンパイラが決めるんじゃないよ!)、物理アドレスと仮想アドレスとか、連結リストのようなデータ構造とか、実践的な内容が盛りだくさんです。伊達にポインタだけで300ページ以上書いているわけではありません。手前味噌になりますが、おすすめできると思っています。

gihyo.jp

*1:蓄電器が小さすぎて一定時間で放電してしまうので、定期的に書き込みなおす(リフレッシュする)必要があり、この特徴から「ダイナミック」RAMと呼ばれます。

*2:実際には、これは物理アドレスであり、今時のPCでプログラマが普通に扱うアドレス(仮想アドレス)とは異なります。「2-1 仮想アドレス」にて後述します。

プログラマよ、貧乏性たれ

かなり古い話ですが、かつて増井俊之さんが提唱した概念で「富豪的プログラミング」というものがあります。

富豪的プログラミング

実のところ私は、この文章の趣旨には異論はありません。特に以下の部分などは、場合によってはプロトタイプに限るかもしれませんが、強く同意します。

 

  • メモリや実行効率を気にしないでお気楽にプログラムを作る
    効率を重視したプログラムは作るのが大変ですし、 ちゃんと動かすにはデバッグも大変です。 富豪的プログラミングでは一番単純で短いアルゴリズムを使います。
  • 条件が変わる度にすべての計算や表示を行なう
    再表示が必要な場所だけ書き直ししたり、出力のバッファリング をしたりする貧乏性な工夫はバグのもとになるので行なわず、 条件が変わる度に計算を再実行したり全体を書き直したりします。

 ――が、こういうのは、あくまで、それにより開発効率が上がったり、UXが向上したり、という場合に限るのであって、最近のコンピュータは速いしメモリもディスクもでかいからいくらでも資源を無駄遣いしていいさー、というわけではないでしょう。

たとえば。

例1)

20年近く前、「いんたーねっとのほーむぺーじ」が流行していたころ、「いまどきの閲覧者のPCは性能が上がっているし、回線速度も速くなったし、多少重い、広い画面を要求するページにしてもいいだろう」と思ったら、閲覧者はガラケーi-modeでWebを見るようになった。「携帯用ページ」を作ってガラケーユーザーを追い出したら、今度は(さすがにPCに比べたら遅くて画面も狭い)スマホでPC用サイトを見るようになった。

例2)

いまどき、PCのHDDの容量なんか巨大なんだから、ファイルがでかくてもいいだろう、と思ったら、SSDに置き換えられて容量が減った。

例3)

仮にもサーバなら、メモリもディスクもそれなりにはあるはずだから無駄遣いして良いだろう、と思ったら、クラウドになってメモリやディスクの無駄遣いが直接コストに響くようになってしまった。

 

――大昔、「マイコン少年」がPC8001やらMZ80シリーズやらの8ビットパソコンで遊んでいたころ、BASICがROMに焼いてあって一瞬で起動するPC8001に比べ、起動時にテープからBASICをピーヒョロヒョロと読み込むMZ80は、起動に2~3分かかるということで馬鹿にされたものです*1。しかし、一時、Windowsは起動するのに数分単位で待たされた時期がありました(Windows8以降、かなりマシになった)。コンピュータの性能は天文学的に上がったのに、肝心のユーザにとっての待ち時間が縮まないのでは意味がありません。

Computer latency: 1977-2017

うむ。あとでじっくり読む。

Webページにしたって、先日爆速なWebサイトが話題になりましたが、

www.itmedia.co.jpもちろんアクセス数とかサーバからの距離とかあるでしょうが、今時シンプルなテキストサイトなら、かなり爆速だったりします(例:私のWebサイト)。これにくらべてはてなブログの遅いこと遅いこと、「コンピュータもネットワークも速くなったから、これぐらい重くしても誰も困らないさー」とか言えるレベルではありません。

だから、思うわけです。プログラマよ、貧乏性たれ、と。

 

で、ここからはもちろん宣伝ですが、貧乏性なプログラマなら選ぶのはCだよね!

ベンチマークによっては、Cは必ずしも「最速」ではありません。今時のJIT付きの言語の方が高速な結果を返すケースは多いものです。しかし、メモリ使用量も考えると、Cは今でも最軽量の言語のひとつであろうとは思います。

――依存関係増やすの嫌なんだよねー、という話もありますが、それはまた今度。

*1:もちろん、「クリーンコンピューター」という概念は先進的なものでしたが、「BASICが永遠とは限らない」というキャッチフレーズに反して、BASICよりもハードの寿命が先に尽きたように思います。

ブロックの先頭以外での変数宣言について

今日の元ネタは以下のページです(古い記事ですが)。
blog.jnito.com

まあ大筋で異論はないのですが、以前からあまり納得がいっていないのが、冒頭の
「1.使われるローカル変数をすべてメソッドの最初に宣言する。」
です。確かにC90までは、ローカル変数はブロックの先頭でしか宣言できませんでしたし、Cのスタイルを引き継いだ後発の言語、C++とかJavaとかC#とか、あるいはCでもC99からは、ブロックの途中でも変数宣言ができるようになっています。それは、その方がよい、と言語設計者が判断したからなのでしょう。しかし――
私自身、ブロック途中での変数宣言を使わないわけではありません。しかし、「使われるローカル変数をすべてメソッドの最初に宣言する」ことが悪いことであるかのように言われると、反論したくはなります。そんなことを気にする時点で、メソッドが長すぎやしないかと。
「使われるローカル変数をすべてメソッドの最初に宣言する」ことが悪いと主張する人は、変数を使う直前で宣言することで、変数のスコープを狭くすることができると言います。でも、「メソッドの先頭でちょっとだけ使う変数」は結局メソッドの最後までのスコープを持ってしまうわけで、変数のスコープを狭くする効果を期待するとしても、ずいぶん中途半端な話のように思えます。それぐらいなら、C90でも普通に使える、ブロックで囲む方法でスコープを絞る方が、なんぼか筋が通るように思います。
あと、「変数を使う直前で宣言する」というスタイルは、ブロックがスコープを制御するC起源の言語とどうも相性が悪いようにも思います。これはJavaの話になりますが、(try with resources導入前の)Javaで、try節の中で何かのリソースを生成するのでtry節の中で変数宣言して、finally節でリソースの解放処理を書こうと思ったらその変数が見えないので仕方なくtryの外に出して、さらに変数が初期化されていないとエラーが出るので仕方なく宣言時にnullを代入して、せっかくコンパイラが初期化されていないエラーを出してくれているのにこれじゃ意味ないじゃん、と悲しくなったことはないですか。
まあ、こんなことを言ってる私はレガシープログラマなのかもしれませんが、レガシープログラマならCだよね! ということで宣伝です。
今時GDIでWindows用ドローツールを作ってるC言語ポインタ完全制覇第2版発売中ですよ!

ドローツールの画面はこんな感じです。
f:id:kmaebashi:20171220010458p:plain
残念ながら紙面の都合で全ソース掲載とはいきませんでしたが、これぐらいの絵が描ける、実際に動作するドローツールを題材にしている時点で、インベーダーを題材にしながらこれじゃコードは書けないぞ、という本よりははるかにマシな本であろうと自負しております。

C99の可変長配列(VLA)はどれぐらい便利なのか

いわゆるANSI C(C90)では、配列のサイズは定数でなければなりません。つまり、配列を宣言する際には、

int a[10];

のように[]の中には定数を書く必要があり、

int a[size];

のように変数を書くことはできません(gccでは昔からできたりしましたが、それはgcc独自拡張です)。
しかし、C99からは、可変長配列(VLA: Variable Length Array)の機能が追加され、配列の要素数に変数(というか定数でない式)が書けるようになりました。
ただ、VLAが使えるのは自動変数(staticでないローカル変数)だけです。まあ静的配列の要素数が可変というのもいまいち意味が分からないので無理はありませんが、一時的にしか存在できない自動変数の配列のサイズが可変にできたところで、あまり便利じゃないのでは、とも思えます。まあ、実行時にしかサイズが決まらない一時的な作業バッファとかにはよいかもしれません。今時Cを使っている環境だと組み込み系とか多そうで、スタックのサイズ制限がきつかったりしてあまり気楽には使えない、ということもありそうです。
ただし、VLAの構文は、たとえばmalloc()で確保した領域にも使えます。
たとえばオセロでも囲碁でもマインスイーパーでもいいのですが、何らかのゲームの「盤面」を2次元配列で確保するとします。オセロの盤面は普通は8×8ですが、もっと広い盤面も選択できるようにしてもよいでしょう。そういう場合は、縦横が可変長の2次元配列が欲しくなります。しかし、ANSI Cでは、縦横可変の可変長配列を作ることはできません(ポインタを駆使して、board[x][y]の形式でアクセスできる可変サイズの領域を確保することはできなくはないですが)。
VLAであれば、たとえば盤面の1つのマスをint型で表現するとして、以下のように書くことで、size×sizeの2次元配列を確保できます。

int (*board)[size] = malloc(sizeof(int) * size * size);

もちろん、盤面の各マスは、board[x][y]のようにしてアクセス可能です。
これを関数の引数として受け渡しするときは、受け取る側の関数のプロトタイプは以下のように書けます。

void func(int size, int board[size][size]);

これは、

void func(int size, int (*board)[size]);

シンタックスシュガーです。私はこのシンタックスシュガーはあまり好みではないのですが、さすがにこのケースでは、前者の例の方が意図をよく表していてわかりやすいかなあ、と思います……
さて、宣伝しますよ。
VLAをはじめ、C99の機能についてもいろいろ解説した「C言語 ポインタ完全制覇」改訂版発売中ですよ!

なぜあなたは「配列へのポインタ」を学ぶ必要があるのか

かつて(20年くらい前)一緒に仕事をしていた人が、こう言ったことがあります。

はっきり言って、Cプログラマ過半数は、「配列へのポインタ」を理解していないと思う。

まあ「過半数」かどうかはわかりませんが、実際、それなりに長くCを使っている人でも、「配列へのポインタ」を理解していない人はいるように思います。以下、一例。

きくT(2/10 ビッグアップル) on Twitter: "んー、2次元配列を1次元にキャストして関数に渡すことはできるんだけど、1次元配列として受け取った関数側で2次元配列にキャストする方法はあるのか?"
f:id:kmaebashi:20171217185156p:plain

もちろん菊池誠先生は物理学者であり、Cは専門ではないでしょうから、このことをもって菊池先生のことをとやかく言う意図はありません。

それにしても、リプライ中にある以下の記述は、やはりCの初心者の方にとっては「わけがわからない」ものであるかと思います。

Int (*b)[5] = (int(*)[5])a;

int (*b)[5]」なんて、こんなマニアックな書き方使わないよ!

と思う人もいるかもしれません。でも、現に菊池先生が困ったように、これを使う機会は、確実にあるものです。

「配列へのポインタ」を使う典型的なケースは、「多次元配列を関数の引数として渡す時」です。たとえばオセロの盤面をintの2次元配列(int board[8][8];)で表現するとして、これを引数として受け取る関数のプロトタイプは、たとえば以下のようになります。

void func(int (*board)[8]);

いや、そんなマニアックな書き方しなくても、

void func(int board[8][8]);

とか

void func(int board[][8]);

とか書けばよいのでは? と思う人もいるかもしれません。しかし、こうして受け取った引数を別の変数にコピーしようとした場合や、malloc()で動的に多次元配列を確保したい場合は、「配列へのポインタ」を宣言することを避けることはできません。
たとえばオセロの盤面をmalloc()で確保するなら、以下のように書くことになります。

int (*board)[8] = malloc(sizeof(int) * 8 * 8);

で、わざわざこんなの書いたということはもちろん宣伝なのですが、「配列へのポインタ」はもちろん、Cの配列とポインタについて徹底解説した「C言語 ポインタ完全制覇」改訂版発売中ですよ!

ちなみに旧版の画像はこちら。この画像を見せると「あっ、見たことある!」という方も結構いらっしゃるので。
f:id:kmaebashi:20171217195236j:plain

C言語 ポインタ完全制覇 改訂版が発売されます!!

2001年の発売より、実に17年、第18刷を数えるロングセラーとなった「C言語 ポインタ完全制覇」の改訂版が発売されます。

f:id:kmaebashi:20171203200126j:plain

 

私の作成した紹介ページはこちら。

「C言語 ポインタ完全制覇(第2版)」書籍情報

技術評論社さんの紹介ページはこちら

新・標準プログラマーズライブラリ C言語 ポインタ完全制覇:書籍案内|技術評論社

Amazonでは現在予約注文が可能です。

https://www.amazon.co.jp/o/ASIN/477419381X/gihyojp-22

技術評論社さんでの電子書籍版(PDF)販売、およびKindle化の予定もあります。

 

「なんでいまさらCの本?」と思う人が多いかもしれません。私自身そう思わなくもないので当然です。しかし、現在でも、WebやTwitterで検索してみると、Cのポインタで苦労している人はまだまだたくさんいるようです。ていうか著者からすると、最近書いた「Webサーバを作りながら学ぶ 基礎からのWebアプリケーション開発入門」よりも、17年も前に書いた「C言語 ポインタ完全制覇」の方がTwitter検索するとよっぽどたくさんかかってくる、という、喜んでいいのか悲しむべきなのか、という状況がずっと続いていたりします。

旧版「C言語 ポインタ完全制覇」は、自分で言うのも何ですが、Cのポインタおよび宣言の構文について、当時としては画期的な説明をした本であったと思っています*1。最近でも時々、「Cの宣言は英語順で読むといいよ!」という記事がはてなブックマークに上がってきたりしますが、この「英語読み」を日本で最初に言い出したのは、おそらくこの本(の原型となったWebページ)です*2

 Cのポインタで悩んでいる人も、Cのポインタが「わかっているつもり」の人も、だまされたと思って上記書籍情報のページくらいは読んでみてください。

今回の改訂では、旧版と大きく構成を変えたわけではないですが、さすがに17年も経てば直すべきところも出てきます。以下のような点で加筆・修正を行っています。

  • C99の可変長引数(VLA)やC11のライブラリに言及
  • ASLRやDEPといった今時の機能にも言及
  • サンプルプログラムの動作環境の64bit化
  • 1章に、「メモリとアドレス」の項を追加。17年前にCプログラマを志す人ならある程度前提にできたかもしれませんが、今時はそうもいかないと思われるので。
  • 「補足」を目次に載せました(これはご要望が多かった!)。
  • その他、細かい修正。

何しろ旧版が323ページのところ、今回は367ページありますので、相応の書き足しを行ってます。旧版をお持ちの方も、ぜひどうぞ。 

*1:と言いつつ、実のところ文法通りの説明をしているだけなので、「なぜ私以外の人がもっと早くこういう本を書いてくれなかったんだろう」というのが正直な気持ちでもあります。

*2:たとえば「エキスパートCプログラミング」にも宣言を読むダイアグラムはありますが、いきなり日本語を組み立てているので末尾から文章を作るという妙なことになっています。どうして訳者注くらい入れてくれなかったんだろう……