投稿

6月, 2012の投稿を表示しています

C言語 処理時間を計測

clock_tを使った処理時間の計測 #include &ltstdio.h&gt #include &lttime.h&gt /* 処理時間計測に必要 */ int main(void){ /* 宣言 */ clock_t start, stop; /* 計測開始 */ start = clock(); /* 処理 */ int i; for(i=0; i<1000; i++){ printf("%d\n",i); } /* 計測終了 */ stop = clock(); printf("%f sec.\n",(double)(stop-start)/CLOCKS_PER_SEC); return 0; } 実行すると以下のように1000回表示して、そのかかった時間を表示する。windows XPで試しているが、意外と再現性はなく、実行するたびに処理時間はいろいろ変わる。OSの仕事量に影響されているのだろう。それでも目安にはなる。 988 989 990 991 992 993 994 995 996 997 998 999 0.171000 sec. C言語 ANSI C89 Meadow & MinGW GCC 目次

C言語 static 関数

関数にstaticを使って簡易カプセル化。関数にstaticキーワードを使うことで、その関数は同一ファイル内(モジュール内)でしか基本的には呼び出せないようになる。これを利用することで、1ファイルがオブジェクト指向のクラスに相当するような使い方ができそうだ。ということで実験。 main関数 a.c /* a.c */ #include "a.h" int main(void){ funcB1(); /* funcB2(); 直接呼び出せない 簡易カプセル化 */ return 0; } 実装ファイル b.c /* b.c */ #include &ltstdio.h&gt static void funcB2(void){ int num = 1; printf("funcB2 %d\n",num); num++; } void funcB1(void){ int num = 1; printf("funcB1 %d\n",num); num++; funcB2(); } ヘッダファイル a.h /* a.h */ #ifndef A_H #define A_H void funcB1(void); #endif メイン関数から funcB1 関数を呼び出すのだが、staticの付いている funcB2 は呼び出すことはできずコンパイルエラーになる。b.c 内の関数からはstaticなfuncB2にもアクセスできる。外部からのアクセスを制限し、窓口を限定しておくことで、秩序が作られる。ファイル単位で機能をモジュール化し、クラスっぽい扱いが出来るようになる。 funcB1 1 funcB2 1 今回の記事は、具体的なプログラミングを組もうと試していたら関数の構成方法で迷い始めたのがきっかけ。C言語では構成が適当でもプログラムは動く。関数ごとに整理するにしても、オブジェクト指向のような構成方法が示されているわけでもない。実際、入門書には文法的なことは書かれているが、ファイルの構成方法などには触れていない。これからは、構成方法を試行錯誤して行くことになりそうだ。オブジェクト指向ほ

C言語 パスを構造体で管理してみる

自分で使うアプリを少し作ろうかと思うのだが、一気にやる時間もないので、ちょろちょろパーツ単位で作って行こうと思う。C言語では意外と文字列の操作で引っかかったので、その部分を書いておく。 ドラッグ&ドロップでパスを取得し加工する #include &ltstdio.h&gt #include &ltstring.h&gt /* 構造体 各パスを管理 */ struct Path{ char exepath[128]; char filepath[128]; char filepathNew[128]; char inipath[128]; } path; /* 構造体にパスを入れる関数 */ filepath(char *str0,char *str1){ /* a.exe パスをコピー */ strcpy(path.exepath, str0); printf("filepath exepath \t%s\n",path.exepath); /* 新規ini用パスを作る*/ strcpy(path.inipath, path.exepath); /* \0を入れて exe path から a.exe を切り捨てる */ *(path.inipath + (strlen(path.inipath) - 5)) = '\0'; /* 連結 */ strcat(path.inipath, "hpf.ini"); printf("filepath ini filepath \t%s\n",path.inipath); /* ファイルパスを構造体へ */ strcpy(path.filepath, str1); printf("filepath filepath \t%s\n",path.filepath); /* 新規ファイルパスを作る */ strcpy(path.filepathNew, path.filepath); /* ドット以下を切り捨てる */ strtok(path.filepa

C++ 多重継承

Javaでは許されない多重継承がC++では出来るので、ちょっと試してみた。 a.h #ifndef A_H #define A_H /** スーパークラス */ class Aclass{ public: Aclass(); ~Aclass(); void methodA(); protected: int varA; }; /** スーパークラス */ class Bclass{ public: Bclass(); ~Bclass(); void methodB(); protected: int varB; }; /** サブクラス 多重継承 */ class Subclass : public Aclass, public Bclass{ public: Subclass(); ~Subclass(); void methodSub(); }; #endif ヘッダファイルにはクラスの宣言を書いた。2つのクラスを継承したサブクラスを作っている。 a.cpp #include "a.h" #include &ltiostream&gt /** Aclass */ Aclass::Aclass(){ std::cout << "Aclass constructor\n"; varA = 20; } Aclass::~Aclass(){ std::cout << "Aclass destructor\n"; } void Aclass::methodA(){ std::cout << "Aclass::methodA() varA:" << varA << std::endl; } /** Bclass */ Bclass::Bclass(){ std::cout << "Bclass constructor\n"; varB = 30; } Bclass::~Bclass(){ std::cout << "Bclass destru

C言語 文字列

Cの文字列の扱いが独特なので、少し試してみる。 文字列 #include &ltstdio.h&gt #include &ltstdlib.h&gt int main(void){ /* \0が入ると文字列終了と認識 通常は自動で最後に入る */ char str0[] = "str0[] string\0string"; printf("%s\n",str0); /* 強制的に配列を全部表示させてみる 最後に\0(^@)がある 文字列は1byteなので、1byteずつシフトしている*/ int i; for(i=0; i&ltsizeof(str0); i++){ printf("%c",str0[i]); } /* 配列のインデックス指定で表示させる */ char str1[] = "str1[] 文字列のテストです"; printf("\n%s\n",&str1[0]); /* 途中から\0まで表示ということも可能 */ printf("%s\n",&str1[3]); /* ポインタ 文字列最初のアドレスが入っている 配列との差は微妙で宣言以外は同じ扱い 内部は同じ? */ char *str2 = "*str2"; printf("%s\n",str2); /* 便利なアドレスでもアクセスできる */ printf("%s\n",&str2[2]); /* 文字列の応用 一部抜き出してdoubleに変換 */ char *str3 = "param0= 0.345034;comment...", *endptr; double param0 = 0; /* 文字列比較 先頭から6文字目までが同じなら 0 を返す */ if(strncmp(str3,"param0",6)==0){ /* 文字列からdoubleへ

