【初心者向け】情報学部生と学ぶC言語 [7限目:構造体]

構造体とは

例えば、30人のクラスのテストの点数を扱う時のことを考えてみましょう。名前のための変数”name”、数学のための変数”math”、英語のための変数”english”を用意して各々にデータを入力していくとします。このとき、名前の表には「”田中太郎”,”山田花子”,…」といったように名前のデータだけ、数学の表には「”60”,”80”,…」と数学の点数のデータだけが格納されているとしたらとても分かりにくいですよね?

普通、こういう時は「”田中太郎”について”数学”,”英語”のデータ」、「”山田花子”について”数学”,”英語”のデータ」と一人ひとりデータを分けて扱います。

このように複数のデータを一つのまとまりとして扱う時に使用されるのが構造体です。

では、「『九州』にある県の『県名』と『人口』、『面積』を構造体としてひとまとめにし、それらを表示するプログラム」を作ってみましょう。

#include<stdio.h>
#include<string.h>

#define MAX 64

struct kyushu {
	char prefecture[MAX]; //県名
	int population; //人口
	double square; //面積
};

int main(void)
{
	struct kyushu fukuoka;
	
	strcpy(fukuoka.prefecture, "Fukuoka");
	fukuoka.population = 511;
	fukuoka.square = 4986.52;
	
	printf("県名 : %s\n", fukuoka.prefecture);
	printf("人口 : %d 万人\n", fukuoka.population);
	printf("面積 : %.2f 平方キロメートル\n", fukuoka.square);
	
	return 0;
}
■実行結果
県名 : Fukuoka
人口 : 511
面積 : 4986.52

解説

構造体は以下のように宣言します。

struct 構造体タグ {
    型名 メンバ
};

上記のソースコードでは、

構造体タグが「kyushu」でメンバが「”prefecture”,”population”,”square”」となります。

構造体を宣言した時、記憶域上には各メンバが宣言順に並びます。

そして、これら個々のデータをひとつのオブジェクトに格納するための宣言が上記のプログラムの以下の部分となります。

struct kyushu fukuoka;

構造体の個々のデータにアクセスするとき

オブジェクト.メンバ

と記述することでそのオブジェクトに関しての個々のデータを扱うことができます。

例えばオブジェクト”fukuoka”の人口”population”にアクセスする時、”fukuoka.population”と記述して取り扱います。

オブジェクト”fukuoka”について図で示したものが以下になります。

上のプログラムでは構造体の型の変数の宣言を行ったのちに、数値の代入を行っていますが、宣言した時に初期化を行うことで簡略化することができます。

また、構造体の宣言時にtypedef宣言といって

typedef struct 構造体タグ {
    型名 メンバ
} typedef名;

 

とすることで構造体の型の変数を宣言する際に

typedef名 変数名

とすれば良くなるため、記述が簡潔化します。

これらを利用して、上記のプログラムを書き換えたものが以下のプログラムです。

#include<stdio.h>

#define MAX 64

typedef struct kyushu {
	char prefecture[MAX]; //県名
	int population; //人口
	double square; //面積
} Kyushu;

int main(void)
{
	Kyushu fukuoka = {"Fukuoka", 511, 4986.52};
	
	printf("県名 : %s\n", fukuoka.prefecture);
	printf("人口 : %d 万人\n", fukuoka.population);
	printf("面積 : %.2f 平方キロメートル\n", fukuoka.square);
	
	return 0;
}
今は”fukuoka”だけしか扱ってないけど、それ以外の県の情報を追加した時mainで同じようなことを何回も書かなきゃいけないよね?メンドクセー

構造体の型の変数には配列も使用できます。これでその悩みは解決できますね。

#include<stdio.h>

#define MAX 64
#define MEMBER 3

typedef struct kyushu {
	char prefecture[MAX]; //県名
	int population; //人口
	double square; //面積
} Kyushu;

int main(void)
{
	Kyushu mem[] = {
			{"Fukuoka", 511, 4986.52},
			{"Kumamoto", 175, 7409.48},
			{"Oita", 113, 6340.73},
			};
	
	for(int i=0;i<MEMBER;i++){
		printf("県名 : %s\n", mem[i].prefecture);
		printf("人口 : %d 万人\n", mem[i].population);
		printf("面積 : %.2f 平方キロメートル\n", mem[i].square);
		if(i != MEMBER-1)
			puts("");
	}
	
	return 0;
}
■実行結果
県名 : Fukuoka
人口 : 511 万人
面積 : 4986.52 平方キロメートル

県名 : Kumamoto
人口 : 175 万人
面積 : 7409.48 平方キロメートル

県名 : Oita
人口 : 113 万人
面積 : 6340.73 平方キロメートル

C言語学習におすすめのテキストはこちら

【初心者向け】情報学部生と学ぶC言語 [6限目:ポインタ]

ポインタはC言語の学習における最難関のひとつとされています。現にポインタを理解出来ないためにC言語の習得を諦める人も多数います。そこでポインタを理解するために以下のステップを踏んで説明していきます。いずれもポインタを理解するためには必要な知識となるためひとつひとつしっかり理解されることを推奨します。

ふたつの値の和、差、積、商を求める関数を用いて、main関数内でそれらの答えを出力するプログラムを作りましょう。

#include <stdio.h>

void cal(int num1, int num2, int sum, int diff, int prod, double quot)
{
	sum = num1 + num2;
	diff = num1 - num2;
	prod = num1 * num2;
	if(num2==0)
		quot = 0;
	else
		quot = (double)num1 / (double)num2;
}

int main(void)
{
	int x,y;
	int wa = 0, sa = 0, seki = 0;
	double sho = 0.0;
	
	printf("整数1:");
	scanf("%d", &x);
	printf("整数2:");
	scanf("%d", &y);
	
	cal(x, y, wa, sa, seki, sho);
	
	printf("和:%d\n", wa);
	printf("差:%d\n", sa);
	printf("積:%d\n", seki);
	printf("商:%.1f\n", sho);
	
	return 0;
}
■実行結果[例]
整数1:30
整数2:8
和:0
差:0
積:0
商:0.0
あれれ~?おかしいぞ~?
答えが全部0になってるよ。

