入力待ち状態となるプログラムを書く

Posted コメントするカテゴリー: JAVA

入力待ち状態のプログラムを書きます。

import java.io.*;

public class input_test {

    public static void main(String[] args) {
        
        System.out.print("なにか入力してください\n");
        
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        
        try {
	        String line = reader.readLine();
	        
	        System.out.print("入力した文字は" + line + "です\n");
	    } catch (IOException e) {
            System.out.print(e);
	    } catch (NumberFormatException e) {
            System.out.print("なにか間違っています\n");
	    }
        
    }

}

実行すると、次のようになります。

なにか入力してください
129873469127384
入力した文字は129873469127384です

初歩の為に書いたプログラムは簡単でしたが、上記のプログラムは見たことがない記述が出て気ました。

まず行頭でいきなりimportという命令が来ます。
これはクラスライブラリを利用する時に宣言する記述です。

そもそもBufferedReaderというものを見たことも書いたこともなかったです。
どうやらこれはデータの読み込みを行う為のクラスということでした。

C言語を勉強した時には出てこなかったtryという書き方もjavaでは頻繁に使うようです。
あとは、クラスをnewして使う部分もC言語では出てこなかったと思います。

とにかく一度書いて動かしてみて慣れていくのがいいのかもしれません。

java言語に慣れる為にいろいろ書いてみる

Posted コメントするカテゴリー: JAVA

言語に慣れる為に、いろいろと書いて実行をさせてみます。
文法的にはC言語に近い部分があるので、初歩の段階では得に違和感もなく書いて動かしてみました。

public class hello {
    public static void main(String[] args) {
        
        System.out.print("hello\n");
        
        //改行を試す
        System.out.print("hello2\n");
        System.out.print("hello3\n");

        //日本語を試す
        System.out.print("でますか?\n");
        
        //加減乗除を試す
        System.out.print("たしざん" + (3+2) + "\n");
        System.out.print("ひきざん" + (3-2) + "\n");
        System.out.print("かけざん" + (3*2) + "\n");
        System.out.print("わりざん" + (3/2) + "\n"); //結果は余りが表示される
        
        //変数を試す
        int x;
        x = 5;
        System.out.print("変数の中身は" + x + "です");
        
    }
}

実行すると次のような結果になります。

hello
hello2
hello3
でますか?
たしざん5
ひきざん1
かけざん6
わりざん1
変数の中身は5です

JAVAでhellow worldを出力してみます

Posted コメントするカテゴリー: JAVA

JAVAでソースコードを書いて、コンパイルし、hellow worldを出力したとがないので、やってみます。(いままではIEDとかを使用していました)

次のコードを書いて、hello.javaというファイルに保存します。

public class Hellow {
	public static void main(String[] args) {
		System.out.print("hello");
	}
}

次にDOSコマンドプロンプトを立ち上げて、ソースコードを保存したディレクトリに移動します。

//便宜的に下記のディレクトリを作業ディレクトリにしました
cd C:\works\java

次にソースコードをコンパイルするコマンドを入力します。
コンパイルは「javac」の後にスペースを空けてソースコードを指定します。

C:\works\java>javac hello.java

と、ここで下記のようなエラーが発生しました。

'javac' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。

少し調べてみましたが、原因はまだわかっていません。

PC内の環境変数をチェックしてみましたが、正しくPATHが追加されていました。

(20140828追記)
その後、一旦PCから離れ改めてjavacを実行してみると次のように表示されました。
おそらくですが、JDKをインストールし、環境変数のpathを変更したあとにPCの再起動をした為かと思います。