C++ ファイルの分割

C++で書くとソースが長くなって読みにくくなる。そこでファイルを分割するのだが、なるべく標準的な分割方法にしたい。とりあえずヘッダファイルにクラスを宣言(インライン関数可)して、定義をcppファイルに書く。mainは切り離した方が何かとよいと思われるので、別ファイルにしてみた。 オープンソースのソースファイルを見るときなどは、こういう知識がないと、さっぱり分からないということになってしまう。特にヘッダファイルの使い分けが不明だったり。C++の学習は全体像から細部へと向かうつもり。 a.h #ifndef A_H #define A_H //クラスの宣言 class Aclass{ public: Aclass(); ~Aclass(); void method(); }; #endif ヘッダファイルはクラスの宣言を書いておいて、中身の実装部はcppに書くようだ。実際オープンソースのソースファイルを見ると、そういう使い分けになっていた。それなりの規模のクラスだと、ヘッダファイルとクラスファイルが1対1の関係になっているようだが、ヘッダファイルが多すぎると管理しにくくなるので、ある程度関連あるクラスはひとつのヘッダファイルにまとめた方がよさそうだ。 またマクロ #ifndef、#define、#endif を使ってクラスの重複定義を防止している。重複してしまうとコンパイルエラーとなってしまう。多くのファイルを使い始めると必要性が見えてくるようだ。マクロは#ifndef の次の行の #define A_H が「もし定義されていなければコンパイルする」という意味。もし定義されていれば#endifまで無視する。#が付いているので、プリプロセッサの処理となる。 a.cpp #include "a.h" #include &ltiostream&gt //コンストラクタ Aclass::Aclass(){ std::cout << "constructor\n"; } //デストラクタ Aclass::~Aclass(){ std::cout << "destructor\n"; } //メンバ関数 void Acl

C++ new, delete演算子でインスタンス化

C言語のmelloc()とfree()のC++版がnewとdeleteになる。newはメモリ確保時にコンストラクタ、deleteはデストラクタが呼び出せるのでC++では基本的にこちらを使う。 new演算子でインスタンス化 #include &ltiostream&gt //クラス class Aclass{ public: Aclass(); ~Aclass(); void method(); }; //コンストラクタ Aclass::Aclass(){ std::cout &lt&lt "constructor\n"; } //デストラクタ Aclass::~Aclass(){ std::cout &lt&lt "destructor\n"; } //メンバ関数 void Aclass::method(){ std::cout &lt&lt "Aclass::method()\n"; } //メイン関数 int main(void){ //ポインタ宣言 Aclass *oAclass; //newでメモリ確保、そのアドレスをポインタへ oAclass = new Aclass(); //上記をこのように1行で書いてもOK //Aclass *oAclass = new Aclass(); //ポインタなのでこのように扱う oAclass->method(); //この書き方でもOK //(*oAclass).method(); //メモリ解放 delete oAclass; return 0; } ひとつのクラスをnewでインスタンス化し、deleteでメモリ解放している。 constructor Aclass::method() destructor C++言語 Meadow & MinGW GCC 目次

C++ オーバーライド override

名前がオーバーロードと似ているオーバーライド。こちらは継承したクラスでメソッドの上書きをすることを指す。 関数のオーバーライド #include &ltiostream&gt //基底クラス class Aclass{ public: void method(); }; //メンバ関数 void Aclass::method(){ std::cout << "Aclass::method()\n"; } //派生クラス class Bclass : public Aclass{ public: void method(); }; //メンバ関数 オーバーライド 上書きによる再定義 void Bclass::method(){ std::cout << "Bclass::method():override\n"; } //メイン関数 int main(void){ Aclass oAclass; //基底クラスをインスタンス化 Bclass oBclass; //派生クラスをインスタンス化 oAclass.method(); oBclass.method(); return 0; } Aclassを継承したBclassにて、method()を上書きすることで、Aclassに修正を加えることなく、同じ名前の関数を違った機能にすることができる。 Aclass::method() Bclass::method():override C++言語 Meadow & MinGW GCC 目次

C++ オーバーロード overloading

同じ名前の関数を複数定義して、引数の数や型の違いで処理を分けることができる。オブジェクト指向のポリモーフィズム。これを使うことで、スムーズに分岐させることができ、プログラムの保守性が上がる。 関数のオーバーロード #include &ltiostream&gt //クラス class Aclass{ public: Aclass(); void method(double n); void method(double n1, double n2); //overloading private: double PI ; }; Aclass::Aclass(){ PI = 3.141592653; } //メンバ関数 void Aclass::method(double n){ std::cout << "円の面積: " << n*n*PI << std::endl; } //メンバ関数 overload void Aclass::method(double n1, double n2){ std::cout << "円柱の体積: " << n1*n1*PI*n2 << std::endl; } //メイン関数 int main(void){ Aclass oAclass; oAclass.method(10); //引数1つ oAclass.method(10, 100); //引数2つ return 0; } 引数1つだと、半径とみなし、2つだと半径と高さとみなして処理する。 円の面積: 314.159 円柱の体積: 31415.9 C++言語 Meadow & MinGW GCC 目次

C言語 文字列のコピー strcpy

strcpyは文字列を置き換える。 書式は char *strcpy(char *s1, const char *s2); 文字列のコピー strcpy #include &ltstdio.h&gt #include &ltstring.h&gt /* 必要な標準関数 */ int main(void){ char str1[] = "日本"; char str2[] = "Japan"; printf("str1 = %s\n",str1); /* 文字列を置き換える1 */ strcpy(str1, str2); printf("str1 = %s\n", str1); /* 文字列を置き換える2 */ strcpy(str1, "ねこ"); printf("str1 = %s\n", str1); return 0; } 上記を実行すると以下のように文字列が置き換わっている。 str1 = 日本 str1 = Japan str1 = ねこ C言語 ANSI C89 Meadow & MinGW GCC 目次

C++ クラスの継承

