C
MSYS2の各環境が何を対象としたプログラムを作成するのか理解してしまえば話は簡単。 foo.c #include <stdio.h> int main(void) { int c; while ((c = getchar()) != EOF) printf("%c", c); fprintf(stderr, "EOF\n"); return 0; } mingw64.exeまたはmingw32.exeにて</stdio.h>…
FILEストリームの入出力単位をワイド文字かバイトか設定する関数fwideについて。実は前回のソースの ...snip fwide(stdout, 1); ...snip はWindows版では設定は無視され*1、あろうが無かろうが動作した。 たとえ第二引数を1(=ワイド文字単位)にしても、 …
前回は文字列をバイト列で扱ったが、 今回はワイド文字版でlinuxとWindowsの共通ソースを作成してみる。 hello.c #include <stdio.h> #include <locale.h> #include <wchar.h> int main(void) { setlocale(LC_ALL, ""); fwide(stdout, 1); wprintf(L"%ls\n", L"hello world"); wprintf(L"</wchar.h></locale.h></stdio.h>…
前述のhello.cはWindowsのAPIを利用したプログラムなので、 クロスコンパイルを行ったlinux側では実行できない*1。 同一のソースを使い普通にコンパイルするかクロスコンパイルするかの違いだけで、 それぞれのターゲット環境で実行できるものを試してみる。…
*1 せっかくなのでメッセージを日本語にする。 hello.c #include <windows.h> #include <tchar.h> int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { MessageBox(NULL, _T("こんにちは世界"), _T("ご挨拶"), MB_OK); retur</tchar.h></windows.h>…
せっかくtchar.hを使って書いたのでUnicode版も作る。 当然ソースはそのままでUnicode版にする旨をコンパイラに指示する。 $ i686-w64-mingw32-gcc -Wall -ansi -pedantic -o hello.exe hello.c -mwindows -municode -D_UNICODEUNICODEと_UNICODEを定義して…
Win32/64向けにC/C++のクロスコンパイラ環境をUbuntu(Trusty Tahr)上にちょこっと作る*1。 $ apt-get --simulate install mingw-w64 注意: これはシミュレーションにすぎません! ...snip 以下の特別パッケージがインストールされます: binutils-mingw-w64-i6…
のとき漸化式で得られる数列は、 #include <stdio.h> int main(void) { int i; double an = 2; for (i = 1; i < 20;i ++) { printf("%2d: %f\n", i, an); an = (2 * an + 1) / (an + 1); } printf("%02d: %f\n", i, an); return 0; } 1: 2.000000 2: 1.666667 3: 1.62</stdio.h>…
#2のen2.cや#3のen3.cでは多重エッジを含むグラフを生成しており、 #2ではこれを除去するためにtredを使ってフィルタリングした。 いちいちフィルタするのも面倒な場合、 DOTの方でこれに対処する方法がある。 たとえば、en3.cの場合なら、 en3strict.c #inc…
この問題では特にコストが高いわけではないと思うが、 呼び出すたびにstrlenで履歴文字列の長さを求めるのはちょっとという向きには、 新たに履歴に文字を追加する時の場所を履歴とともに渡すことでstrlenを消せる。 en7.c #include <stdio.h> #include <stdlib.h> #include <string.h> ty</string.h></stdlib.h></stdio.h>…
enumerate0における履歴は変更不可な文字列として関数の呼出しごとに生成していた。 それぞれの呼出し環境で独立したオブジェクトというのはわたし好みではあるが、 少々お大尽的プログラムでもある。 というのも、渡された履歴の末尾に情報を追加して次へ渡…
前述の方針に従って実装してみる。 en5.c #include <stdio.h> #include <stdlib.h> #include <string.h> static char *append_history(const char *h, const char *a) { return strcat(strcpy(malloc(strlen(h) + strlen(a) + 1), h), a); } static void enumerate0(const char *h, unsign</string.h></stdlib.h></stdio.h>…
したがってこの列挙をプログラムにさせるには、 ルートノード(2, 1)から葉ノード(0, 0)まで辿ってきたエッジのラベルを順に表示すればいい。 とはいえ単純に考えすぎて、 en4.c #include <stdio.h> static void enumerate(unsigned int a, unsigned int b) { if (a ==</stdio.h>…
enumerate(5, 4)では詳細に立ち入るにはちょっと大きい。 そこでスケールダウンしてenumerate(2, 1)について見てみる。 実はenumerate(2, 1)についてのグラフは既に出ている。 前回の記事の最後に出したグラフの中で、 ノードenumerate(2, 1)を根にして辿る…
再帰関数enumerateの呼び出し関係をグラフで表してみる。 例えば、enumerate(5, 4)内では個数aを一つ減じて、 enumerate(4, 4)が呼ばれているので、これを、 と表現することにする。 ノードに関数の二つの引数の値、エッジにaとbのどちらの記号数を減じて呼…
二種類の記号からなる記号列を考える。 各記号を決められた数ちょうどだけ含む記号列を列挙してみる。 記号列が長くなってくると実装上の理由から実行時に破綻するだろうが、 ここでは記号列はそれほど長くないとして、 再帰関数でコーディングしてみよう。 …
やっぱり講義の構成に難がある気がする『データ構造とプログラミング』。 ちぐはぐというか焦点がぼけた感じに思えて仕方ない。 それはおいておいて、 木構造のノードデータをインデント付きで表示するCプログラムの説明。 インデントをどうやって付けるのか…
N = 100以下の素数をリストアップする。 #include <gmp.h> int main(void) { unsigned int N = 100UL; mpz_t p; mpz_init_set_ui(p, 2UL); do { gmp_printf("%Zd ", p); mpz_nextprime(p, p); } while (mpz_cmp_ui(p, N) <= 0); gmp_printf("\n"); mpz_clear(p); re</gmp.h>…
school_recordを分割した残りの方だが名前を短くしよう。 たくさんキーを打つのが面倒なのは予約語に限ったわけではない。 識別できるのなら識別子は短い方が打つのが楽だ。 record.h #ifndef RECORD_H_INCLUDED #define RECORD_H_INCLUDED #include "grade.…
たぶん使うであろう機能の不足を追加。 grade.h ...snip /* returns the letter representing this grade. */ char grade_toletter(grade_t g); #endif /* GRADE_H_INCLUDED */ grade.c ...snip struct tag_grade { enum {GRADE_VAL_A = 5, GRADE_VAL_B = 4,…
grade_t型はGRADE_Aのような定数を指す時にしか使わない。 用意した定数はすべてconst grade_t * const型なので、 #include <stdio.h> #include "grade.h" int main(void) { grade_t *x = GRADE_A; grade_t *y = GRADE_A; printf("%d\n", grade_compare(x, y)); y = G</stdio.h>…
ちょっと抜けが。 GRADE_A等の定数が指すgrade_t型の実体を収めた配列gradesは公開する必要はない。 したがって、 grade.c ...snip static grade_t grades[] = {{GRADE_VAL_A}, {GRADE_VAL_B}, {GRADE_VAL_C}, {GRADE_VAL_D}, {GRADE_VAL_F}}; ...snip の方…
成績の評点に関する部分を独立させて、不必要に複雑度を増やし分かりにくくしてみる。 grade.h #ifndef GRADE_H_INCLUDED #define GRADE_H_INCLUDED typedef struct tag_grade grade_t; extern const grade_t * const GRADE_A; extern const grade_t * const…
リストの生成と廃棄を行う関数を書く。 ここでは循環リストで実装してみる。 school_record_list.h #ifndef SCHOOL_RECORD_LIST_H_INCLUDED #define SCHOOL_RECORD_LIST_H_INCLUDED #include "school_record.h" typedef struct tag_school_record_list schoo…
二教科の成績記録の#100での実装に間違いがあった。 school_record_t型の実体を生成する関数school_record_newにおいて、 生徒の名前p->nameのための領域の割り当てに失敗したときに、 既に割り当てていたschool_record_t型の領域を解放しているものの、 解…
表題の通りである。 二つの教科の成績を保持するschool_record_t型のデータを値として持つリストの要素を考える。 とりあえずリスト要素の定義のみの未完成のコード(コンパイルはできる)。 school_record_list.h #ifndef SCHOOL_RECORD_LIST_H_INCLUDED #d…
dice[123].cは試行回数やカウンタ配列をunsigned int型としている。 試行回数を一億回とするのであればunsigned long型にすべきであろうが、 乱数の生成にdSFMTを使うように書いているため、 SIMDに最適化されたSFMTを使える環境でunsigned int型が32ビット…
さて、ダイスを何回でも振ることのできるルールの場合はどう書けばいいだろう。 何回でも振れるなら一試行で得られる点数はいくらにでもなりうる。 したがって、カウンタ配列を得点の取りうる範囲分だけ準備する方法は厳密には取れない。 しかし、例えば一億…
ダイスを振りなおせる回数が2回以上の場合でも、 それがある程度までの回数であるなら似たようなコードになる。 dice3.c #include <stdio.h> #include <math.h> #include "dSFMT.h" #define MPT 5 /* point range per a dice throw: [0, MPT] */ #define NT 3 /* storable num</math.h></stdio.h>…
次に、#2のルールにしたがって、同じく一億回試行してみる。 一億回は試行回数であって、ダイスを振る回数はそれ以上になる。 dice2.c #include <stdio.h> #include <math.h> #include "dSFMT.h" #define MPT 5 /* max point per a throw */ #define M (MPT * 2 + 1) /* size </math.h></stdio.h>…