C:\works\java>javac
使い方: javac <options> <source files>
使用可能なオプションには次のものがあります。
  -g                         すべてのデバッグ情報を生成する
  -g:none                    デバッグ情報を生成しない
  -g:{lines,vars,source}     いくつかのデバッグ情報だけを生成する
  -nowarn                    警告を発生させない
  -verbose                   コンパイラの動作についてメッセージを出力する
  -deprecation               推奨されない API が使用されているソースの位置を出力する
  -classpath <path>          ユーザークラスファイルおよび注釈プロセッサを検索する位置を指定する
  -cp <path>                 ユーザークラスファイルおよび注釈プロセッサを検索する位置を指定する
  -sourcepath <path>         入力ソースファイルを検索する位置を指定する
  -bootclasspath <path>      ブートストラップクラスファイルの位置を置き換える
  -extdirs <dirs>            インストール済み拡張機能の位置を置き換える
  -endorseddirs <dirs>       推奨規格パスの位置を置き換える
  -proc:{none,only}          注釈処理やコンパイルを実行するかどうかを制御します。
  -processor <class1>[,<class2>,<class3>...]実行する注釈プロセッサの名前。デフォルトの検出処理をバイパス
  -processorpath <path>      注釈プロセッサを検索する位置を指定する
  -d <directory>             生成されたクラスファイルを格納する位置を指定する
  -s <directory>             生成されたソースファイルを格納する場所を指定する
  -implicit:{none,class}     暗黙的に参照されるファイルについてクラスファイルを生成するかどうかを指定する
  -encoding <encoding>       ソースファイルが使用する文字エンコーディングを指定する
  -source <release>          指定されたリリースとソースの互換性を保つ
  -target <release>          特定の VM バージョン用のクラスファイルを生成する
  -version                   バージョン情報
  -help                      標準オプションの概要を出力する
  -Akey[=value]              注釈プロセッサに渡されるオプション
  -X                         非標準オプションの概要を出力する
  -J<flag>                   <flag> を実行システムに直接渡す

さらにコンパイルを実行してみると、コンパイルに失敗。

C:\works\java>javac hello.java
hello.java:1: クラス Hellow は public であり、ファイル Hellow.java で宣言しなければなりません。
public class Hellow {
       ^
エラー 1 個

プログラム内のクラス名がおかしいので修正をする。

public class hello {
	public static void main(String[] args) {
		System.out.print("hello");
	}
}

改めてコンパイル

C:\works\java>javac hello.java
C:\works\java>

何事もなく完了。コンパイルしたjavaを実行します。

C:\works\java>java hello
hello

と表示されました。
ケアレスミスが多くとまどりましたが、環境構築はひとまず完了です。

JAVAの開発環境を整える

Posted コメントするカテゴリー: JAVA

まず最初にJAVAの開発環境を用意します。

 

JAVAは移植性の高い言語と呼ばれています。

 

その理由は一度書いたソースコードはJVMと呼ばれる、プラットフォーム上で、ネイティブコードに変換して実行する仕組みになっている為、どの機械でも動作しやすいように設計されています。

 

配布時にはプラットフォームから独立したJAVAバイトコードになっていて、それをプラットフォーム固有のネイティブコードに変換して実行します。

 

この変換と実行を行う部分がJVMと呼ばれるものです。
実行前にまとめて変換することで実行時のオーバーヘッドをなくして実行速度を向上させたものをJITコンパイラと呼びます。

 

■開発環境を整える

まずは、JAVAを動作させる為に、JDKをインストールします。
公式のサイトからJDKをダウンロードし、自マシンにインストールします。
■公式サイト
http://www.oracle.com/technetwork/java/javase/downloads/index-jsp-138363.html#javasejdk
■JDKのダウンロード(ここから適宜、バージョンを選択してダウンロードする)
http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

JAVAの勉強を開始します

Posted コメントするカテゴリー: JAVA

これからJAVAの言語を勉強していきます。

今まではおぼろげながらJAVAに触れてきましたが、ひととおりの知識を得る為に、ひとつひとつ実験しながら、体系的にやっていきます。

体系的に知ることが目的なので、深すぎる部分については、次の段階で落とし込もうと思います。

ソート(データを並び替える)

Posted コメントするカテゴリー: C

配列内の数値や文字列を並びかえるにはqsort()関数を使います。

参考例を実行してみましたが、動作せず・・・。

#include <stdio.h>
#include <stdlib.h>

int compare(const void *a, const void*b)
{
	if (*a > *b) {
		return 1;
	} else if(*a < *b) {
		return -1;
	} else if(*a == *b) {
		return 0;
	}
}

int main(void)
{
	int num[] = {4, 6, 5};
	qsort(num, sizeof(int), compare);
	printf("%d\n", num);
	
	return 0;
}

エラーメッセージは次のように出ました。

関数呼び出しに指定されているパラメータ数が少ないです。
呼び出している関数の引数の数を再確認してください。

「qsort(num, sizeof(int), compare);」この行でエラーが出ていることがわかっていますので、C言語ライブラリのマニュアルを検索してみると、次のように書かれています。

#include <stdlib.h>

void qsort( void * data , size_t data_cnt
       , size_t data_size
       , int( * func )( const void * , const void * );

■戻り値:
なし

数学関数

Posted コメントするカテゴリー: C

指数や平方根などの数学レベルでの計算が必要な場合に使います。

実際に使う場合は、math.hで定義された数学用の関数を読み込みます。

■乱数を作る
ランダムな文字列を作成するには、stdlib.hを読み込み、rand()関数を使います。

実際に書いてみます。

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
	
	int n;
	srand(time(NULL));
	n = rand();
	
	printf("%d\n", n);
	
	return 0;
}

結果は、実行するたびにランダムな数字が表示されます。

時間に関する関数

Posted コメントするカテゴリー: C

日時を取得する為には、time()関数とlocaltime()関数を組み合わせて使います。

これらの関数の定義はtime.hの中で定義されています。

■現在時刻を得る

time_t ct;  //time_t型という型になります
ct = time(NULL);
struct tm *now;
now = localtime(&ct); //「&ct」はtime関数で得た値が入った変数のアドレスを指定します。

time.hを利用したtm構造体のメンバはtm_secやtm_min等があります。
その他のメンバや、使い方等はC言語の標準ライブラリについて調べる必要があります。

シフト演算子

Posted コメントするカテゴリー: C

シフト演算子とは、ビット列を左右に指定した分だけずらす動きをします。

シフト演算子は2種類あり、「右シフト演算子」と「左シフト演算子」があります。

■右シフト演算子(ビット列を右に2ビットシフトする)