クラスを継承することで、クラスの全機能を引き継ぎつつ、新たな機能を加えることができる。 クラスの継承 #include &ltiostream&gt //基底クラス(スーパークラス) class Aclass{ public: Aclass(); ~Aclass(); void method1(); protected: int num; }; //コンストラクタ Aclass::Aclass(){ std::cout &lt&lt "Aclass constructor" &lt&lt std::endl; num= 20; } //デストラクタ Aclass::~Aclass(){ std::cout &lt&lt "Aclass destructor" &lt&lt std::endl; } //メンバ関数 void Aclass::method1(){ std::cout &lt&lt "method1: " &lt&lt num*2 &lt&lt std::endl; } //派生クラス(サブクラス) class Bclass : public Aclass{ public: Bclass(); ~Bclass(); void method2(); }; //コンストラクタ Bclass::Bclass(){ std::cout &lt&lt "Bclass constructor" &lt&lt std::endl; } //デストラクタ Bclass::~Bclass(){ std::cout &lt&lt "Bclass destructor" &lt&lt std::endl; } //メンバ関数 void Bclass::method2(){ std::cout &lt&lt "method2: " &lt&lt num*4 &

C言語 ローカル、グローバル変数

同じ変数名を使って有効範囲を確かめてみる。C言語では有効範囲をスコープという。関数の外で宣言する変数をグローバル変数(外部変数)。関数内で宣言する変数をローカル変数(局所変数)という。ファイルを3つ用意して、それぞれの関数で表示させてみる。 ファイル1 #include &ltstdio.h&gt /* グローバル変数の宣言 初期化はファイル2で行っている。*/ int var; /* fun1 */ void func1(){ printf("func1 %d\n", var); } /* fun2 */ void func2(){ int var = 20; printf("func2 %d\n", var); } /* fun3 */ void func3(){ { int var = 30; printf("func3 A %d\n", var); } printf("func3 B %d\n", var); } /* メイン関数 */ int main(){ func1(); func2(); func3(); func2(); func4(); func5(); func6(); return 0; } ファイル2 #include &ltstdio.h&gt /* グローバル変数の初期化 */ int var = 10; /* fun4 */ void func4(){ printf("func4 %d\n", var); } /* fun5 */ void func5(){ /* externはグローバル変数使用と宣言 上部で宣言済みなので通常省略 */ extern var; printf("func5 %d\n", var); } ファイル3 #include &ltstdio.h&gt /* fun6 */ void func6(){ extern var; /* グローバル変数使用 必須 */ printf(&quo

C言語 ビット演算子

ビット演算子 &lt&lt, &gt&gt バイナリを扱うときによく使う。2進数の演算なので、分かりやすいように2進数表示の関数も自作して2進数で表示させてみた。 #include &ltstdio.h&gt /* 2進数表示関数 */ void binNumShort(unsigned short num) { const BYTE = 8; int i,j; int barray[sizeof(short)*BYTE]; int binary; printf("%s","Binary Number: "); for(i=0; i&ltsizeof(short)*BYTE; i++){ barray[i] = 0; } if(num != 0){ for(i=1; num&gt0; i++){ binary = num % 2; barray[sizeof(short)*BYTE-i] = binary; num = num / 2; } } for(i=0; i&ltsizeof(short)*BYTE; i++){ if(i==BYTE)printf(" "); printf("%d",barray[i]); } printf("\n"); return; } /* メイン関数 */ int main(void) { unsigned short num = 0xff; binNumShort(num); printf("Decimal Number: %d\n",num); binNumShort(num<<1); printf("Decimal Number: %d\n",num<<1); binNumShort(num>>1); printf("Decimal Number: %d\n",num&

C言語 三項演算子(条件演算子) ? :

三項演算子は1行で短く書けるので、if文の代わりにたまに使う。大きな違いは文ではなく式だということ。Cではマクロなどに使うのに適していると思う。式のかたちは以下のようになる。 式1 ? 式2 : 式3 式1が真なら式2となり、偽なら式3となる。 三項演算子 #include &ltstdio.h&gt int main(void) { int num1 = 500; int num2 = 300; printf("%dと%dでは%dが小さいです。\n", num1, num2, num1 &lt num2 ? num1:num2); printf("%dと%dでは%dが大きいです。\n", num1, num2, num1 &gt num2 ? num1:num2); int age = 11; printf("あたなは%sですね。\n",age &lt 20 ? "未成年":"成人"); return 0; } 数値だけでなく、文字列も扱うことができる。 500と300では300が小さいです。 500と300では500が大きいです。 あたなは未成年ですね。 C言語 ANSI C89 Meadow & MinGW GCC 目次はこちら

C言語 乱数 rand()

子供がJavaで作ったプログラムをCに移植してみたら、乱数の部分がうまくいかない。やっぱりCは原理的なことを学習しないと先に進めないと思えた。それがCのよいところ。 乱数 /** 0 以上 1 以下の範囲の乱数値(double) */ #include &ltstdio.h&gt #include &ltstdlib.h&gt #include &lttime.h&gt int main(void){ int i; double ran; printf("RAND_MAX: %d\n",RAND_MAX); /* 同じ値にならないようにtimeで初期化 */ srand((unsigned)time(NULL)); /* まず1から100の間の乱数を求める */ int ran1 = rand()%100+1; printf("rand1(1 to 100): %d\n",ran1); /* 求めた100回以下をループ 最後の値を使用 */ for(i=0; i&ltran1; i++){ ran = (double)rand()/RAND_MAX; } printf("rand(): %f\n",ran); return 0; } Cのrand()は実行環境で違いがあるようだ。RAND_MAXを実行することで、どんな値が出てくるか確認することができる。「32767」と出たので、0から32767の間でランダムに整数が出力されることになる。この値を好きなように計算して、欲しい範囲に設定すればよい。ところが実際には毎回同じ値しか出てこない。擬似乱数を勉強する必要がある・・・ とりあえず定番のtimeで初期化することで、比較的バラバラな値が出るようになった。でも移植したプログラムは頻繁に乱数を利用していたので、数秒以内に乱数を使うと、近い値が並んでしまうことが判明。そこで2重に乱数を使って、多少バラバラになるようにしてみた。Javaだと1行で出来たことがCではこんなになってしまう。そ

C言語 マクロ #define