さすがコ○ン君!実は、こうなってしまうという所に「値渡しとは何なのか」という事が表されています。

値渡しとは

値渡しとは、コンピュータプログラム中で関数やプロシージャなどに渡す引数として変数などを指定する際、その値のみを引き渡す方式。渡された引数の値を変更しても呼び出し元の変数の値は更新されない。


引用元:IT用語辞典 e-Words

「渡された引数の値を変更しても呼び出し元の変数の値は更新されない。」という所に注目しましょう。

例えば上記の引用文を利用してこのページの中で以下のような文章に書き換えたとします。

値渡しとは、「アタイ・ワタシ」の2語から構成され、女の子の一人称を表す隠語である。

この時、このページ内の「値渡しとは」の文章(コピーした値)は変更されましたが、引用元の文章(オリジナルの値)は変更されませんよね?

これが値渡しというものです。値渡しでは引数によりひとつの値を計算して返すことは出来ますが、上記のプログラムのように複数の値を一度に計算したい時には、2個以上の値を返せないという性質上、実現できません。

そこで利用されるのがポインタです。

ポインタを理解するために、まずアドレスというものを理解しなければなりません。

アドレスとは

英語でアドレス(address)というと、住所や番地のほかに演説や講演といったような意味がありますが、ここで使うアドレスは番地ということを意味します。つまり、自分のいる所(=場所)を示しています。各々の変数には宣言した時にアドレスが付与されます。アドレスを用いる際、変数の前に”&”を用います。この”&”アドレス演算子と言います。そしてアドレスを出力するための変換指定には%pを用います。

pはpointerの意

変数名 アドレス演算子 変換指定
n &n %p

では、さまざまな型のアドレスを出力するプログラムを作りましょう。

#include <stdio.h>
int main(void){
	int a;
	double b;
	char c;
	
	printf("aのアドレス:%p\n", &a);
	printf("bのアドレス:%p\n", &b);
	printf("cのアドレス:%p\n", &c);
	
	return 0;
}
■実行結果[例]
aのアドレス:200
bのアドレス:204
cのアドレス:208

ここでは説明のためアドレスの出力を簡易的に”200″といったような10進数で表示していますが、通常は16進数で表示されると思います。[例]0x000000000000(実行環境により異なる)

ポインタとは(参照渡しとは)

最初に作成した「ふたつの値の和、差、積、商を求める関数を用いて、main関数内でそれらの答えを出力するプログラム」はポインタというものを使うことにより実現できます。以下のソースコードからポインタの使い方についてみていきましょう。

#include <stdio.h>

void cal(int num1, int num2, int *sum, int *diff, int *prod, double *quot)
{
	*sum = num1 + num2;
	*diff = num1 - num2;
	*prod = num1 * num2;
	if(num2==0)
	*quot = 0;
	else
	*quot = (double)num1 / (double)num2;
}

int main(void)
{
	int x,y;
	int wa = 0, sa = 0, seki = 0;
	double sho = 0.0;
	
	printf("整数1:");
	scanf("%d", &x);
	printf("整数2:");
	scanf("%d", &y);
	
	cal(x, y, &wa, &sa, &seki, &sho); // (num1 = x, num2 = y, int *sum = &wa, 以下略)を意味する
	
	printf("和:%d\n", wa);
	printf("差:%d\n", sa);
	printf("積:%d\n", seki);
	printf("商:%.1f\n", sho);
	
	return 0;
}
■実行結果[例]
整数1:20
整数2:8
和:28
差:12
積:160
商:2.5

解説

ポインタは変数の前に”*”を付けて宣言します。例えば「intへのポインタ型p」を生成したい時は以下のように宣言します。

int *p;

この時、変数は「『int型の値を格納する変数のアドレス』を格納する箱」を意味します。

そして

int *p;
p = &n;

とした時、ポインタpにはnのアドレスが格納されます。このことを「pはnを指す」といいます。

そして、ポインタが指し示す先の中身を使用する時には”*”(間接演算子という)を付けます。この時ポインタは格納されているアドレスを参照して、そのアドレスにある変数の中身を指します。そしてその変数の中身を出力します。このことを慣例的に参照渡しといいます。

ここで、ポインタの使い方のおさらいをしておきましょう。

int *p; // intへのポインタ型の変数pの宣言
p = &n; // pにnのアドレスを格納
printf(“%d”, *p); //間接演算子”*”をつける事で参照したアドレス先の中身を扱える

値渡しと参照渡しの違い

先程のプログラムからポインタを使わない場合(=値渡し)とポインタを使う場合(=参照渡し)の違いをみていきましょう。

値渡し

値渡しは中身が同じである変数を複製します。この時、格納されているアドレスが異なるため複製した値を変更してもオリジナルの値は変わりません。

参照渡し

参照渡しはオリジナルの値が格納されている変数のアドレスを複製します。オリジナルのアドレスが格納された変数の値を変更する時、そのアドレスを参照してオリジナルの値そのものを変更します。

そういえば、今まで何も考えずに使ってたけど
scanf(“%d”, &n);
ってアドレス演算子を使ってたんだ!

いい所に気づきましたね!scanfは「渡されたアドレスを参照して、そこにある変数の中身を入力される値に変更する」という関数だったのです。

ポインタについて理解できるかどうかがC言語について理解しているかどうかに直結するといっても過言ではありません。しっかり復習してポインタを理解できるようになりましょう。


C言語学習におすすめのテキストはこちら

【初心者向け】情報学部生と学ぶC言語 [5限目:列挙体]

列挙体とは

列挙体について理解するために、以下に示す

[様々な国の選択肢の中から選ばれた国の挨拶を表示するプログラム]

から列挙体とはどういうものなのか、そしてその使い方について学んでいきましょう。

#include <stdio.h>

enum greet { Japan, America, Korea, Invalid};

void japan(void)
{
	puts("こんにちは");
}

void america(void)
{
	puts("hello");
}

void korea(void)
{
	puts("안녕하세요");
}

enum greet select(void)
{
	int tmp;
	