                    ↓最上位ビット ↓最下位ビット
元のビット列         1 0 1 1 0 0 1 0
                     ~~~ここが
シフトしたビット列   1 1 0 0 1 0 1 0
                                 ~~~ここにシフトされる

■左シフト演算子(ビット列を左に2ビットシフトする)

                    ↓最上位ビット ↓最下位ビット
元のビット列         1 0 1 1 0 0 1 0
                                 ~~~ここが
シフトしたビット列   1 0 1 0 1 1 0 0
                     ~~~ここにシフトされる

ビット演算子

Posted コメントするカテゴリー: C

データをビット単位で、比較、操作する際に使うのがビット演算子です。

■論理積(and) &
各ビットを比べて、「両方とも1なら1、そうでなければ0」を返す演算

参考例
a = 170, b = 245

変数名    10進数    2進数
a         170		1	0	1	0	1	0	1	0
b         245		1	1	1	1	0	1	0	1
a&b       160		1	0	1	0	0	0	0	0

■論理和(or) |
「片方が1なら1、そうでなければ0」を返す演算(これはどちらも1の場合は1となる)

変数名    10進数    2進数
a         170		1	0	1	0	1	0	1	0
b         245		1	1	1	1	0	1	0	1
a|b       160		1	1	1	1	1	1	1	1

■排他的論理和(xor) ˆ
「片方が1で、もう片方が0なら1、そうでなければ0」を返す演算

変数名    10進数    2進数
a         170		1	0	1	0	1	0	1	0
b         245		1	1	1	1	0	1	0	1
aˆb       160		1	1	1	1	1	1	1	1

■1の補数表現(not) ~
「各ビットを反転させたもの」

変数名    10進数    2進数
a         170		1	0	1	0	1	0	1	0
a~        160		0	1	0	1	0	1	0	1

列挙型

Posted コメントするカテゴリー: C

列挙型とは、整数値に特定の名前を与えることです。

列挙型を使うと、int型の整数値に名前をつけることができます。
列挙型の宣言はenumという記述ではじめます。

サンプルを書いて動かしてみます

#include <stdio.h>

int main(void)
{
	//列挙型の宣言
	enum _mon{
		Jan,
		Feb,
		Mar,
		Apr,
		Jun
	} mon;
	
	printf("%d\n", mon); //結果「4198543」と表示される
	
	//明示的な値を代入する場合

	//列挙型の宣言
	enum _mon{
		Jan = 1,
		Feb,
		Mar = 5,  //ここはわざと5にする
		Apr,
		Jun
	} mon;
	
	
	//↑の例では、1,2,5,6,7,という値が自動的に割り振られることになる
	
	
	//列挙型の値を使う時の例。列挙指定子のいずれかの名前を使った代入や参照ができる
	mon = Feb;
	
	printf("%d\n", mon); //結果「2」と表示される
	
	return 0;

}

共用体

Posted コメントするカテゴリー: C

共用体とは、1つのアドレスに異なるデータを割りあてることです。

共用体は、1つのメモリ領域で異なる型の変数のどれかひとつを選んで使うことができます。
共用体の宣言は以下のようになります。

//「uniondata」は共用体名、「unilist1」は共用体変数
union uniondata{
    int no;
    char name[10];
    float weight;
};
union uniondata unilist1;

共用体を使ったサンプルを試してみます。

#include <stdio.h>

int main(void)
{

	//「uniondata」は共用体名、「unilist1」は共用体変数
	union uniondata{
	    int no;
	    char name[10];
	    float weight;
	};
	union uniondata unilist1;


	unilist1.no = 1;
	printf("%d\n", unilist1.no);
	
	strcpy(unilist1.name, "test!!");
	printf("%s\n", unilist1.name);
	
	unilist1.weight = 123.4;
	printf("%f\n", unilist1.weight);

	return 0;
}

unilist1がメモリに占める領域は一番大きな型にあわせた大きさになる。
共用体はまだまだ深いので、改めて追記して理解を深めることにします。

出力結果は以下のなります。

1
test!!
123.400002

引数つきマクロ

Posted コメントするカテゴリー: C

#defineを使うと、引数をもち、関数のように動作するマクロを定義することができます。

#define HIKU(x, y) ((x) - (y))

上記の書き方は有効範囲は1行です。
複数行の場合は次のように定義します。

#define hiku2(a, b, c) ((a) * (b) * (c) )\
+ a+b+c)