ソース中に何度も出てくる定数や小さな関数をマクロにすることで、開発効率及び処理速度を上げることが可能。マクロはコンパイルする直前に、プリプロセッサによってマクロ名を使った部分が置き換えられる。同じ処理が複数箇所に書かれる事になるので、定数や小さい処理に向いているが、型は指定できない。マクロのようなものはプリプロセッサ命令という。他に#includeなどがある。 書き方の注意点としては、マクロは1行で書く必要がありセミコロンなどは必要ない。2行に分けて書きたい場合は、\(バックスラッシュ)を使って折り返す。マクロ名と置き換え部の間にはスペースを入れる。マクロ名は区別しやすいように大文字を使うようにするなどルールを決めておいた方がよい。 マクロ #include &ltstdio.h&gt /* 関数形式マクロ定義 三項演算子*/ #define MIN(a,b) ((a)<(b) ? (a):(b)) int main(int argc, char **argv) { /* オブジェクト形式マクロ定義 */ #define CALIBA 440 int num1 = 380; int num2 = 350; /* マクロの使用 */ printf("%dと%dでは%dが小さいです。",num1,num2,MIN(num1,num2)); printf("基準音は%dHzです。\n",CALIBA); /* CALIBAマクロ無効化 */ #undef CALIBA /* 下はコンパイルエラーになる */ /*printf("基準音は%dHzです。\n",CALIBA);*/ return 0; } マクロは関数の中でも定義できる。またundefで途中で無効化することこも可能。マクロの定義は 三項演算子 を使用している。式1 ? 式2 : 式3 の場合は式1が真なら式2となり、偽なら式3となる。 380と350では350が小さいです。 基準音は440Hzです。 マクロを使った定数の型はどうなる? #include &ltstdio.h&gt in

C++ クラスからオブジェクトを複数作る

C++ではCの構造体を拡張してクラスとして扱う。構造体は基本的に型の違う複数変数を扱うもの。対してクラスは変数と関数をまとめて扱うのが基本。クラスを利用するためにはメモリに展開する必要がある。そのことをインスタンス化すると言う。インスタンス化したものをオブジェクトと言う。 実際にC++で試していたら、Cでも構造体を使って似たようなものが出来そうだなぁ?と思って、Cでクラスぽいことをやってみた。構造体内部で関数ポインタを使いまくって、カプセル化したクラスぐらいまでは作れた。しかし・・・かなりソースが混沌としてしまった。たぶん誰がやってもCで見やすいというレベルのソースは書けない気がする。やっぱりクラスを利用したオブジェクト指向プログラミングをするなら素直にC++でやるべきだと思えた。ただCでもオブジェクト指向的プログラミングは可能だということが分かった。 またC++のクラスの書き方はJavaとは大分違うので、C++独特の構造体風クラスの書き方に慣れる必要がある。 クラスのインスタンス化 mainから他のクラスをインスタンス化して実行してみるサンプル。 #include &ltiostream&gt //クラスの宣言 class Box{ public: Box(); //コンストラクタ ~Box(); //デストラクタ void Add(int add); void Sub(int sub); void Clear(); int Get(); private: int n; }; //コンストラクタ 初期設定 Box::Box(){ std::cout &lt&lt "constructor\n"; n = 10; } //デストラクタ メモリ解放 Box::~Box(){ std::cout &lt&lt "destructor\n"; } //メンバ関数(メソッド) Add void Box::Add(int add){ std::cout &lt&lt "Add: " &lt&lt add &lt&lt "\n";

C++ 学習開始

世の中のオープンソースのほとんどが C++(シープラスプラス)で書かれているので、それらを少し読もうとするだけでもC++の知識が必要。ということでCと並行してC++の基礎も学習することにした。 C++はCを拡張してオブジェクト指向プログラミングをできるようにした言語。拡張なのでCで記述したソースファイルは、基本的にC++でもコンパイルができる。オブジェクト指向プログラミングは大規模なプログラミングを多人数で開発するのに向いているため、現在では巨大なプログラムはC++で作られることが多い。 C++は1983年にビャーネ・ストロヴストルップによって公開され、1998年にはISO/IEC C++ 1998として規格化された。最新はISO/IEC C++ 2011。 学習環境はCと全く同じで行うつもり。コンパイラはGCC(g++)を使って、エディタはMeadow。CUIの範囲で基本的なことだけを確認程度にやってみようと思う。Cと重複する部分も多々あるので、そういう部分はCのページに書いて、C++独自の部分のみ扱うつもり。クラス、多重継承、オーバーロード、仮想関数、テンプレート、例外処理等の基本的な学習になると思う。 Hello World! #include &ltiostream&gt int main() { std::cout &lt&lt "Hello World! C++\n"; return 0; } まずはwikiにあるHello Worldから。ソースファイルの拡張子は.cpp。コンパイルはg++を使う。Cでは「printf」を標準的に使うけど、C++ではコンソール入出力にはstdio.hではなくiostreamを使うようだ。「std::cout」(シーアウト)という見慣れない記述となる。これはオブジェクトらしい。「<<」はビットシフトではなく、出力ストリーム演算子。このiostreamを使う理由は、コンソール出力だけでなく、ファイル出力や、通信などでも同じように使える便利さがあるようだ。 もちろんCとの互換性もあるのでstdio.hをインクルードすればprintfも使える。下のコンソールイメージはコンパイルから実行まで。 c:\&gt

C言語 main関数

main(メイン)関数だけのプログラム int main(void) { return 0; } 最小限のプログラム。実行してもそのまま終了するだけ。下の実行イメージにはWindowsXPの場合の表示例。内容的なものは何もない。 基本的にプログラムはmain関数から始まって、main関数で終了する。関数の範囲は { } 波括弧に囲まれた部分でブロックと言う。 はじめの行の「int main(void)」を見てみると、 「int」は関数の戻り値のタイプを表している。つまりint型の整数をOSに返すことになる。この場合は下の行に書かれている「0」を返している。 「main()」はプログラムの開始位置を宣言している。そのためmain関数が複数存在してはいけない。 「(void)」は引数(ひきすう)がないことを意味する。つまりこのmain関数が開始された時点で何も受け取らない。起動時に何らかの情報を受け取る場合は、ここの記述を変える必要がある。 (int argc, char *argv[]) や (int argc, char **argv) など。 こんな感じで引数を取ることができる。コマンドで起動する場合は、同時に引数も打ち込んだり、ドラッグ&ドロップで起動する場合は、ドロップしたファイル情報などを受け取ることができる。 次の行の「return 0;」は終了を意味する。「0」は正常終了したいことをOSに伝える。0以外では異常終了ということになるが、OSがそれに対してアクションすることは稀のようだ。Windowsの場合は、おそらく無視されている。 c:\&gta.exe c:\&gt コマンドライン引数を表示するプログラム #include &ltstdio.h&gt int main(int argc, char **argv) { int i; /* 引数の個数表示 */ printf("argc: %d\n", argc ); /* 引数の文字列表示 */ for(i=0; i&ltargc; i++) { printf("argv[%d]: %s\n",i,argv[i]); }