	do{
		printf("0...日本 1...アメリカ 2...韓国 3...終了:");
		scanf("%d", &tmp);
	}while (tmp < Japan || tmp > Invalid);
	
	return tmp;
}

int main(void)
{
	enum greet selected;
	
	do {
		switch (selected = select()){
		  case Japan : japan(); break;
		  case America : america(); break;
		  case Korea : korea(); break;
		}
	}while (selected != Invalid);
	
	return 0;
}
■実行結果
0…日本 1…アメリカ 2…韓国 3…終了:0
こんにちは
0…日本 1…アメリカ 2…韓国 3…終了:1
hello
0…日本 1…アメリカ 2…韓国 3…終了:2
안녕하세요
0…日本 1…アメリカ 2…韓国 3…終了:3

解説

列挙体とは、限られた整数値の集合を表すものです。列挙体は以下のように宣言します。

enum greet { Japan, America, Korea, Invalid };

greetを列挙体タグといい、{}内のJapan, America, Korea, Invalidを列挙定数といいます。このように宣言したとき、列挙定数には、Japanから順に、0, 1, 2, 3 と整数値が与えられます。この時、”enum greet”を列挙型といい、列挙型に変数をつけて宣言することで、その変数は列挙定数の値を取りうる変数となります。

enum greet selected;

このプログラムでは、enum greet型の変数selectedは0, 1, 2, 3の値を取りうるということになります。

ここでワンポイント

Invalidは「無効」という意味で、このプログラムでは、終了するときのための列挙定数として使用していますが、Invalidを使用せずとも同じ動きをするプログラムは作れますよね?例えばenum greet型の関数selectの中のdo-while文の条件を

//Invalidを使用しない例

do{
    ...
}while(tmp < Japan || tmp > Korea + 1);

とすれば実現可能です。

しかし、ここで新しい選択肢として、”China”を入れたいとき、先程の条件式を毎回書き換える必要があります。

//Invalidを使用せず列挙定数"China"を加えた例

enum greet { Japan, America, Korea, China };
...
do{
    ...
}while(tmp < Japan || tmp > China + 1);

しかし、Invalidを用意しておけば条件式は変更することなく、列挙体の宣言だけ変更すれば良いので、いかに有効かがわかると思います。

//Invalidを使用し列挙定数"China"を加えた例

enum greet { Japan, America, Korea, China };
...
do{
    ...
}while(tmp < Japan || tmp > Invalid);

補足

列挙定数の値は 列挙定数 = 整数値 という形で自由に設定することもできます。

例

enum name { Tanaka , Yamada = 3, Kato };

この時Tanakaの値は0、Yamadaの値は3、そしてKatoの値は指定されていないため、前の列挙定数(ここではYamada)に1を足した4になります。

列挙定数は同じ値でも構いません。いかの例では、TanakaとTaroの値はともに0となります。

例

enum name { Tanaka , Taro = 0 };

列挙体タグは必要でなければ省略することもできます。その時、その列挙型の変数の宣言はできなくなるので注意しましょう!

例

enum { JANUARY = 1, FEBRUARY, ..., DECEMBER};

上記の例を使用することで

#define JANUARY 1
#define FEBRUARY 2
...

と宣言したいとき、簡単に宣言する事が可能です。


C言語学習におすすめのテキストはこちら

日本人の6割が損してる!自己肯定感の高め方4選

あなたは自分に満足していますか?

これは内閣府が行った満13~29歳の若者を対象とした意識調査(我が国と諸外国の若者の意識に関する調査(平成25年度))における質問のひとつです。

この質問に対して

「満足している」と答えた日本人…45.8%

日本以外の諸外国…約8割

と、諸外国に比べて著しく低かったようです。

自分に満足しているかというのは、自己肯定感の高さと密接な関係があります。

自己肯定感(じここうていかん)とは、自らの在り方を積極的に評価できる感情、自らの価値や存在意義を肯定できる感情などを意味する言葉であり、自尊心(英語: self-esteem)、自己存在感、自己効力感(英語: self-efficacy)、自尊感情などと類似概念であり同じ様な意味で用いられることがある。

この自己肯定感が高いほど、人生の幸福度も高いようです。自己肯定感が高いことにはたくさんの利点がありますが、自己肯定感が低くても利点はひとつもありません。

え?でも、自己肯定感が自分に満足しているってことなら、自分に満足してたら向上心とかなくなって、新しい事に挑戦しなくなるんじゃないの?

実は、自己肯定感が低いと「挑戦してもどうせ失敗するんだろうな」と考え、挑戦力も低下してしまうようです。

じゃあ、自己肯定感が低い僕たちは不幸な人生なんだ…

安心して下さい!自己肯定感は自分の力で高めることができます。これから紹介する方法は効果があることが実際に証明されているものなので、自分って自己肯定感低いかもなと思っている人は試してみてください。

毎日5つの感謝

寝る前に今日起きた感謝出来る事を思い出して5つほど書き出しましょう。

感謝することを探すと脳はポジティブなものに目がいくようになります。また、感謝出来る事を探していけば、自分が周りの人に支えられて生きているんだと気づき、「私はここにいてもいいんだ」と実感できるようになります。

でも、今日ずっと家にいたし、誰にも会ってないから感謝できることとかないんだけど…

そんな日もあると思いますが、その中からでも感謝できることを探すということが重要です!例えば今日食べた食材は誰が作ったものでしょうか?そして誰が店まで届けたのでしょうか?何もなかった日の方が本質的なものに気付けるかもしれません。

今日の自分に○をつける

こちらも寝る前に今日あったことを振り返りましょう。そして、良かったこと悪かったこと出来たこと出来なかったこと全部含めて「今日の自分に○」と自分に○をつけましょう。

またセルフハグも自己肯定感を高める効果があるようなので同時にセルフハグを行うのもいいのではないかと思います。

失敗したイメージを成功したイメージに書き換える

何かで失敗した時、「失敗したけどまあいいか。次はうまくいくだろう。」とその失敗に囚われなければよいのですが、真面目な人ほど「ちゃんとやらなきゃいけない」という思いがあるので、何度もその失敗を振り返ってしまいます。その度に自己肯定感を低下させてしまうことになります。そこで、失敗したイメージを成功したイメージに書き換える方法を使いましょう。