実際に動かしてみます

#include <stdio.h>

#define HIKU(x, y) ((x) - (y))

int main(void)
{
    int i;
    
    printf("マクロ!%d\n", HIKU(10, 8));
    
    return 0;
}

//結果は「マクロ!2」と表示されます

引数つきマクロは、実行する処理全体とその中の引数はカッコでくくります。

//正しい例
#define HIKU(x, y) ((x) - (y))

//間違った例
#define HIKU(x, y) (x - y)

マクロ名と()の間にスペースを入れてしまうと、区切りが正しく認識されません。

//正しい例
#define HIKU(x, y) ((x) - (y))

//間違った例
#define HIKU (x, y) ((x) - (y))

条件に応じたコンパイル指示

Posted コメントするカテゴリー: C

条件に応じて、必要な部分だけ抜き出してコンパイルしたい場合、次のように書きます。

#if 条件
    指定範囲
#endif
#ifdef 識別子
    指定範囲
#endif
#ifndef 識別子
    指定範囲
#endif

また、複数の条件を判断することもできます。

#ifdef 識別子
    範囲指定A   //指定範囲Aをコンパイルする
#elsif 条件B
    範囲指定B   //指定範囲Bをコンパイルする
#else
    範囲指定C   //指定範囲Cをコンパイルする
#endif

複数のプログラムファイル内でヘッダファイルを使うと、同じヘッダファイルを重複インクルードしてしまう場合があります。
これを防ぐためには次のように書きます。

#ifndef _MYHEADER_
#define _MYHEADER_
    //2回目以降は既に呼ばれているので、この内容は読み込まれない
    void MyFunc();
    extern int x;
#endif

マクロ

Posted コメントするカテゴリー: C

#からはじまる1行分のことをマクロと呼びます。
マクロはプログラムのソースコードをコンパイルする前にプリプロセッサが処理します。

プログラムの最初に記述する「#include」もマクロの一種です。

マクロは次のような書式で書きます。