C言語 printf

便利な出力関数のprintf(プリントエフ)。Javaでもバージョン5から追加されて使えるようになった。コマンドプトンプトに表示する場合は、これだけあれば十分だと思う。他にもputsとかputcharなど、いくつか出力関数はあるのだが、使う必要性はなさそうだ。printfは書式指定ができる便利な関数。 printf 主な書式変換 #include &ltstdio.h&gt int main(void){ int num = 255; /* 10進数 */ printf("%d\n",num); /* 16進数 小文字 */ printf("%x\n",num); /* 16進数 大文字 */ printf("%X\n",num); /* 8進数 */ printf("%o\n",num); /* 複数の指定も可能 */ printf("%d %x\n",num,num); /* 小数 丸められる*/ printf("%f\n",3.141592653); /* 小数 桁全体11、小数点以下10 */ printf("%11.10f\n",3.141592653); /* 指数表示 */ printf("%e\n%e\n",0.00003,456.789); /* 符号表示 */ printf("%+e\n%+f\n",-0.067,2.345); /* アドレス表示 */ printf("%p\n",&num); /* 4桁右揃え */ printf("%4d\n",1); /* 4桁右揃え 余白を0で埋める */ printf("%04d\n",12); /* 単純文字列 */ printf("text\n"); /* 文字列 */ printf("%s\n","text"); /* ch

C言語 関数のプロトタイプ

このBlogでの多くのサンプルは、メイン関数の前に、その他の関数を定義してある。メイン関数は一番最後に書いている。関数が少なければ、これでもよいのだが、関数が数十となってくると読みにくくなってしまう。そこで関数のプロトタイプを使ってこの問題を解決する。C言語はいろいろな書き方が出来てしまうが、プロトタイプを宣言するのが正しい書き方のようだ。 関数のプロトタイプ #include &ltstdio.h&gt /* プロトタイプ 関数1 関数2 */ void function1(void); void function2(int num); /* メイン関数 */ int main(void){ int num = 123; function1(); function2(num); return 0; } /* 関数1 */ void function1(void){ printf("function1\n"); } /* 関数2 */ void function2(int num){ printf("function2 %d",num); } プロトタイプを使うことで、ファイルにどんな関数があるのか目次のように確認できる。 function1 function2 123 C言語 ANSI C89 Meadow & MinGW GCC 目次はこちら

C言語 2ヶ月学習してみて

C言語かじりはじめてから約2ヶ月経った ANSI C89 の範囲内で、エディタは Meadow。コンパイラーは MinGW GCC を使用。OSはWindows XP。プラットフォーム非依存の、なるべくピュアなC言語のところだけを学習中。注意している点は学習間隔をあけないこと。今のところ比較的成功している。Java学習のときは半年ぐらい間隔があいたりしていたので。でも学習内容をプログラムにまとめてBlogにアップしたりしているので、思ったよりも学習スピードはのろい。それでも現状でwavファイルを加工するプログラムぐらいは作れるようになった。現時点で思うことを書いてみる。 C言語はメモリを意識しないと組めない これは良い勉強になったと思う。Javaでは、あまり意識しなくても動いてしまうので手軽なのだが、Cではちゃんとイメージして組まないと、とんでもないことになる。抽象的なJavaに対して現実的なCというところ。Cではメモリのアドレスとポインタの動きを正確に把握することが、すごく重要だと思えた。メモリを意識し始めると、プログラムに応じて、メモリをたっぷり使って高速に処理させたり、スピードを犠牲にしても省メモリで組むなど、自在にコントロールが出来るようになる。今後Javaで組む場合にもCのメモリ管理スキルはプラスになるはず。Javaの隠れたポインタを意識しまくることになるだろう。 C言語は環境に依存する コンパイラによっても違いが出るし、プラットフォームでも違いが出る。教科書的に学習しても、それが使えるとは限らない。型なども環境でサイズが違ったりするので、Javaの固定的な仕様からすると、何ともつかみ所のない言語。まぁそこにローレベルなプログラミングを実感できるのだが。 とっつきにくさ 推奨でない関数等が平気で存在している。廃止することもできないらしく、いつまでも存在し続けている。入門では scanf なんて必ず出るのに実際には使わないという。Cにはそういう部分が結構あって戸惑うところ。使わないなら学習する必要もないけど、読むという意味では理解しておく必要があったりする。また同じようなことを実現する場合、いくつかの手段があるのが普通で、その違いが十分理解できてない。たぶんハードウェアレベルの勉強もしないと、ちゃんとした理解につながらないような気が

C言語 演算子 (算術 代入 比較 論理)

四則演算 +, -, *, /, % 代表的な算術演算子。基本的なところも書いておこう。 #include &ltstdio.h&gt int main(void){ int a=20,b=3; printf("加算(int) %d+%d = %d\n",a,b,a+b); printf("減算(int) %d-%d = %d\n",a,b,a-b); printf("乗算(int) %d*%d = %d\n",a,b,a*b); printf("除算(int) %d/%d = %d\n",a,b,a/b); printf("剰余(int) %d%c%d = %d\n",a,'%',b,a%b); printf("乗算(float) %d/%d = %f\n",a,b,(float)a/b); return 0; } %の表示で少し悩んでしまった。普通はどうやるのかな? 加算(int) 20+3 = 23 減算(int) 20-3 = 17 乗算(int) 20*3 = 60 除算(int) 20/3 = 6 剰余(int) 20%3 = 2 乗算(float) 20/3 = 6.666667 代入演算子 =, +=, -=, *=, /=, %= 算数、数学のイコールとは扱いが違うので、プログラム初心者は違和感を感じるところ。 #include &ltstdio.h&gt int main(void){ int a=20,b=3; printf("まず「a」には「%d」が入っている\n",a); printf("代入 a=%d aは %d になる\n",b,a=b); a=20; printf("加算して代入 a+=%d aは %d になる\n",b,a+=b); a=20; printf("減算して代入 a-=%d aは %d になる\n",b,a-=b); a=20; printf("乗算して