失敗する前の場面をイメージし、そこからうまくいったイメージを思い浮かべます。

それを何度も繰り返しましょう。

そんなの効くの?と思われるかもしれないので、成功イメージの有用性についての実験を紹介しましょう。

バスケットの選手を3つのグループに分けます。

グループA…シュートの練習をするグループ


グループB…何もしないグループ


グループC…シュートが入るイメージトレーニングをするグループ

グループAとCだけシュートの成功率が上がったのですが、AもCもほぼ同じ割合で成功率が上がったそうです。

またこちらは僕のツイートですが、こちらも実際に起こったことらしいので、如何にイメージといえど馬鹿にできないですね。

目標設定とスモールステップ

自己肯定感をあげるには成功体験を積み重ねていくことが重要になります。

そこで明確な目標設定とそれを成功させるためのスモールステップを設定しましょう。

ここで注意しなければならないことが、実現できるレベルの目標を設定するということです。

例えば、「毎日1時間勉強する」という目標は、体調不良や不測の事態が起こった時に失敗してしまいがちです。ストイックな人ほど成長するために自分に負荷を与えようとしますが、自己肯定感を高めるためには成功可能な目標を掲げることが重要になります。

また、もし失敗した時、不測の事態が起こった時の事をあらかじめ予想して、その時にどういう感情になるはずだから、どういう行動をとるかという事を決めておきましょう。

以下は例です。参考にしてみてください。

<例> 

目標


    ○月○日までに○○みたいな体型になる


スモールステップ


    火、木、土はジムで1時間トレーニング


        やる気が起きない→時間を減らす


        ジムに行けない→家で腕立て、腹筋、スクワット


        それもできない→今日は休養日だと思って積極的に体を休める

まとめ

こんな事して、ほんとに効果があるの?と思われるかもしれませんが、まずは3ヶ月間続けてみてください。今回紹介した方法は、いずれも効果が証明されています。少なくとも言えることは、何もしなければ変わりません。ぜひ、これらの方法を試して、みんなで幸せになりましょう!

⬇️⬇️⬇️今回紹介した方法以外に様々な方法が多数紹介されています⬇️⬇️⬇️

【初心者向け】情報学部生と学ぶC言語 [4限目:関数]

今回は関数について勉強していきましょう

関数とは

今までのプログラムで毎回書いてきたものがありますよね?その中の以下の部分をmain関数といいます。


int main(void)
{
    //省略
}

また、printfやscanfなどをライブラリ関数といいます。

これまではmain関数のみのプログラムを作成してきましたが、自分で関数を作成し、それを組み合わせてプログラムを作ることもできます。そこで今回は関数の作り方と関数の使い方について学んでいきましょう。

関数の作り方

二つの整数値のうち大きい方を返す関数を作ってみましょう。


int bigger (int x, int y)
{
    if (x > y)
        return x;
    else
        return y;
}

この関数の名前(関数名)はbiggerです。

この関数はintで宣言されているため、関数が呼び出されたとき、intの値を返します。

int x, int yは仮引数と呼ばれます。

関数の使い方

作成した関数を使うためには関数呼び出しをしなければなりません。

では先程作った関数をmain関数の中で呼び出して、二つの整数値のうち、大きい方の値を求めるプログラムを作成しましょう。

#include<stdio.h>
int bigger(int x, int y)
{
	if(x > y)
		return x;
	else
		return y;
}

int main(void)
{
	int num1,num2;
	
	printf("ひとつ目の数字は:");
	scanf("%d", &num1);
	printf("ふたつ目の数字は:");
	scanf("%d", &num2);
	
	printf("大きい方の値は%dです.\n", bigger(num1,num2));
	
	return 0;
}
■実行結果[例]
ひとつ目の数字は:5
ふたつ目の数字は:8
大きい方の値は8です.

解説

上のソースコードのmain関数内のprintfに注目してください。

printf(“大きい方の値は%dです.\n”, bigger(num1,num2));

赤の部分が関数呼び出し式とよばれ、関数呼び出し式の記述により関数を呼び出すことができます。また、()内のnum1, num2のことを実引数といいます。実引数の値が仮引数にセットされ、関数内で処理が行われた後return文により、その値が関数呼び出し式に返却されます。




関数の引数には配列を使用することもできます。平均を計算する関数を作成し5人のテストの点数の平均を求めるプログラムを作ってみましょう。

#include<stdio.h>
#define NUM 5 //受験者数

double ave(int v[], int x)
{
	int i,sum;
	sum = 0;
	
	for(i=0;i<x;i++)
		sum += v[i]; // sum = sum + v[i];
	
	return (double)sum/x;
}

int main(void){
	int score[NUM];
	
	puts("テストの点数を入力してください");
	for(int i=0;i<NUM;i++)
	{
		printf("%d番目:",i+1);
		scanf("%d", &score[i]);
	}
	
	printf("テストの平均は%.1f点です.\n", ave(score, NUM));
	
	return 0;
}
■実行結果[例]
テストの点数を入力してください
1番目:50
2番目:78
3番目:92
4番目:34
5番目:66
テストの平均は64.0点です.


いかがでしたか?機能ごとに関数を作成することで、ソースコードがわかりやすくなり、エラーが発生した時も全体に影響を及ぼしにくくなったり対処がしやすくなったりと様々な利点があります。

慣れるまでは難しく感じるかもしれませんが、頑張って使いこなせるようになりましょう!

C言語学習におすすめのテキストはこちら

【初心者向け】情報学部生と学ぶC言語 [3限目:条件分岐文]

条件分岐とは

今までのプログラムでは上から下へと順番に命令を行なっていくものでした。しかし、プログラムは一方通行ばかりではありません。条件分岐についてイメージしてみましょう。あなたは今冒険をしています。ドラクエの勇者とかポケモントレーナーにでもなった様子を想像しましょう。目の前には分かれ道。分かれ道の前に看板があります。看板には「○○村← →○○洞窟」の記述が。

