MinGW
楽で快適なプログラミング言語など、ある訳が無いと知りつつも、
ハンドルを切ろうにも重くて切れないC#、
敷居が低そうに見えて、その低い敷居にどうしてもつまずいてしまうPython、
それがうまくいかないならば、残るはあのcしかない?!
MinGW はWindows上で動くUNIX的なOS機能を持ったシステム。文字通りミニマム(最小限度)のc。PythonやC#のような華やかさは無いが、必用にして十分なプログラミング言語と言える。
●
MinGW (ミン・ジー・ダブリュー)のダウンロード
MinGW Downloas
Download をクリックして mingw-get-setup.exe が読み込まれたら、このセットアップツールをInstallします。
mingw32-baseとmingw32-gcc-g++ をチェックします。
インストールするディレクトリを指定する画面が出ます。C:\MinGW のままでよければContinueボタンを押します。私はDドライブの空き容量が余っていたため "D:\MinGW"
に変更して、Changes を押し Apply を指示しました。
●
準備
スタートボタン→WindowsシステムツールのCommand Promptを
マウスの左ボタンで押さえてデスクトップ画面の適当な場所に置きます。
WindowsアクセサリのNotepadも同じようにデスクトップに置きます。
「サクラエディタ」をネットで検索し、ダウンロードします。短いBATファイルなどはNotepadで作れますが、長いソースファイルを編集する場合はサクラエディタが便利になってきます。
●
BATファイル
プログラムを作成するための作業フォルダを d:\temp\mingw にする場合は、
Notepad を使って、次のようなバッチファイルを用意します。
1)作業フォルダに入るためのBATファイル
フォルダ: c:\users\ユーザー名
ファイル名: gocc.bat
内容:
chcp 65001
d:
cd \temp\mingw
1行目は日本語の文字化け防止のためです。
2,3行目で作業ディレクトリに変更しますが、自分の環境に合わせてください。
2)コンパイル実行のBATファイル
フォルダ: d:\temp\mingw
ファイル名: cc.bat
内容:
path \MINGW\BIN
gcc -Wall -o test test.c
●
プログラムソースファイル
ソースファイルを作業フォルダに作ります。
フォルダ: d:\temp\mingw
ファイル名: test.c
例:
#include <stdio.h>
int main()
{
printf("Hello World
\n");
return 0;
}
●
コンパイル実行
Command Prompt を呼び出し、黒い画面が表示されたら gocc を入力すると作業フォルダに入れます。
次にcc.bat を実行してプログラムをコンパイルします。
エラーがなければ test.exe が生成され、上の画面のようになるはずです。
次に完成した test.exe を実行してみます。
●
printf関数とscanf関数
c言語を習うと最初に出てくる printf() はディスプレイに表示する関数で、第1引数に印字したい文字列を、第2引数以降に印字したい変数名を指定して呼び出します。
scanf() は標準入力(キーボード)から入力する関数で、第1引数に入力する書式を指定し、第2引数以降は入力する変数のアドレスを指定します。
printf()とscanf()は、c言語への第一歩で、慣れるまでいろいろ試してみてください。例えば後に出てくる資料などを参考にすれば簡単な電卓や、もっと高級な関数電卓などの自作も夢ではありません。実際にプログラミングしてみることが、c言語に近づく唯一の近道です。
#include <stdio.h>
int main() {
int a,b,ans; //
int型変数 a,b,ans を宣言
printf("Input A\n"); //
キー入力を促す表示
scanf("%d",&a); //
変数aを10進入力
printf("A= %d\n",a); //入力した値
a を表示
printf("Input B\n"); //
キー入力を促す表示
scanf("%d",&b); //
変数bを10進入力
printf("B= %d\n",b); //入力した値 b
を表示
ans = a + b; //
演算
printf("ANS %d\n",ans); // 結果を表示
return 0; //プログラム終了
}
実行してAとBに値を入れると
★
複数項目を出力する
const char *hw = "Sells amount: "; //文字列データ
hw
int x = 12300; //
整数型データ x
printf("%s %d", hw, x); //
"文字列型 整数型" hw,x
結果
Sells amount: 12300
★
16進数の入力と表示
scanf("%x",&a);
printf("A= %x\n",a);
●
C言語の基本文法
★コメント(注釈)
// から改行まではコメント
/* と */ で囲まれた全文字はコメント(改行があっても)
★ステートメント(文)
文の終わりにはセミコロン(;) を付ける。
大文字と小文字は区別される。
1行に複数の文を書いてもよい。
予約語の途中にスペースや改行を入れてはならないが、それ以外の場所であれば、見やすくするための改行、スペース、タブを任意に使うことができる。
プログラムの構造を見やすくするため、慣例としてブロックごとにインデント(字下げ)を使うが、文法上の規制ではない。
例
int main(void)
{
int i;
for (i = 1; i <= 20; i++)
{
if (i % 2 == 0)
{
printf("%d\n",
i * 2);
}
}
return 0;
}
原則的には上記のように対を成すブロックの { と } の字下げを一致させるが
int main(void) {
int i;
for (i = 1; i <= 20; i++) {
if (i % 2 == 0) {
printf("%d\n",
i * 2);
}
}
return 0;
}
のように記述される場合も多い。
★変数の型
型
バイト数
値
文字型
char
1
-128〜127
unsigned
char 1 0〜255
整数型
short int 2 -32768〜32767
unsigned
short int 2 0〜65535
int 4 -2147483648〜2147483647
unsigned
int 4
0〜4294967295
浮動小数点型
float
4 3.4e-38,〜3.4e+38
double
8
1.7e-308〜1.7e+308
★
数値
10進数 123
16進数 0xffb0
2進数 0b10001001
★変数の宣言
変数は使用する前に型と名前を必ず宣言する。宣言と同時に代入することもできる。
char zo; // キャラクタ型変数
zo の宣言
int num,tx; // int型変数numとtxの宣言
int mem4 = 100; // int型変数mem4の宣言と同時に代入
ある関数の中で宣言した変数はその関数の中でのみ有効なローカル変数となる。
関数の外で宣言した変数はグローバル変数と呼ばれ、メモリは常駐する。
なお、関数の中で使う変数の種類が多くなることが予定されている場合、入り口でこれらの関数を予め宣言した状態でコンパイルすると [-Wunused-variable] という警告が多く出てしまいます。こうした場合は、関数の外で宣言しておき、後に関数の中に宣言文を移動させます。
★定数の宣言と代入
const データ型 定数名 = 初期値;
const int x = 100;
const char name1[] = "Ichiro Suzuki";
★書式(フォーマット)指定子
標準入出力で使用される入出力フォーマット。例えば "%5.2f"は整数部5桁と小数部2桁の実数
指定 型 内容 例
%c char
1文字を出力
"%c"
%s char * 文字列を出力 "%8s", "%-10s"
%d int, short
整数を10進で出力 "%-2d","%03d"
%u unsigned int, unsigned short 符号無し整数10進出力 "%2u","%02u"
%o int, short,unsigned int, unsigned short 整数8進出力 "%06o","%03o"
%x int, short,unsigned int, unsigned short 整数16進出力"%04x"
%f float
実数を出力 "%5.2f"
%e float 実数を指数表示出力
"%5.3e"
%g float 実数を最適な形式で出力
"%g"
%ld long 倍精度整数を10進で出力 "%-10ld"
%lu unsigned long 符号なし倍精度整数を10進で出力
"%10lu"
%lo long, unsigned long 倍精度整数を8進で出力
"%12lo"
%lx long, unsigned long 倍精度整数を16進で出力
"%08lx"
%lf double 倍精度実数を出力
"%8.3lf"
★エスケープ文字
\記号(英記号のバックスラッシュ)で特殊文字の出力
\a 警報音
\n 復帰改行
\f 改ページ
\' シングルクォーテーション
\" ダブルクォーテーション
\xhh 16進数コード文字
\0 nul
\\ \
★演算
算術演算子
+ , - 加算、減算
* , / , % 乗算,
除算, 剰余
比較演算子 (比較演算の結果は正1が偽0が返される)
< , <= 小、小またはイコール if(a
<= 3) もしaが3より小さいか等しいなら
> , >= 大、大またはイコール
== イコール if(a==1) もしaが1なら
!= ノットイコール等しくない if(a
!= b) もしaとbが等しくないなら
代入演算子
= 左項←右項
+= , -= a+=b
はa=a+b
*= , /= , %= a*=b は a=a*b
インクリメント、デクリメント演算子
++ , -- a++ は a=a+1
ビット演算子
| ビットor
& ビットand
^ ビットxor a
^= 0x80; aのbit7 を反転
論理演算
! 否定 if(!a)
もしaが0なら
|| 論理和 if(x
> 10 || y < 20) Xが10より大か、yが20より小なら
&& 論理積 if(x
> 10 && y < 20) Xが10より大で、かつyが20より小なら
シフト演算子
<< ビット左シフト
y = x << 3; xを3ビット左シフトしてyに代入
>> ビットの右シフト
キャスト
( 型指定 ) データを指定型に変換
sizeof演算 データ型および変数のサイズを得る
sizeof(データ型)
sizeof(変数名)
★制御文
if文
if (x == 5) { // もし(条件式)なら
,,,
}
if (x > 5) { // もし(条件式)なら
,,,
}
else { // それ以外なら
,,,
}
if (x == 5) { // もし(条件式)なら
,,
}
else if ( x == 6) { // ではなく(条件式)なら
,,,
}
else { // それ以外なら
,,,
}
switch文
switch (x) { // パラメーターxの値によって
case 0:
// x が 0 のときの処理
break;
case 1:
// x が1 のときの処理
break;
default:
// それ以外のときの処理
break;
}
while文
while(条件式) { //条件が成立する間
処理1;
処理2;
…
}
do while文
do { //処理をして
処理1;
処理2;
…
while (条件式); //条件が成立する間
for文
for (int i = 0; i < 10; ++i) { //初期化 ; 条件成立の間 ; 繰り返す処理
,,,
}
★配列
int Arr[3]; //int型配列Arr[]
の宣言
int Arr[3] = { 1, 2, 3 }; //配列の宣言と初期化
int nums1[3][5] = { //二次元配列の宣言と初期化
{0, 1, 2, 3, 4},
{1, 2, 3, 4, 5},
{2, 3, 4, 5, 6} };
宣言時に要素数が未定の場合は int abc[]; のようにする。
MinGWでは、宣言した範囲外の配列をアクセスしてもMinGWではエラーにならない。
char a[] = {'A','B','C'}; とした場合は、a[0],a[1],a[2]にそれぞれ'A','B',C'が入る。
★アドレスの表記方法
変数 a のアドレスは &a
配列 ab[] の先頭アドレス は ab
"abc"という文字列の先頭アドレスは "abc"
関数 int fnc() のアドレスは fnc
★ポインタ
c言語では、メモリ内のデータを値としても使うが、メモリの番地としても扱うことができる。例えばあるメモリに書かれた fc00 というデータは、c言語が変数の値として使用する場合もあり、
fc00 いう番地を記憶するために使う場合もる。
*p という表記において、p はポインタ型の変数と呼ばれる。
p にアドレスの値をセットすると *p はアドレスp に入っているデータということになる。
pを、++したり--すると、隣接するアドレスのデータをアクセスできる。
また、配列や文字列や関数の先頭アドレスとしても使うことができる。
#include <stdio.h>
int main(void) {
char tx[] = "ABC"; // char型配列変数tx[]
の宣言と初期化
char *pt; //
char型ポインタ変数ptを宣言
pt = tx; //
変数ptにtx[]の先頭アドレスをセットする
printf(pt); // printf関数が、pt (つまり tx の先頭アドレス)から印字
return 0;
}
実行すると "ABC"が印字される。
printf("ABC"); と異なり printf(pt); はptに異なる文字列のアドレスをセットすることで、異なった内容を印字できる。
★関数
戻値型 関数名(型名 引数1,型名 引数2,,,) {
処理
return オブジェクト
}
戻り値も引数も無い場合は
void 関数名(void) {
処理
}
例
#include <stdio.h>
int ad(int,int);
int main() {
int ans;
ans = ad(2,3); // 引数に2と3をセットして関数adを呼び出し、戻り値をansに代入
printf("ANS = %d",ans);
return 0;
}
int ad(int a,int b) { // 関数ad (戻り値int型、引数int型aとint型b)
return a + b; //
a+b の値を返す
}
★プロトタイプ宣言
作った関数は使う前(普通はソースファイルの先頭)に、
int abc(int, int);
void xyz(void);
のように並べて列記する。宣言中の戻り値とパラメーターは型のみで可。末尾のセミコロンが必要。
★構造体
配列は同種のデータを扱うが、異種データの集合は構造体を使う。
#include <stdio.h>
#include <string.h>
struct psn { //構造体のテンプレート定義
char name[50]; //文字列
int age;
//整数
float ht; //浮動小数点
};
int main() {
struct psn psn1; //構造体psnにpsn1という変数を定義
strcpy(psn1.name, "TARO"); //名前文字列の書込み
psn1.age = 18; //年齢データの書込み
psn1.ht = 179.2; //身長データの書込み
printf("Name: %s\n", psn1.name); //psn1の名前を出力
printf("Age: %d\n", psn1.age); //psn1の年齢を出力
printf("Height: %.2f\n", psn1.ht); //psn1の身長を出力
return 0;
}
★#define
#define は疑似命令またはマクロと呼ばれ、コンパイル時に最初の文字列が後ろの文字列に置き換わる。
定数の定義としても用いられるが、パラメータを使うこともできる。パラメータはカッコで囲う必要がある。
#define TAX_RATE 0.1 // TAX_RATE
という文字列すべては0.1に置き換わる。
#define ARE(r) (r*r*3.14) //
ARE(5) は 78.5 に置き換わる(5*5*3.14→78.5)
#define は疑似関数のようにも使え、奥深い。ただし関数と違ってコンパイルによっては文字が置き換えられるだけのため、エラーは、実行してみないと分からない点に留意する必要がある。
Cの標準ライブラリ関数
以下は代表的な関数と、幾つかの使い方の例です。
各分類先頭の<ヘッダ.h> を #include して使います。
詳細はネット上で検索することができます。
文字処理系関数
<string.h><stdio.h>
strcat 文字列同士を連結する関数
形式:char *strcat(char *s1, const char *s2);
int main(void) {
char test1[100] = "abcde";
char test2[10] = "12345";
strcat(test1,test2);
printf("連結後の文字列「%s」\n",test1);
return 0;
}
strcmp 文字列同士を比較
形式:int strcmp(const char *s1, const char *s2);
戻り値: s1>s2 で正;s1<s2 で負;s1=s2で0
strcpy 文字列をコピー
形式:char *strcpy(char *s1, const char *s2);
char test1[10] = "abc";
char test2[10] = "123";
strcpy(test1,test2); //test1の配列が"abc
"から"123"になる
strlen 文字列の長さを「バイト数」で返す
形式:size_t strlen(const char *s);
引数に文字列を指定、戻り値は文字列のバイト数
strncat 文字列同士を指定文字数分連結
strncmp 文字列を先頭から指定文字数分比較
strncpy 指定文字数だけ文字列をコピー
strstr 文字列から文字列を検索してその場所のポインタを返す
形式:char *strstr(const char *s1, const char *s2);
第一引数は検索対象の文字列、第二引数は検索文字列
strchr 文字列の先頭から「文字」を検索して見つかった場所をポインタで返す
strrchr 文字列の「最後」から「文字」を検索して見つかった場所をポインタで返す
strtok 文字列を区切り文字で区切ってトークンに分解
isalnum 引数の文字が英数字かどうかを調る
isalpha 引数の文字が英字かどうかを調べる
isdigit 引数の文字が数字かどうかを調べる
islower 引数の英字が小文字かどうかを調べる
isupper 引数の英字が大文字かどうかを調べる
tolower 大文字の英字を小文字に変換
toupper 小文字の英字を大文字に変換
日付・時刻系関数
<time.h><stdio.h>
time 1970年 1月 1日の00:00:00から現在までの経過時間の秒数
形式:time_t time(time_t *timer);
#include <time.h>
#include <stdio.h>
int main(void) {
time_t tt;
time(&tt); //現在までの経過時間を取得
printf("現在時刻:%s",ctime(&tt));
return 0;
}
mktime tm構造体をtime_t構造体に変換する関数
localtime time_t型の構造体をtm構造体に変換
difftime time_t型の構造体を二つ引数に渡すと、二つの時間の差を秒数で返してくれる関数
ctimet ime_t型の構造体に格納された時刻情報を文字列として返す
clock プログラムが起動してから経過した時間
asctime tm構造体に格納されている時刻を文字列に変換
ファイル、標準入出力系関数
<stdio.h>
fopen ファイルを開きそのポインタを取得
fclose 引数のファイルポインタのファイルをクローズ
fgets ファイルから文字列を一行取得
fputs ファイルに文字列を書き込む
fputc 文字を1文字ファイルに書き込む
fgetc 1文字ファイルから読み込む
getchar 標準入力から文字を1文字取得
gets 標準入力から文字列を1行取得
putc 文字を1文字ファイルに書き込む
putchar 文字を1文字標準出力に出力
puts 文字列を標準出力に出力
printf 書式付で文字列を標準出力に出力
形式:printf( 書式文字列, 可変個引数 );
remove ファイルを削除
remame ファイル名を変更
sprintf 書式付文字列を文字配列に格納
scanf 書式指定をして標準入力をバッファに格納
形式:int fscanf(FILE *fp, 書式指定文字列, 格納可変個引数);
fscanf 書式指定をしてファイルから値を読み込み、バッファに格納
fread ファイルから指定バイト数のデータを指定した数読み込み、バッファに格納
fwrite 指定バイト数のデータを指定した個数だけファイルに書き込み
getc 文字を1文字ファイルから読み込む
fprintf 書式付文字列でファイルに文字列を格納
fgetpos 現在のファイルポインタの位置を調べる
fseek ファイルポインタの位置を指定した位置に移動させる
rewind ファイルポインタの位置を先頭に戻す
メモリ処理系関数
<stdio.h><stdlib.h><string.h>
malloc 指定したバイト分のメモリを確保する
free malloc関数などで確保したメモリを解放する
calloc 指定したバイト数のメモリを指定個数分確保し、そのメモリブロックを0にクリア
realloc 確保したメモリの割り当てを変更
memchr メモリの中からバイト数を指定して文字を検索
memcmp 指定バイト数のメモリブロックを比較
memcpy 指定バイト数分のメモリをコピー
memmove 指定したバイト数のメモリをコピー(移動)
数学関数
<math.h><stdio.h> 下記の数値x,yは double
M_PI 円周率
sqrt(x) 平方根
int main() {
double x = 2.0;
double y = 0;
y = sqrt(x);
printf("y=%f",y);
return 0;
}
sin(x) サイン
double radian = M_PI / 2.0; //
π/2ラジアン
printf("sin(pi/2)= %f\n", sin(radian));
cos(x) コサイン
tan(x) タンジェント
asin(x) ア−クサイン
acos(x) アークコサイン
atan(x) アークタンジェント
ceil(x) 切り上げ
floor(x) 切り捨て
pow(x,y) xのy乗
exp(x) eのx乗
log(x) xの自然対数
log10(x) xの常用対数
fabs(x) 絶対値
fmod(x,y) x/y の余り
★値の符号(0/1/-1)を返すマクロ
#define SIGN(a) ((a>=0)-(a<0))
その他の関数
<stdio.h><stdlib.h><string.h>
rand 0〜RAND_MAX定数までの乱数を返す
printf("%d回目の乱数:%d\n",i+1,rand()%10+1);
srand rand関数の擬似乱数の発生系列を変更
●
テキストファイルの書き込み#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main() {
FILE *fp;
int num = 10;
char str[] = "Hello";
fp = fopen("test.txt", "w");
//書込み w
if (fp == NULL){
printf("ファイルをオープンできませんでした。\n");
return 1;
}
fprintf(fp, "数値: %d\n", num);
fprintf(fp, "文字列: %s\n", str);
fprintf(fp, "書込みデータ終了");
fclose(fp);
return 0;
}
●テキストファイルの読み込み#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void) {
// 読み込んだテキストデータの格納
char tx;
// ファイルポインタ
FILE *fp;
// ファイルオープン
fp = fopen("test.txt", "r");
// ファイルが適切に読み込まれているかを確認
if( fp == NULL ) {
perror("ファイルの読み込みに失敗!\n");
return 1;
}
// テキストの読み込みと出力
printf("File data: \n");
while(( tx = fgetc(fp)) != EOF ) {
printf("%c",
tx);
}
// ファイルクローズ
fclose(fp);
return 0;
}
●
バイナリファイルの書込み#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void) {
// バイナリファイル書き込み
char buf[] = {0x41,0x42,0x43,0x44,0x45,0x46};
FILE *file;
file = fopen("d:\\temp\\mingw\\test.bin",
"wb"); //バイナリデータ書き込み
fwrite(buf, sizeof(buf), 1, file);
fclose(file);
return 0;
}
●
バイナリファイルの読み込み#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void) {
FILE *fp;
int i;
unsigned char buf[1000];
int size;
fp = fopen("test.bin", "rb");
size = fread(buf, sizeof(unsigned char), 1000,
fp);
for(i=0; i<size; i++){
if(i % 16 == 0) printf("\n");
printf("%02x ",
buf[i]);
}
fclose(fp);
return 0;
}