C言語 realloc 動的メモリのリサイズ

確保していたメモリが足りなくなった場合、メモリを拡張する必要がある。C言語ではreallocを使うようだ。早速試してみた。 reallocのお試し #include &ltstdio.h&gt #include &ltstdlib.h&gt /* 動的メモリのリサイズ */ int main(void){ float *buff, sample = 0.000001; int bsize = 2, fsize = 32, i; /* 初期メモリ確保 */ buff =(float*)malloc(sizeof(float)*bsize); if (buff == NULL) { printf( "error malloc\n" ); exit(1); } /* 書込み */ for(i=0; i&ltfsize; i++){ if(bsize == i){ bsize *= 2; buff =(float*)realloc(buff,sizeof(float)*bsize); if (buff == NULL) { printf( "error realloc %d\n",i); exit(1); } sample += sample; } buff[i] = sample; printf("%d:\t%f\n",i,buff[i]); } /* メモリ解放 */ free(buff); return 0; } はじめ float 2つ分のメモリを確保し、for文でそのメモリに数値を入れていく。メモリが足りなくなったら、メモリを2倍にして対応する。さらに足りなくなったら、また2倍にする。これを繰り返して行く。Javaでは苦労したメモリの拡張がC言語では結構簡単に実現できてしまう。音加工では、よく使う処理なので、便利に思えた。ソースは、かなり自分勝手に書いているので間違っているかもしれない。とりあえず動いているというレベルです。 0: 0

C言語 定数 const, enum

定数は個人的に使用頻度は少なさそうだが、こんなこともできるというレベルのメモ。 定数 const #include &ltstdio.h&gt int main(void) { const float PI = 3.141593; printf("PI = %f\n", PI); return 0; } constキーワードを付けると、変数ではなく定数となり、値を変更することが出来なくなる。値を変更されては困る場合に使用する。定数に使用する名前は区別するために大文字が好ましい。 PI = 3.141593 Cではconstではなくマクロ(#define)を使った定数もよく見かける。マクロについては こちらのページ 。 列挙型 enum #include &ltstdio.h&gt int main(void) { enum {a,b,c}; printf("a:%d\nb:%d\nc:%d\n", a, b, c); enum {d, e=10, f, g}; printf("d:%d\ne:%d\nf:%d\ng:%d\n", d, e, f, g); return 0; } これも定数で自動で0から整数が割り振られる。値を変更することはできない。d,e,f,gの途中で数値を代入すると、その番号を基準に以降は+1されていく。整数に名前を付けて管理したいときに使う。 a:0 b:1 c:2 d:0 e:10 f:11 g:12 列挙タグ enum #include &ltstdio.h&gt int main(void) { enum enote {a,as,b,c,cs,d,ds,e,f,fs,g,gs}; enum enote note; note = d; printf("note d:%d\n\n", note); printf( "a:%d\n" "b:%d\n" "c:%d\n" "d:%d\n&quo

C言語 複数ファイルをコンパイル

プログラムの規模が大きくなってくると、機能ごとにファイルに分けたほうがよい。そうすることで管理、再利用などがしやすくなる。複数ファイルのコンパイル方法は、拡張子が「.h」のヘッダファイルによって関連付けることで実現する。以下は3つのソースファイルと、ひとつのヘッダファイルで構成されている。内容的には10進数を入力すると、2進数と16進数に変換して表示するプログラム。各進数ごとにファイルを分けてみた。 main関数があるファイル main.c /* main.c */ #include &ltstdio.h&gt #include "nbase.h" int main(void){ int num; char str[10], buf[512]; printf("Decimal Number: "); setbuf(stdout,buf); fgets(str,10,stdin); fflush(stdout); /* 文字から整数へ変換 */ num = atoi(str); /* Binary Number */ binNum(num); /* Hexadecimal Number */ hexNum(num); return 0; } atoi関数は文字列を数字に変換する。このプログラムは整数入力前提だが、文字が入力されると手前まで有効となる。文字のみだと0として扱う。2進数と16進数の表示は以下の別ファイルの関数に投げている。 2進数変換 bin.c /* bin.c */ #include &ltstdio.h&gt void binNum(int num){ int i,j; int barray[64]; int binary; printf("%s","Binary Number: "); if(num == 0){ printf("%d\n",num); }else{ for(i=0; num&gt0; i++){

C言語 予約語

変数などに付ける識別子(名前)には予約語を使うことは出来ない。C言語の予約語は以下の通りでひじょうに少ない。ついでに識別子は半角英数字を使うが、先頭には数字は使えない。大文字小文字は区別される。 C89の予約語 auto int break long case register char return const short continue signed default sizeof do static double struct else switch enum typedef extern union float unsigned for void goto volatile if while C99の予約語 inline restrict _Bool _Complex _Imaginary 予約語を見るとmainとかは予約語ではないのね。ということでmainを変数名にして動かしてみた。 mainを変数名で使ってみる #include &ltstdio.h&gt int main(void){ int main; main = 100; printf("main = %d\n",main); return 0; } 問題なくコンパイルできて、実行もできたが、紛らわしいのでやるべきではないね。 main = 100 C言語 ANSI C89 Meadow & MinGW GCC 目次はこちら

C言語 wavファイルのヘッダを読む

オーディオフォーマットであるwavのヘッダーを読むプログラムを作ってみる。Windowsなら普通はAPIを使って、こんな部分は自分で作らないものだけど、wavの勉強と、プラットフォーム非依存という意味もあって作ってみた。でも、きっちり作るのは面倒なので、自分が使っているwavの範囲で動けばよい。読み込みたいデータはfmtだけ。fmt(オーディオファオーマット)には基本的な、チャンネル数、ステレオ/モノラル、サンプリング周波数、ビット数などが書かれている。他にもいろいろな情報が書けるようだが、LISTぐらいしか見たことがないので、LISTが出てきたら、その部分をスキップして、データの部分に飛ばすというプログラム。実際に使う場合は、ヘッダにある基本情報を取得することと、データの開始位置を把握するのが目的。その予備実験。 #include &ltstdio.h&gt #include &ltstdlib.h&gt #include &ltstring.h&gt /* format chunk 構造体 */ struct FormatChunk { char id[5]; unsigned int size; unsigned short format; unsigned short channels; unsigned int samplerate; unsigned int bytepersec; unsigned short blockalign; unsigned short bit; }fmtchunk; /* バッファー 構造体 */ struct Buff { FILE *fpr; unsigned char bufchar; unsigned char buf[5]; unsigned int bufint; unsigned short bufshort; } buff; /* 文字列 4byte ビッグエンディアン*/ void readchar(){ int i,size; size = fread(buff.buf, sizeof(unsigned char), 4, buff.fpr); } /* 数値 4byte