//マクロの中にはスペースやタブは入れてはダメ
#define マクロ名 パターン

■置換
#defineは、文字列を置換するマクロです。

#define VALNUM 3;

次のように書くと、DEBUG_MODEが定義されているということを表します。

#define DEBUG_MODE;

簡単なサンプルを書いてみましたが、うまく動作せず。

#include <stdio.h>

#define VALNUM 3;

int main(void)
{
    printf("%d \n", VALNUM);
    
    
    return 0;
}


//実行結果
「7行目」で記述エラーを発見しました。
「,」を付け忘れています。

もうひとつ、サンプルを書きましたが、これもうまく動作しませんでした。原因について調査中、、、

#include <stdio.h>

#define VALNUM 3;

int main(void)
{
	int i;
	
	for (i=0; i<VALNUM; i++) {
	    printf("%d \n", i);
	}
    
    return 0;
}

//実行結果
「9行目」で記述エラーを発見しました。
「identifier」を付け忘れています。

エラーの原因から地道に紐解いていこうかと思います。
解決したら、ブログに追記します。

2014.09.25追記
コメントからご指摘いただいた点を元に、下記のようなプログラムを作って動かしてみました。

#include <stdio.h>
 
#define VALNUM 3
 
int main(void)
{
    int i;
     
    for (i=0; i<VALNUM; i++) {
        printf("%d \n", i);
    }
     
    return 0;
}

エラーが出ずに実行され、コンソール上には「0 1 2」という表示が出ました。
ケアレスミスでした。

static宣言

Posted コメントするカテゴリー: C

グローバル変数をstaticをつけて宣言すると、変数の有効範囲はその宣言をしたファイル内に限られます。

外部変数を宣言して、他のファイルから参照することはできません。

例として次のような場合

//ソースファイル1で記述
static int gvar;

//ソースファイル2で記述
extern int gvar;

//ソースファイル3で記述
extern int gvar;

上記のようにソースファイル2やソースファイル3からgvarを呼び出そうとしてもエラーになります。

■static宣言したローカル変数
static変数はプログラムの開始から終了まで、値が削除されません。
ローカル変数は関数の中で宣言され、関数の処理が終わると同時に破棄されます。

■const宣言
const宣言は変数の値を書き換えられないようにする宣言です。
定数として変数を使用する場合は、この宣言を使います。

const宣言を関数の引数で指定している場合、その引数は関数の中で値が保持されることを保障する動きになります。

ファイルの分割と組み立て

Posted コメントするカテゴリー: C

ソースファイルの分割

ひとつのソースファイルに大量のプログラムコードを書くと良くないので、分割をしてソースファイルを管理します。

通常、プログラムを構成する「機能」ごとにソースファイルを分割します。

ソースファイルを分割すると、どのプログラムファイルからも参照できる変数が必要になってきます。
その変数を「外部変数」とよび、変数を宣言することを「外部変数宣言」といいます。

ソースファイルの分割例

本体ファイル①

int global_val;

分割ファイル①

extern int global_val;

分割ファイル②

extern int global_val;

上記のように記述します。

■ヘッダファイルを利用する
ヘッダファイルを利用することにより、さらに効率的にプロジェクトを管理できるようになります。

コンパイルとリンク

Posted コメントするカテゴリー: C

実行ファイルを作るには、C言語のソースを書いて、「コンパイル」、「リンク」することで完成します。

コンパイルとリンクを合わせて「ビルド」または「メイク」と呼びます。

ヘッダファイル

Posted コメントするカテゴリー: C

拡張子が「h」のファイルのことをヘッダファイルと呼びます。

ヘッダファイルは、プロトタイプ宣言、構造体や定数の定義などのテキストファイルを指し示す。

ソースファイルの中に組み込むと、それらの宣言や定義を利用できるようになります。

#include <stdio.h>

インクルードの書き方は、C言語に標準搭載されているヘッダファイルは次のように書きます。

#include <stdio.h>

また、自分で作ったヘッダファイルは次のように書きます。

#include "xxxxxxx.h"

C言語が用意しているヘッダファイルは次のようなものがあります。