この看板は、「あなたが○○村に行きたいなら左に行きなさいあなたが○○洞窟に行きたいなら右に行きなさい。」という「条件(赤字)命令(青字)」を意味していますよね。プログラミングでも同様に、条件と命令を記述していく必要があります。

条件
{
    命令
}

と記述することで条件分岐を行います。条件には、if文、(do)while文、for文、switch文があります。では、これら各文について学んでいきましょう。

if文

入力された数値が「正、0、負」のどれに該当するかを出力するプログラムを作りましょう。

#include<stdio.h>
int main(void)
{
	int num;
	printf("数値を入力してください:");
	scanf("%d",&num);
	
	if(num==0) //a==b:aとbが等しければ、a!=b:aとbが異なるならば
	{
		puts("入力された数字は0です.");
	}else if(num>0){
		puts("入力された値は正です");
	}else{
		puts("入力された値は負です");
	}
	
	return 0;

}
■実行結果
数値を入力してください:10
入力された値は正です
数値を入力してください:-10
入力された値は負です
数値を入力してください:0
入力された値は0です

解説

if(条件)
{
   命令1
}

「もし条件のとき命令1を実行」となります。

else
{
    命令2
}

「これまでの条件以外のとき命令2を実行」となります。

これらは組み合わせることもできまして、

else if(条件)

とすることで「これまでの条件以外のうち(条件)のとき」ということを意味します。

==演算子!=演算子のことを等価演算子と言います。一般的には学校で習った数学の知識により「a=b」で「aとbが等しい」ってことじゃないの?と思われると思いますが、変数の時に説明したようにプログラミングの世界では「a=b」は「aという変数にbという値を代入する」という意味になります。そこで「aとbが等しい」を実現するために「a==b」、「aとbが異なる」を「a!=b」で表します。

ちょっとしたポイント

正、0、負に分けるようなプログラムのとき、「数値が正かどうか→0かどうか→負かどうか」の順で条件分岐を行いがちですが、最初に数値が一つに限定されるもの(このプログラムでいえば0)を使って条件分岐したほうがわかりやすいプログラムになります。プログラムを作るときわかりやすいかどうかを意識できるようになると脱初心者の第一歩になるでしょう。

(do)while文

基本的には、do文、while文というように分けて言います。しかし、do文はwhile文と一緒に使うという特性上一緒に説明していきます。ではまず、while文についてみていきましょう。

#include<stdio.h>
int main(void){
	
	int plus,minus;
	int i=0;
	printf("正の数値を入力してください:");
	scanf("%d", &plus);
	minus = plus;
	
	while(minus>0){
		printf("%d ",minus--);
	}
	puts("");
	
	while(i<plus){
		printf("%d ",++i);
	}
	puts("");
	
	return 0;
}
■実行結果
正の数値を入力してください:10
10 9 8 7 6 5 4 3 2 1
1 2 3 4 5 6 7 8 9 10

解説

while文は

while(条件)
{
    命令
}

で表現し、「条件が満たされる間命令を繰り返す」という条件分岐となります。

”++”インクリメント演算子”–”デクリメント演算子といい変数を+1または-1します。これらの演算子を変数の前につける時、、「前置インクリメント(デクリメント)演算子」と呼ばれ、変数の後ろにつける時、、「「後置インクリメント(デクリメント)演算子」と呼ばれます。

前置演算子とは、式を評価する前にインクリメント(デクリメント)、しますよということを意味します。プログラムでいえば

printf("%d ",++i);

が該当し、printfでiの値を出力する前にiの値を+1しています。

後置演算子は前置演算子とは順番が逆で、式を評価した後で変数をインクリメントまたはデクリメントします。

続いてdo文です。do文は少なくとも一度は命令を実行したい時に使用されます。生まれた月を訪ねるプログラムで見てみましょう。

#include<stdio.h>
int main(void){
	int month;
	
	do{
		printf("あなたの誕生月は?:");
		scanf("%d",&month);
	}while(month<1||month>12);
	puts("thank you!");
	
	return 0;
}
■実行結果
あなたの誕生月は?:-1
あなたの誕生月は?:15
あなたの誕生月は?:3
thank you!

解説

do
{
    命令
}while(条件);

で表します。

これまでと異なるのが、条件が命令の後に記述されるということです。

こうすることで少なくとも一度は命令が実行されることになります。その後while文の条件を評価して、命令を繰り返すかどうかが決まります。

for文

for文はwhile文のように繰り返し(ループ)を行うために用いられますが、while文よりもわかりやすく読みやすいためwhile文より多用されます。

べき乗を計算するプログラムを用いてfor文の使い方を確認してみましょう。

#include<stdio.h>
int main(void){
	int r,n,x;
	printf("数値を入力してください:");
	scanf("%d",&r);
	printf("何乗しますか?:");
	scanf("%d",&n);
	
	x=r;
	
	for(int i=1;i<n;i++)
	{
		r = r*x;
	}
	printf("%dの%d乗は%dです\n",x,n,r);
	
	return 0;
}
■実行結果
数値を入力してください:2
何乗しますか?:3
2の3乗は8です

解説

for文は

for(式1;式2;式3)
{
    命令
}

で表現されます。式1は前処理と言われ、繰り返しの前に一度だけ評価されます。式2は制御式と言われ、ここが基本的な条件になります。式3は後始末と言われ、ループ後に評価されます。

i=1
while(i<n){
    r=r*x;
    i++;
}

と書き換えられますね。

練習問題

九九の表を作ってみましょう。

#include<stdio.h>
int main(void)
{
	for(int i=1;i<=9;i++){
		for(int j=1;j<=9;j++){
			printf("%2d ",i*j);
		}
		puts("");
	}
	return 0;	
}
■実行結果
1 2 3 4 5 6 7 8 9
2 4 6 8 10 12 14 16 18
3 6 9 12 15 18 21 24 27
4 8 12 16 20 24 28 32 36
5 10 15 20 25 30 35 40 45
6 12 18 24 30 36 42 48 54
7 14 21 28 35 42 49 56 63
8 16 24 32 40 48 56 64 72
9 18 27 36 45 54 63 72 81

解説