C言語 音声ファイル加工 音量

イメージ
オーディオファイルの音量調整プログラム。gainの設定値で全体の音量を変えられる。以下のソースはサンプルなので、ヘッダレスのrawデータで32bit-float専用。gainの設定はプロンプトから入力する。実用的なプログラムにするには、ヘッダ情報の読込みと、それに基づいた処理が必要。 #include &ltstdio.h&gt #include &ltstdlib.h&gt #include &ltstring.h&gt int main (int argc, char *argv[]){ FILE *fpr, *fpw; int i, fileSize=1024; unsigned char str1[256], *str2; /* gainの初期値 */ float *buff, *buffout, gain=1.0; char strgain[10]; for(i=0; i&ltargc; i++){ printf("%d = %s\n", i, argv[i]); } fpr = fopen(argv[1], "rb"); if (fpr == NULL){ printf("error rb"); getchar(); exit(EXIT_FAILURE); } strcpy(str1,argv[1]); str2 = strtok(str1,"."); strcat(str2,"_new.wav"); fpw = fopen(str2, "wb"); if (fpw == NULL){ printf("error wb"); getchar(); exit(EXIT_FAILURE); } /* プロンプトからgain値を入力 */ printf("gain = "); fgets(strgain,10,stdin); /* atof 浮動少数点文字列を浮動少数点値に変換

C言語 malloc 動的メモリ

メモリにオーディオファイルをまるまるロードした上で、コピーファイルを作るプログラム。一気にメモリに読み込むために高速に処理することが出来る。また、こうしないと大きなファイルを格納する配列が作れないようだ。 mallocを使ったwavファイルコピー #include &ltstdio.h&gt #include &ltstdlib.h&gt #include &ltstring.h&gt int main (int argc, char *argv[]){ FILE *fpr, *fpw; int i, fileSize=1024; unsigned char str1[256], *str2; float *buff; for(i=0; i&ltargc; i++){ printf("%d = %s\n", i, argv[i]); } fpr = fopen(argv[1], "rb"); if (fpr == NULL){ printf("error rb"); getchar(); exit(EXIT_FAILURE); } strcpy(str1,argv[1]); str2 = strtok(str1,"."); strcat(str2,"_new.wav"); fpw = fopen(str2, "wb"); if (fpw == NULL){ printf("error wb"); getchar(); exit(EXIT_FAILURE); } /* ファイルサイズ(バイト)を調べる */ fseek(fpr, 0L, SEEK_END); /* ファイルサイズ単位をfloatにするため4で割る */ fileSize = ftell(fpr)/4; /* ファイルポインタの位置は先頭に戻す */ fseek(fpr, 0L, SEEK_SET); /* 動的メモリ float(

C言語 wavファイルのエンディアン変換 (union)

オーディオrawデータのリトルエンディアンとビッグエンディアンを相互に変換するプログラム。前回作った プログラム はchar単位だったけど、unionの応用ということでfloat単位で処理してみた。データは32bit-float専用。 wavファイルエンディアン変換 (union) #include &ltstdio.h&gt #include &ltstdlib.h&gt #include &ltstring.h&gt union byteorder{ float bfloat; /* 4byte */ unsigned char bchar[4]; /* 1byte ×4 */ }; int main (int argc, char *argv[]){ union byteorder border; FILE *fpr,*fpw; int i; unsigned char str1[256], *str2; for(i=0; i&ltargc; i++){ printf("%d = %s\n", i, argv[i]); } fpr = fopen(argv[1], "rb"); if (fpr == NULL){ printf("error rb"); getchar(); exit(EXIT_FAILURE); } strcpy(str1,argv[1]); str2 = strtok(str1,"."); strcat(str2,"_new.wav"); fpw = fopen(str2, "wb"); if (fpw == NULL){ printf("error wb"); getchar(); exit(EXIT_FAILURE); } /* float単位で処理 */ for(;!feof(fpr);){ /* read float単位*/

C言語 ファイルサイズの取得

ドラッグ&ドロップしたファイルのサイズを取得するプログラム。 wavファイルのサイズを取得 #include &ltstdio.h&gt #include &ltstdlib.h&gt int main(int argc, char *argv[]){ FILE *fpr; int fileSize; fpr = fopen(argv[1], "rb"); if (fpr == NULL){ printf("error rb"); getchar(); exit(EXIT_FAILURE); } /*ファイルポインタをファイル終端位置に設定 */ fseek(fpr, 0L, SEEK_END); /* ファイルポインタの位置を取得 */ fileSize = ftell(fpr); /* ポインタ位置 = ファイルサイズ */ printf("filesize: %s = %d byte\n",argv[1], fileSize); fclose(fpr); printf("success\n"); getchar(); return 0; } ポインタの位置情報からサイズを取得している。fseek()でポインタをファイルの終端に移動して、ftell()で位置を取得する。位置はそのまま先端からのバイト数なので、そのままファイルサイズとみなしている。 filesize: C:\sample.wav = 352844 byte success C言語 ANSI C89 Meadow & MinGW GCC 目次はこちら

C言語 wavファイルのエンディアン変換

波形編集ソフトAudacityでビックエンディアンのRawデータ出力が出来そうもなかったので、C言語でエンディアン変換プログラムを組んでみた。データは32bit-float専用。リトルエンディアンをビッグエンディアンへ変換し、またその逆もできる。 wavファイルエンディアン変換 #include &ltstdio.h&gt #include &ltstdlib.h&gt #include &ltstring.h&gt int main(int argc, char *argv[]){ FILE *fpr,*fpw; int size, i, byteflag = 1; unsigned char str1[256], *str2, byteR[4], byteW[4]; unsigned char in = 0, out = 0; for(i=0; i&ltargc; i++){ printf("%d = %s\n", i, argv[i]); } fpr = fopen(argv[1], "rb"); if (fpr == NULL){ printf("error rb"); getchar(); exit(EXIT_FAILURE); } strcpy(str1,argv[1]); str2 = strtok(str1,"."); strcat(str2,"_new.wav"); fpw = fopen(str2, "wb"); if (fpw == NULL){ printf("error wb"); getchar(); exit(EXIT_FAILURE); } /* char 1byte単位で処理 */ for(;!feof(fpr);){ /*read*/ fread(&in , sizeof(char), 1, fpr); if(ferror(fpr)){ perro