ヘッダファイル  処理の種類
stdio.h         入出力
string.h        文字列処理
time.h          時間処理
math.h          数学処理

自分でヘッダファイルを作るには、次のように書きます。

//呼び出し元の拡張子cのファイル
#include "test.h"
main ()
{

}

void testfunc()
{

}

自作ヘッダファイル側

void testfunc();

型の再定義

Posted コメントするカテゴリー: C

長い型名を簡潔に名前をつけなおすことができます。(型の再定義)

//「unsigned char」を「u_char」という名前に定義している
typedef unsigned char u_char;
u_char c;

ポインタ型の再定義もあります。

//ポインタ型の場合
typedef unsigned int * pt_int;
pt_int a;

構造体名を再定義する方法

typedef struct data {
    int no;
    char name;
    int age;
} DATA;
DATA list1;

//↑の例は下記のように記述したものと同じになる
typedef struct data {
    int no;
    char name;
    int age;
};
struct data list1;

構造体と配列

Posted コメントするカテゴリー: C

構造体変数を配列として考えることを構造体配列と呼びます。

#include <stdio.h>
  
int main(void)
{
      
    //構造体配列の宣言(構造体テンプレートと、構造体配列を別々に書く場合)
    struct data{
        int no;
        char name[10];
        int age;
    };
    
    struct data list1[10];
    
    //構造体配列の宣言(構造体テンプレートと、構造体配列を同時に書く場合)
    struct data2{
    	int no;
    	char name[10];
    	int age;
    } list1[10];
    
    //構造体配列を初期化する場合(各々の配列内に値をセットしている)
    struct data2 list1[10] = {
    	{1, "testA", 10},
    	{2, "testB", 20},
    	{3, "testC", 32},
    	{4, "testD", 41}
    };
    
    //↑の例では、list1[10]と定義しているので、10個分の構造体配列を持たせることができる
    
    
    return 0;
}

上記プログラムを実行しただけでは、画面上にはなにもおこりません。
そこで、構造体配列の中身を参照する記述を書いてみます。

#include <stdio.h>
  
int main(void)
{
      
    //構造体配列の宣言(構造体テンプレートと、構造体配列を別々に書く場合)
    struct data{
        int no;
        char name[10];
        int age;
    };
    
    struct data list1[10]; //構造体配列の宣言
    
    //構造体配列の宣言(構造体テンプレートと、構造体配列を同時に書く場合)
    struct data2{
    	int no;
    	char name[10];
    	int age;
    } list1[10];  //構造体配列の宣言(同時に)
    
    //構造体配列を初期化する場合(各々の配列内に値をセットしている)
    struct data2 list1[10] = {
    	{1, "testA", 10},
    	{2, "testB", 20},
    	{3, "testC", 32},
    	{4, "testD", 41}
    };
    
    //↑の例では、list1[10]と定義しているので、10個分の構造体配列を持たせることができる
    
    
    //構造体配列の中身を参照する記述
    //方法1
    int i;
    for (i = 0; i <10; i++ ) {
    	printf("%d %s %d \n", list1[i].no, list1[i].name, list1[i].age);
    }
    
    printf("-----------\n");
    
    //方法2
    int j;
    struct data2 *sp = list1;
    for (j = 0; j < 10; j++ ) {
    	printf("%d %s %d \n", list1[*(sp+j)].no, list1[*(sp+j)].name, list1[*(sp+j)].age);
    }

    printf("-----------\n");

    //方法3
    struct data2 *sp;
    for (sp = list1; sp != list1 + 10; sp++ ) {
    	printf("%d %s %d \n", sp->no, sp->name, sp->age);
    }

    return 0;
}

上記を実行した結果、方法2の結果がなぜか下記のようになる。

1 testA 10
2 testB 20
3 testC 32
4 testD 41
0  0
0  0
0  0
0  0
0  0
0  0
-----------
2 testB 20      //出力の開始がおかしい(2つめからになっている)
3 testC 32
4 testD 41
0  0            //←ここの値がおかしい
1 testA 10
1 testA 10
1 testA 10
1 testA 10
1 testA 10
1 testA 10
-----------
1 testA 10
2 testB 20
3 testC 32
4 testD 41
0  0
0  0
0  0
0  0
0  0
0  0