まず、iが1の時が評価されます。その中の命令にfor文があるためjが1から9までの値の時i*jを出力します。その後iが2となり、この時jが1から9までというように繰り返されます。

switch文

switch文は多岐に条件分岐させたいときに用いられます。do文のところで作成した誕生月を尋ねるプログラムを改変してswitch文の使い方について確認してみましょう。

#include<stdio.h>
int main(void){
	int month;
	
	do{
		printf("あなたの誕生月は?:");
		scanf("%d",&month);
	}while(month<1||month>12);
	
	printf("あなたは");
	switch(month){
	  case 1:
	  case 2:
	  case 3: printf("冬"); break;
	  case 4:
	  case 5:
	  case 6: printf("春"); break;
	  case 7:
	  case 8:
	  case 9: printf("夏"); break;
	  case 10:
	  case 11:
	  case 12: printf("秋"); break;
	}
	printf("生まれです.\n");
	
	return 0;
}
■実行結果
あなたの誕生月は?:1
あなたは冬生まれです.
あなたの誕生月は?:7
あなたは夏生まれです.

解説

switch(変数)
{
    case 変数の値: 命令
}

で表します。

breakと記述することで、条件分岐から抜け出します。もしbreakがなければ、変数の値が合致するところ以降の命令が全て実行されてしまうため、このプログラムで例えば”4″と入力したとき”あなたは春夏秋生まれです.”と出力されてしまいます。



条件分岐をうまく使うことによりプログラムを簡潔化させることができます。しっかり復習して使いこなせるようになりましょう!

C言語学習におすすめのテキストはこちら

【初心者向け】情報学部生と学ぶC言語 [2限目:様々な型と配列]

今回は前回に少しだけ触れたについて勉強していこうと思います。その過程で配列の知識も必要になってくるので配列についても抑えていきましょう。

前回の復習

型にはどんな種類があったのかおさらいしておきましょう。下の表を見てください。

 
型名とその意味
型名 意味
int 整数型
double 浮動小数点数型(8バイト)
float 浮動小数点数型(4バイト)
char 文字型
void 型なし

ではそれぞれの型について確認していきましょう。

int型

int型とは、整数を扱うための型で、サイズは4バイトです。バイトというのは情報量の単位のことで1バイト=8ビットとなります。ビットも同じく情報量の単位のことなのですが、こちらは最小単位となります。コンピュータは0と1の二つの値を組み合わせて情報を扱う(=2進数)ので、1ビットとは取り扱っているデータの一桁目が”0″か”1″かを表現していると思ってください。以下の表で2進数の3ビットで表現できる数字を確認しましょう。

 
3ビットまでで表現できる数字
ビット表現
(2進数)
普段扱う数字
(10進数)
ビット表現
(2進数)
普段扱う数字
(10進数)
0 0 100 4
1 1 101 5
10 2 110 6
11 3 111 7

表からもわかるように3ビット(桁)で0〜7の8個(2個)の数字を表現することができます。

nビットで表現できる数字の数は2n表現できる範囲の数字は0〜2n−1ということです。

***説明のため正の数に限定していますが負の数が入ってくると表現できる範囲は変わることに注意しましょう***

では4バイトのとき表現できる数字の数と範囲について考えてみてください。

4バイト = 4 × 8 ビット より
数字の数:232
範囲:0〜232−1

では二つのint型の数字の平均を計算するプログラムを作成してみましょう。

/***
filename:average.c
***/

#include<stdio.h>
int main(void)
{
int num1,num2;

printf("一つ目の数字を入力してください:");
scanf("%d",&num1);
printf("二つ目の数字を入力してください:");
scanf("%d",&num2);

printf("ふたつの値の平均は %d です\n", (num1+num2)/2);

return 0;
}
■実行結果<例>
一つ目の数字を入力してください:24
二つ目の数字を入力してください:11
ふたつの値の平均は 17 です

二つの平均値は17ってなってるけど、、、
(24+11)/2=17.5だよね?

鋭い指摘ですね。int型では小数部は切り捨てられます。そこで次に浮動小数点数を扱えるdoubleとfloatについて学んでいきましょう。

double(float)型

double(float)型について理解するために上のプログラムを改変した下のプログラムを作ってみましょう。

/***
filename:average_double.c
***/

#include<stdio.h>

int main(void)
{
	int num1,num2;
	double ans_d;
	float ans_f;
	
	printf("一つ目の数字を入力してください:");
	scanf("%d",&num1);
	printf("二つ目の数字を入力してください:");
	scanf("%d",&num2);
	
	ans_d = num1 + num2; //ans_d = (num1+num2)/2; としないことに注意
	ans_d = ans_d/2;
	
	ans_f = num1 + num2;
	ans_f = ans_f/2;
	
	
	puts("ふたつの値の平均は");
	printf("	double型ans:%f\n", ans_d);
	printf("	float型ans:%f\n", ans_f);
	printf("	キャスト:%.1f\n", (double)(num1 + num2) / 2); //(num1+num2)をdouble型にキャスト
	puts("です");
	
	return 0;
}
■実行結果<例>
一つ目の数字を入力してください:24
二つ目の数字を入力してください:11
ふたつの値の平均は
double型ans:17.500000
float型ans:17.500000
キャスト:17.5
です

実行結果からもわかるようにdoubleとfloatでは小数を扱えるということにおいて違いはありません。両者の違いは扱える範囲で、double型の方が広い範囲を扱えるよくらいの認識で大丈夫です。

ソースコードの説明

double型をprintfで出力するためには、変数指定フォーマットは%fとする必要があります。この時小数第6位まで表示されます。

ans_d = num1 + num2; //ans_d = (num1+num2)/2; としないことに注意
ans_d = ans_d/2;

の部分ですが、上の行ではint型の変数 num1 + num2 をdouble型の変数 ans_d に変換しています。上の例で言えば、num1 + num2 は 24 +11 なので 35 になります。それをdouble型に変換するので 35.000000 となります。
そして2行目で35.000000を2で割っているためans_dには17.500000が格納されているということになります。

“//ans_d = (num1+num2)/2; としないことに注意”とありますがなぜこれがダメなのでしょうか?