C言語 ドラッグ&ドロップで読込み書込み

イメージ
CUIベースでCの学習をしているのだが、実用的なアプリにはGUIの必要性を感じていた。GUIは各OSに依存する部分。マルチプラットフォームを意識するとファイルサイズやスピードが犠牲になってしまう。見た目もイマイチだったり・・・ そこでCUIアプリでも、そこそこの使い勝手を維持できないか調べていたら、作ったexeにファイルをドラッグ&ドロップして起動できることが分かったので、ちょっと作ってみた。この方法であれば、それほどストレスなく、ファイル操作できそうだ。CUIアプリなら手軽にプログラムを作れるし、exeファイルのサイズも最小にできる。何と言ってもネイティブなので起動が高速。ちょっとやる気になってきた。 wavファイルをexeにドロップすると読込み書込みを行うプログラム #include &ltstdio.h&gt #include &ltstdlib.h&gt #include &ltstring.h&gt int main(int argc, char *argv[]){ FILE *fpr,*fpw; unsigned char buf[1024]; int size; int i; char str1[128]; char *str2; for(i=0; i&ltargc; i++){ printf("%d = %s\n", i, argv[i]); } fpr = fopen(argv[1], "rb"); if (fpr == NULL){ printf("error rb"); gets(argv[0]); exit(EXIT_FAILURE); } strcpy(str1,argv[1]); /* 文字列コピー */ str2 = strtok(str1,"."); /* 文字列を.で分割 */ strcat(str2,"_new.wav"); /* 文字列連結 */ fpw = fopen(str2, "wb"); /* 新規ファイル作成 */ if

C言語 ビットフィールド bitfield

ビットフィールド(bitfield)を使うことでメモリ領域を任意のビットで扱うことができる。方法は構造体とほとんど同じ。基本となる型はintかunsignedを使う。下の例ではunsignedをC言語にはない1ビットのbooleanとして扱ってみる。つまり下位1ビットしか扱わないので、0か1しか扱えなくなる。 ビットフィールド #include &ltstdio.h&gt struct{ unsigned boolean: 1; }Boolean; int main(void){ Boolean.boolean; int i; for(i=0; i<10; i++){ Boolean.boolean = i; printf("%d = %d\n",i, Boolean.boolean); } return 0; } structでビットフィールドを宣言する。「unsigned boolean: 1」の「1」は1ビットのこと。このビットフィールドbooleanに10進数を0から9まで入れていって、表示させてみると以下のようになる。 0 = 0 1 = 1 2 = 0 3 = 1 4 = 0 5 = 1 6 = 0 7 = 1 8 = 0 9 = 1 ビットフィールド また上記の宣言部分をunsignedではなくintにすると、プラスマイナスを扱うようになるので、1ビットの場合は0か-1というかたちになる。 #include &ltstdio.h&gt struct{ int boolean: 1; }Boolean; int main(void){ Boolean.boolean; int i; for(i=0; i<10; i++){ Boolean.boolean = i; printf("%d = %d\n",i, Boolean.boolean); } return 0; } 0 = 0 1 = -1 2 = 0 3 = -1 4 = 0 5 = -1 6 = 0 7 = -1 8 = 0 9 = -1

C言語 共用体 union

共用体は構造体に似ているが、メモリ管理方法が違う。構造体がメンバ変数それぞれのメモリ領域を確保するのに対して、共用体では、すべてのメンバ変数が、ひとつのメモリ領域しか使えない。つまり使える変数は1つだけ。メモリ領域はメンバ変数の中で一番大きな型が確保される。共用体のメリットとしては、メモリ節約が行える。 共用体 #include &ltstdio.h&gt union uni{ unsigned int int1; unsigned short short1; unsigned char char1; }; int main(void){ union uni ouni; ouni.int1 = 0xfedcba98; printf("int1 = %8x\n",ouni.int1); printf("short1= %8x\n",ouni.short1); printf("char1 = %8x\n",ouni.char1); ouni.char1 = 0xf; printf("int1 = %8x\n",ouni.int1); printf("short1= %8x\n",ouni.short1); printf("char1 = %8x\n",ouni.char1); return 0; } 3つの異なる型のメンバ変数を用意し、まず一番大きなintに16進数で値を入れる。そして、それぞれのメンバ変数を表示してみる。結果的にはそれぞれの型の領域までしかアクセスしていないのが分かる。次に一番小さい型のcharに16進数のfを代入。そして、それぞれのメンバ変数を表示してみる。書き換えられるのはcharの領域までで、それ以上の桁に関しては前回の値がそのまま維持されているのが分かる。 int1 = fedcba98 short1= ba98 char1 = 98 int1 = fedcba0f short1= ba0f char1 = f C言語 ANSI C89 Meadow & Mi

C言語 エスケープシーケンス

多くのプログラム言語で共通のエスケープシーケンス。よく使うものは限られていると思う。 代表的なエスケープシーケンス #include &ltstdio.h&gt int main(void){ printf("escape sequence\n改行\n"); /* 改行 よく使う */ printf("\ttab\n"); /* タブ */ printf("\\\n"); /* \ 円マーク、バックスラッシュ */ printf("\?\n"); /* ? クエッション */ printf("NULL \0 "); /* NULL */ printf("\n\'\n"); /* ' シングルクォーテーション */ printf("\"\n"); /* " ダブルクォーテーション */ printf("8進数0101= \101\n"); /* 8進数で文字表示 */ printf("16進数0x41= \x41\n"); /* 16進数で文字表示 */ return 0; } これ以外にもエスケープシーケンスはあるけど、ほとんど使わない。また参考までに8、16進数の文字コードの文字表示もやってみたが、これもあまり使わないと思う。 escape sequence 改行 tab \ ? NULL ' " 8進数0101= A 16進数0x41= A C言語 ANSI C89 Meadow & MinGW GCC 目次はこちら