なぜなのか、、調査中

構造体の使用例

Posted コメントするカテゴリー: C

構造体の使用例について、実際に書いてみます。

#include <stdio.h>

int main(void)
{
	
	//構造体のテンプレート宣言
	struct data{
		int no;
		char name[10];
		int age;
	};
	
	//初期化(「1」や「test」というひとつひとつの要素はメンバ)
	struct data list1 = {1, "test !!!", 39};
	
	//メンバが多い場合は折り返して書く
	struct data list1 = {
		1,
		"test !!!",
		39
	};
	
	//構造体メンバへのアクセス
	printf("%d %s %d\n", list1.no, list1.name, list1.age);
	
	//構造体変数へ値を代入する
	list1.no = 3;
	strcpy(list1.name, "cotytext!");
	list1.age = 40;
	
	
	
	return 0;
}

構造体に対するポインタもあります。この場合は、構造体をポインタで指し示すことになります。

#include <stdio.h>
 
int main(void)
{
     
    //構造体のテンプレート宣言
    struct data{
        int no;
        char name[10];
        int age;
    } list1;
     
    //構造体のポインタを宣言
    struct data *sp;
     
    //ポインタへのアドレスの代入方法
    //struct data list1;
    sp = &list1;
     
    //ポインタを使った構造体の参照方法(phpのクラスのメンバ変数へのアクセスに似ている)
    printf("%d %c %d\n", sp->no, sp->name, sp->age);
     
     
    return 0;
}

構造体配列について

構造体

Posted コメントするカテゴリー: C

構造体について

構造体とは、異なる型の変数をひとまとめにして、取り扱える形にしたもの。
どのような型の変数をまとめるのかを指定することを、構造体のテンプレートと呼びます。
テンプレートを定義しただけではデータを入れることができないので、構造体の型を持つ変数を用意します。この変数のことを構造体変数と呼びます。

構造体を配列に格納すると、それは構造体配列と呼ばれるものになります。これはまだ良くわかっていないので後ほど勉強します。

構造体は異なる型の変数をひとつにまとめ、まとめられた要素ひとつひとつをメンバと呼びます。

実際に書いてみます。

#include <stdio.h>

int main(void)
{
	
	//構造体のテンプレート宣言
	struct data{
		int no;
		char name[10];
		int age;
	};
	
	//構造体変数の宣言(dataはテンプレート名、list1は構造体変数名)
	struct data list1;
	
	//構造体テンプレートと構造体変数を同時に宣言
	struct data2{
		int no;
		char name[10];
		int age;
	} list2;
	
	struct data2 list3; //宣言をした後から構造体変数を追加した場合
	
	return 0;
}




キーボード入力

Posted コメントするカテゴリー: C

キーボードからの入力を取り扱う方法を勉強します。

scanf()関数
キーボードから入力したデータを指定の書式に変換したり配列に格納したりします。

int a;
scanf("%d", &a); //&をつけてアドレスとしている

//文字列の場合
char s[30];
//配列の場合は、先頭要素のポインタとなるので、&はいらない
scanf("%s", s);

//複数のデータを一度に入力する場合
int a;
char s[30];
scanf("%d %s", &a, s);

gets()関数
キーボードから入力した1行分の文字列を文字列配列に格納する

char s[30];
gets(s); //1行分

getchar()関数
キーボードから入力された1文字だけ変数に格納する

//実行するとプログラムはキーボードからの入力待ちになる
int c;
c = getchar();

一般的な入出力

Posted コメントするカテゴリー: C

C言語はファイルポインタを通してディスク上のファイルを読み書きを行います。
また、ファイルポインタは必ずしもファイルを取り扱うのではなく、キーボードやディスプレイなどの入出力装置とのやりとりについても使用します。

■標準入出力ファイルの種類
基本的な入出力のため、stdin,stdout,stderrの3つのファイルポインタがあります。
これらはプログラム実行開始時に自動的に開いています。

stdinは標準入力と呼ばれ、キーボードなどからの入力を受け取る
stdoutはディスプレイなどへの出力を行います
stderrは基本的なエラー出力を(ディスプレイ等に)行います

