ゆうなんとかさんの雑記帳的な。

Twitterで踊ったり音ゲーしたりしてるあの名前がよくわからない人が書いてるらしいよ。

ショートコーディングやってみた

初級者は卒業しましたが、上級者への道はまだまだ遠いようです。
Ozyさん出題「スパゲッティコードを召し上がれ♪」問題の解説記事と最終ランキング発表! #c #codegolf|CodeIQ MAGAZINE
今回はこの問題に挑戦してみました。結果70バイトまで詰めることができ、ランキングに名前を残せましたが、上級者の仲間入りはなりませんでした。数バイトの壁が厚いですね。

今回知ったこと

久々に真面目にCを書いたのですが、改めて知ったこともありました。

scanfの仕様

勝手に何も値を返さないんだろうなと思っていたら、int型の値を返していました。値の読み取りに成功した個数が返るようです。何も読み込まなかったときはEOFが返るそうで、この仕様を利用して、入力がないと終了するみたいなコードを書いてループの終了条件としていました。

あやふやになっていた0と非0のどちらがtrue扱いか

0がfalseでそれ以外がtrueです。for文をインクリメントではなくデクリメントで書くと短くできるところからわかります。ちなみにJavaScriptでは0との比較のがほかの数との比較よりも早いらしいため、実はうまく使うと有効なテクニックなのだそうです。

for(var i = 0; i < 10; i++){}
//  ↓ ↓ ↓
for(i=10;i--;){}

実はこの手法、イテレータの i がある数値との比較されるよりも0との比較の方が高速に動作するため、場合によっては実務でも有用です。繰り返し回数が1,000回を超えるような処理では使ってみるのも良いかもしれません。

集え変態プログラマ!JavaScriptの最短コードに挑んだコードゴルフ大会 in Code 2013 | DX.univ

EOFの仕様

基本的に-1なのですが、違うこともあるらしいです。それはさておき。-1はすべてのビットが1となっているため、0にするにはインクリメントよりもビットを反転させるほうが1文字少なくなります。

&&や||の仕様

問題では最初の1回を出力しないように書かないといけないのですが、それをなるべく少ない文字数で実現するにはこの演算子の仕様を使うのが正解なようです。Cの&&や||が短絡評価されるのは知っていたのですが、0がfalseとして評価されるのかがあやふやだったのもあって盲点でした。

mainの仕様

引数の数に制限なんてなかったんだ…
とりあえず「main」って名前の関数があればそこがエントリーポイントになるようです。「int main(int argc, char *argv)」と等価なものであるべきなのを期待しているそうですが、実際のところは引数の数なんて知ったこっちゃないようです。これをうまく使って、mainの再帰を使ってコードを短くする黒魔術もあるそうです。

グローバル変数の初期値

グローバル変数を名前だけ書いておくと、初期値が0のint型変数にしてくれるそうです。これと&&が短絡評価されること、0がfalseと評価されることを利用して最初の出力を飛ばすのが模範回答でした。

printfとscanfを使うときはstdio.hをインクルードしましょう、まあしなくても使えるけどね

gccでコンパイルするときはstdio.hをインクルードしなくても使えるそうです。もちろん警告が出ますけどね。ちなみにclangでコンパイルしても使えました。もちろん警告が出ますけどね。