これは、35/2を計算した結果(=17[int型であるから小数点切り捨て])をdouble型に変換することになってしまい、ans_dに格納された数字は 17.000000 になってしまうということが問題です。

printf("	キャスト:%.1f\n", (double)(num1 + num2) / 2); //(num1+num2)をdouble型にキャスト

キャストとは、上で行った、ans_d = num1 + num2; の操作と似たようなもので、あらかじめ宣言していた型から別の型に変換するときに使います。
(double)(num1 + num2) の部分がキャストを行っている部分で、
(型名) 変数名
で宣言します。

また変数指定フォーマットを%.1fとしていますが”.1″とつけることで小数点第1位まで表示してくださいという指示を送ることができます。

このプログラムではint型のnum1とnum2をdouble型に変えるということを行っていますが、最初から
double num1,num2;
と宣言しておくという手法もあります。

そのとき、scanfの変数指定フォーマットは%lf(エルエフ)としなければならないことに注意しましょう。

scanf("%lf", &num1);

char型

続いては文字型のcharについてみていきましょう。

charは文字を格納する変数を扱うための型です。以下のプログラムで確認していきましょう。

/***
filename:char.c
***/

#include<stdio.h>

int main(void)
{
	char s1[] = "A";
	char s2[] = "ABC";
	
	printf("s1の文字列は %s\n",s1);
	printf("s2の文字列は %s\n",s2);
	printf("s2の文字列の1文字目は %c\n",s2[0]);
	printf("s2の文字列の2文字目は %c\n",s2[1]);
	printf("s2の文字列の3文字目は %c\n",s2[2]);
	printf("s2の文字列の4文字目は %c\n",s2[3]);
	
	return 0;
}

このソースコードを理解するためにはまず、配列について学ばなければいけません。一緒に確認していきましょう。

配列

配列は
型名 変数[要素数]
で宣言します。

変数とは文字や数字を格納するための箱のようなものです。配列はその箱を要素数ぶんだけ並べたものだと思ってください。図に示すとこんな感じ。

配列の要素数は指定しなければ、宣言された時の文字列と文字列の終わりを表す”\0″の分だけ用意されます。ですから上の変数sの配列の要素数は”ABC”と”\0″を合わせて4つということになります。
要素数は0番目から始まるので格納された文字のn番目を呼び出したいときには、
変数[n-1]
と宣言しなければいけません。

ソースコードの説明

printfで文字を出力するときの変数指定フォーマットは%sです。
逆に一文字だけ出力するときには%cを使います。



様々な型が扱えるようになったことで、作成できる範囲が広がったのではないかなと思います。
次回はif文やfor文など条件分岐について扱っていきます。条件分岐では配列が活躍するので、復習しておきましょう。

C言語学習におすすめのテキストはこちら

幸せに生きるコツ〜汎化癖をやめる〜

汎化とは

みなさん「汎化」という言葉をご存知でしょうか?

多分聞きなれない言葉だと思うんですが。

汎化とは、個別の事象から共通点を見つけ、法則を当てはめたり、ひとつにまとめたりする事です。

よくわからないよって人のために例を挙げてみましょう。

「柴犬」、「チワワ」、「ブルドッグ」という個別の事象を「犬」というひとつの事象にまとめることを汎化と言います。

その逆の操作を特化といいます。

図にまとめるとこんな感じ。

僕がこの言葉を知ったのは「オブジェクト指向」という大学の講義でのことでした。つまり、汎化や特化という言葉はITの世界で使われる専門用語なのですが、心理学の世界でも使われる言葉らしいです。

じゃあ、これが幸せに生きるのとどういう関係があるの?と思われる方も多いと思うので、以下で説明していこうと思います。

汎化が可能性をなくす

みなさんこんな経験はありませんか?

「サッカー」が上手なA君に対して、A君は「運動」が得意だと言ったり

「数学」が得意なB君に対して、B君は「勉強」が得意だと言ったり。

逆に

「走る」のが遅いだけなのに、「運動」が苦手だと言ってみたり。

今まで、意識してなかったけど言われてみたらよくやってるわっていう人も多いと思います。

この汎化なんですが、ポジティブな面で使う分には気にする必要はないかなと思うんですが、ネガティブな場面で使うと可能性をどんどん縮めていく危険性があります。

例えば、

体育の授業でサッカーをして、うまくできなかったという経験から、自分は運動が苦手なんだと思い込む。

そして、野球やバスケなどサッカー以外の競技、いわゆる「運動」に取り組まなくなる。

というようなことが起こり得ますね。

もしかすると、この人に野球の才能があったかもしれないのに、「サッカーが苦手」だという経験を「運動が苦手」だと汎化してしまったためにその才能に気づかないかもしれません。

これってすこぐもったいないですよね。

サッカー元日本代表で国民栄誉賞を受賞した澤さんもあんなにサッカーが上手なのにリズム運動やダンスはめちゃくちゃ苦手らしいです。

他の例で考えていきましょう。

汎化についての実験で赤ちゃんが白いネズミに触ろうとすると大きな音が鳴るようにするというものがあり、そこでびっくりした赤ちゃんは白いネズミだけでなく白いウサギも触れなくなり、次第に白いものが触れなくなるそうです。

似たようなもので、

プレゼンのとき、たまたま予想外のことが起きたためにパニックになり失敗してしまったという経験から汎化を起こし、プレゼンがだめだと思い込み、次第に人前に立つのがだめになり対人恐怖症になったり。

など、汎化は無意識のうちに行われるため厄介なものです。

幸せに生きるコツ

ここからは、汎化の癖をやめて幸せに生きるコツを紹介したいと思います。

常に「いま、ここ」を意識し、目の前のことに集中しよう!

僕らに汎化の癖がついてしまっている要因のひとつに日本の教育制度があると思います。

日本の義務教育では、苦手なものをなくし全てを満遍なくできることが重要視されますよね。義務教育における「勉強ができる子」というのは、国語、算数、理科、社会と全て満遍なくできる子であり、そういう子が優等生として扱われます。逆に「理科だけめっちゃ得意で他は全然だめな子」とかは義務教育においては勉強ができない子として扱われます。