ファイル用関数で標準入出力を指定するとキーボードやディスプレイからの入出力になります。
printf関数でディスプレイに出力する場合は、裏側でfprintf(stdout, “%d”, a);という命令が動き、ディスプレイに結果が出ています。

サンプル用プログラム

#include <stdio.h>

int main(void)
{
	//入力された文字列を格納する変数を宣言しておく
	char s[30];
	
	//キーボードからの入力を変数sへ格納する
	fgets(s, 29, stdin);
	
	//変数sの値をそのままディスプレイ出力する
	fputs(s, stdout);
	
	//オマケ
	fputs("error\n", stdout);
	
	return 0;
}

バイナリファイルの書き込み

Posted コメントするカテゴリー: C

バイナリファイルを書き込む場合は、ファイルのオープンモードを「wb」にします。

#include <stdio.h>

int main(void)
{

	short buf[] = {
		0x10, 0x20, 0x30
	};

	FILE *fp;
	fp = fopen("d.data", "wb");

	fwrite(buf, sizeof(short), 3, fp);

	//ファイルを閉じる
	fclose(fp);

	return 0;
}

バイナリファイルの読み込み

Posted コメントするカテゴリー: C

バイナリファイルを読み込む場合は、改行等の制御文字はなく、ひとつながりのデータとして読み込みます。

バイナリファイルを開くときはファイルモードに「b」(バイナリ)を追加します。

FILE *fp;
fp = fopen("file3.data", "rb");

オープンモードは以下のようになる

rb 読み込み専用
wb 書き込み専用
ab 追加書き込み用

バイナリファイルの読み込みは次のようになります。

#include <stdio.h>

int main(void)
{

	//ファイルを開く
	short buf[3];
	FILE *fp;
	fp = fopen("c.data", "rb");

	//データを読み込む
	//「3」は読み込み回数。fpが示す位置から2バイトのデータを3回読み込む
	fread(buf, sizeof(short), 3, fp);

	//ファイルを閉じる
	fclose(fp);

	return 0;
}

ファイルの書き込み

Posted コメントするカテゴリー: C

ファイルへの書き込みは以下のように書きます。

#include <stdio.h>

int main(void)
{
	
	FILE *fp;
	fp = fopen("b.txt", "w");
	fputs("Hello \n", fp);
	
	//指定形式での書き出し
	int a = 5;
	fprintf(fp, "%02d\n", a);
	fclose(fp);
	
	return 0;
}

別パターンを試してみる。

#include <stdio.h>
int main(void)
{
	
	FILE *fp;
	fp = fopen("b.txt", "w");
	fputs("Hello \n", fp);
	fputs("Hello1 \n", fp);
	fputs("Hello2 \n", fp);
	
	//指定形式での書き出し
	int a = 5;
	fprintf(fp, "%02d\n", a);
	fclose(fp);
	
	return 0;
}

上記の場合は

Hello 
Hello1 
Hello2 
05

という内容のb.txtファイルが新規作成されます。
fputsを繰り返し記述するのは良いのか悪いのか考えてみますが、動作上は特に問題なくファイルへの書き込みは完了しました。
書き込む内容を一旦、変数などにまとめて、最終的に一回のfputsで書き込んだほうがプログラムとしてはすっきり明確になります。

ファイルの読み込み

Posted コメントするカテゴリー: C

ファイルを読み込むプログラムを作成します。
ファイルの読み込みの判定を行わないと、a.txtがない場合に無限にループしてしまいます。

また、fgets関数は読み込んだファイル内容について、自動的に改行コードまでをひとつの文字列として認識します。

#include <stdio.h>

int main(void)
{
	char s[10];
	FILE *fp;
	fp = fopen("a.txt", "r");
	
	//ファイルオープンの判定
	if (fp == NULL) {
		printf("file null \n");
		return;
	}
	
	//ファイルを最後まで読み込む
	while(1) {
		//「10」は読み込み最大文字数
		fgets(s, 10, fp);
		printf("%s \n", s);
		if (feof(fp)) {
			printf("break!! \n");
			break;
		}
	}

	//ファイルを閉じる
	fclose(fp);

	return 0;
}