幼少期にこの価値観の中で育ったため、汎化の癖がついてしまうのは仕方ないのかなと思います。

もし、だめな方へだめな方へと汎化を起こし可能性を縮めてしまっているのであれば、常に「いま、ここ」に集中するよう努めてください。

「いま、ここ」に集中するとは、過去に起こったこと、これから起こるであろう未来を無にして、今やるべきことに全てを注ぎ込むということです。

過去に起こったことはどれだけ考えても変わりません。未来に起こることはどれだけ考えてもわかりません。だからこそ「いま、ここ」が大事です。

ニーバーの祈りというものをご存知でしょうか?

神よ、

変えることのできるものについて、

それを変えるだけの勇気をわれらに与えたまえ。

変えることのできないものについては、

それを受けいれるだけの冷静さを与えたまえ。

そして、

変えることのできるものと、変えることのできないものとを、

識別する知恵を与えたまえ。


ラインホールド・ニーバー(大木英夫 訳)


過去は変えることができません。現在は変えられます。未来を変えるには現在を変えるしかありません。

だからこそ「いま、ここ」なんです。

「いま、ここ」に集中していれば、自ずと「個別の事象」に目がいくことになります。そして汎化を起こしていれば自然に気づくようになるでしょう。

あなたが今できないとか苦手だと思っていることは、本当に「それ」が苦手ですか?

実は、汎化により苦手だと思い込み、自ら可能性をなくしていっているのかもしれませんよ。


■「いま、ここ」について詳しく知りたい方におすすめ

脱毛日記7日目

脱毛をはじめてから7日が経過しました。

それでは、脱毛後7日の現在の状態の写真を見ていただきましょう。

正面

sune_07_center

側面左

sune_07_left

側面右

sune_07_right

写真でもわかるくらい毛が伸びてきましたね。相変わらず毛が抜けているという感じもなく、ただ剃って、そのあと伸びてるっていう感じです。

前回書いた毛が擦れる感覚についてですが、慣れたのか既に気にならなくなってます。

そして、新たに気付いたことがあるのですが、夏になり半ズボンを履いている人が多くなりましたが、他の人の足とか見てしまうようになりました。

あの人、全然毛生えてないけど、剃ったり脱毛したりしてんのかな?

とか

あの人、すね毛生え過ぎてて、ちょっと汚いなあ

とか思いながら見てしまいますね。女の人が短パンの男の人をみて、すね毛が気になるという意味がわかりました。

次回は10日目の記事でお会いしましょう。

正直脱毛日記って書くことがないから、1週間か2週間くらいをまとめて一つの記事にしようかな


記事内で使用しているものはこちら

【初心者向け】情報学部生と学ぶC言語 [1限目:変数と標準入出力]

前回の復習

前回はprintfをつかってHello World!という文字の出力を行いました。

しかし、printfで出力出来るのは文字だけではありません。プログラムの中で計算してその数値を出力するなんて事もできます。

ということで、今回は数値の出力から取り扱っていきます。

数値の出力

23+47を計算して出力するプログラムを作りましょう。以下のソースコードを見てください。

/******
filename:constant.c
*******/

#include<stdio.h>
int main(void)
{
	printf("%d\n",23+47);

	return 0;
}
■実行結果
70

コードの説明

%d

dはdecimal(10進数という意味です)の頭文字で、「以下の実引数を10進数で表示しでください」という書式の指定を行なっています。コードでいえば23+47が対象の実引数となります。

変数

変数というのは、文字や数字などの値を格納する箱のようなものです。aという箱に10という数字を入れるというようなイメージです。箱という表現はプログラミングにおいて、しばしば使われる表現です。

以下のプログラムは先程の計算を一度変数に代入して出力するプログラムです。

/*******
filename:variable.c
*******/

#include<stdio.h>
int main(void)
{
	int a=23;
	int b=47;
	int sum=a+b;
	
	printf("%d\n",sum);
	
	return 0;
}

 

■実行結果
70

コードの説明

int a=23

intというのは整数を意味します。ですからint aというのは変数aは整数の型ですよという宣言になります。他にも様々な型があります。

 
型名とその意味
型名 意味
int 整数型
double 浮動小数点数型(8バイト)
float 浮動小数点数型(4バイト)
char 文字型
void 型なし

また、a=23というのは変数aを23という値で初期化するということを意味します。

変数は宣言された時点である値が割り当てられます。そのままでは計算出来ないので最初に初期化してあげる必要があります。

またa=23というのは、変数aに23を代入するということを意味します。数学のようにaと23が等しいという意味ではありません。

プログラミングでは=で結んだ時、右の値を左の変数に代入するということを意味します。ですからプログラミングではa=bとb=aでは全く違うということに注意しましょう!

前回の復習part2

コードを書いていく上で最初に記述する呪文がありましたよね?

えーと。#include<stdio.h>だっけ?

そうです!ではstdioとはなんの略ですか?

standard input/output だから標準入出力だ!

さすがですね!完璧です。

stdioが標準入出力ならば出力があれば入力もあるはず。

ということで、入力について学習しましょう。

入力にはscanfを使おう!

今回はキーボードから数値を入力し、その値を使って計算して出力するプログラムを作成します。

以下のソースコードをみてください。

/*****
filename:input.c
*****/

#include<stdio.h>
int main(void)
{
	int a=0;
	int b=0;
	
	printf("一つ目の値は?:");
	scanf("%d", &a);
	
	printf("二つ目の値は?:");
	scanf("%d", &b);
	
	printf("%d + %d = %d\n", a, b, a+b);
	
	return 0;
}

 

■実行結果[例]
一つ目の値は?:23
二つ目の値は?:47
23 + 47 = 70

コードの説明

scanf

キーボードからの入力をコンピュータが待つときに使われる命令です。キーボードから入力される値は、「,」以下の変数に格納されます。その際、&をつけることに注意しましょう。

今回のプログラムでは、scanf(“%d”,&a)となっているので、「aという変数にキーボードから入力された10進数の値を格納する」という命令になります。


次回は、今回少し触れた型について、整数型以外にも触れていきましょう。

C言語学習におすすめのテキストはこちら