C言語で情報オリンピック Day3

はじめてのCプログラム

コンピュータの世界(せかい)には、色々な言語(げんご)が存在します。
たとえば

C(シー)
C++(シープラプラ)
Java(ジャバー)
Javascript(ジャバースクリプト)
Ruby(ルビー)
Python(パイソン)

などの言語がありますが、この授業(じゅぎょう)ではC言語とC++言語だけをつかいます。

オンラインエディタを使ってはじめてのCプログラムを書き、実行(じっこう)してみましょう。まずソースコードの作成〜実行までの動画を見てみましょう。

このプログラムに #include int mainなどいろいろありますが、これらはideoneが自動(じどう)てきに書いてくれましたので、実際(じっさい)に書いてもらったのは一行だけです。(書く場所は { の後ろと return のあいだになります)

printf("こんにちは\n");

printfというはC言語では関数(かんすう)といいます。コマンドだと認識(にんしき)してもだいじょうぶです。ようはパソコンに指示(しじ)をだす魔法(まほう)のことばです。

ダブルクォーテーション(")に囲(かこ)まれているのは文字列(もじれつ)といいます。最後のセミクロン(;)は区切り(くぎり)といいます。複数のコマンドがあれば、コマンドとコマンドの間(あいだ)に必ず区切りを入れます。

\nは特殊の符号(ふごう)です。改行(かいぎょう)符(ふ)といいます。これがなかったら改行されません。以下のサンプルを見てみましょう。

printf("こんにちは");
printf("はじめまして");

この2行を実行したらどうなりますか。

こんにちははじめまして

が出力されます。\nをいれますと

printf("こんにちは\n");
printf("こんにちは\n");

今度(こんど)は

こんにちは
はじめまして

が出力されます。

問題1:動画を参考に

あいうえお 
かきくけこ

を出力するプログラムを作成しましょう。

整数型

コンピュータのべつの名前は計算機(けいさんき)といいます。当初(とうしょ)コンピュータの役割(やくわり)は主(おも)に計算につかわれていました。それでは、プログラムで如何(いか)に数学(すうがく)問題をとくかをみてみましょう。

例題 整数 a=90 と b=3 に対し、a+b、a-b、a✕b、a÷bを出力せよ。

プログラムをみてみましょう。

#include <stdio.h>
int main() {
  int a = 90, b = 3;
  printf("a+b=%d\na-b=%d\na✕b=%d\na÷b=%d\n", a+b, a-b, a*b, a/b);
  return 0;
}

プログラムを実行しますと、以下の結果がでました。

a+b=93
a-b=87
a✕b=270
a÷b=30

期待(きたい)とおりの結果でした。

aとbの値を変えてみて出力をたしかめましょう。

printf文は複雑になってましたね。この例題では、5つのパラメータ(あるいは引数ひきすうといいます)で構成されてます。1番目はフォーマット文字列(もじれつ)といいます。この文字列のなかに%dは整数型で、後ろの引数を代入しろといういみの特殊符号です。一番めの%dにa+bが代入(だいにゅう)され、二番目はa-bが代入され、三番目にa*b、四番目にa/bが代入されました。%dの数だけ、うしろに引数がつづきます。%d以外に %f(実数)や、%c(文字)、%s(文字列)などいろいろあります。

a=1、b=3のときはどうなりますか。

割り算 a/b の結果が0になりましたね。これはなぜでしょうか。C言語のなかに / 符号が割り算ですが、被除数(ひじょすう)が整数型intの場合は、結果が商(しょう)の整数部だけになります。(小数点以下は切り捨てになります)0.3の場合は0、1.7の場合は1、-1.8の場合は-1になります。

例題 整数型変数aとbの割り算の商と余りを出力せよ。

#include <stdio.h>
int main() {
  int a=108, b=38;
  printf("商: %d, 余り:%d\n", a/b, a%b);
}

%演算子(えんざんし)は a ÷ b の余りを計算してくれました。

これでC言語の算術(さんじゅつ)演算子(えんざんし)はすべて学(まな)ぶになりました。+ - * / % 5つになります。この5つの演算子には優先(ゆうせん)順位があります。* / %は同じ優先度で+ - より高い。

5 + 4 * 2 は 13、2 - 5 % 2 は1になります。

実数型

割り算で小数点以下の数字をもらいたい場合はどうしましょうか。実数であることをC言語に教えなければなりません。以下のプログラムを見ましょう。

#include <stdio.h>
int main() {
  float a = 1.0f;
  printf("%8.2f", a/3);
  return 0;
}

float a = 1.0f; 変数aを実数(じっすう)として宣言(せんげん)し、1.0の値を代入する。1.0fのfはこの数字が実数であることを意味します。そしてprintfの一番目の引数に、%dではなく、%fを使います。8.2fの意味は、ここに実数をつかい、最短8つのスペースを占(し)め、小数点後2桁を出力せよといういみです。

注意してほしいのは、%fをつかうときに、指定した小数点の桁数を超えた場合は、小数部分が四捨五入(ししゃごにゅう)になります。
printf("%.1f", 3.0/4)の出力結果が0.8になります。

論理(ろんり)演算子と比較(ひかく)演算子

論理とはなんでしょうか。

例えば「◯◯さんは男である」という論理式があります。これについてほんとうか嘘(うそ)か1つの結果しかありません。ほんとうの場合は真(しん, True)、うその場合は偽(ぎ, False)といいます。

C言語では1を使って真をあらわし、0で偽を表します。以下のプログラムを見てみましょう。

#include <stdio.h>
int main() {
  int a = 3, b = 5;
  printf("a<b : %d\n", a<b);
  printf("a<=b: %d\n", a<=b);
  printf("a>b: %d\n", a>b);
  printf("a>=b: %d\n", a>=b);
  printf("a==b: %d\n", a==b);
  printf("a!=b: %d\n", a!=b);
  return 0;
}

以下のような結果になりますので、なぜそうなるかを考えてみてください。

ここで使われた <、<=、>、>=、==、!=はC言語の比較演算子になります、その結果は1か0で論理値になります。

C言語の論理演算子は3つあります。&&、|| と ! です。

&&は論理積(ろんりせき、AND)といいます。数学では「かつ」という意味です。a && b は aとbがともに真の場合のみ結果が真になります。たとえば「円が丸い」&&「2が1より大きい」の結果が真で、「円が丸い」&&「1イコール2」の結果が偽であります。もちろん「三角が丸い」&&「1が2より大きい」の結果が偽である。C言語の0と1を使うと、こうなります: 1&&1は1、1 && 0は0、0 && 1は0、0 && 0 は0です。

|| は論理和(ろんりわ、OR)といいます。数学では「あるいは、または」という意味です。a || b は a または bが真の場合は結果が真であります。つまりどちらかが真であれば結果が真です。1 || 1 = 1, 1 || 0 = 1, 0 || 1 = 1, 0 || 0 = 0。逆に結果が偽であれば、a と bどちらも偽になります。

!は否定(ひてい、NOT)といいます。!a の結果はaの値を逆転することになります。真ならば偽、偽ならば真になります。たとえば「〇〇さんは男である」の!は「〇〇さんは男ではない」ということになります。

この3つの論理演算子を使って複雑(ふくざつ)な論理式を記述することができます。たとえば  !( ( a - b < c) && (b-c <=d) || a > b) のような式ですね。

C言語の中にif(条件判断文), while文で論理式を使うことになります。

例題 a=1, b=2, c=3と定義します。a+b*c と a-b/cの値を比較し、前者が大きい場合のみ1を出力せよ。

#include <stdio.h>
int main() {
  int a = 1, b = 2, c = 3;
  if (a+b*c > a-b/c)
    printf("1");
  return 0;

if 文は右側の( )内の論理式を判断し、真の場合はうしろの行を実行します。偽の場合はなにもしません。

例題 aとb2つの変数があります。大きい数と小さい数を出力せよ。
たとえばa=2, b=1の場合は、

Max: 2
Min: 1

と出力します。

#include <stdio.h>
int main() {
  int a = 10, b = 5;
  if (a > b) {
    printf("Max:%d\nMin:%d\n", a, b);
  } else {
    printf("Max:%d\nMin:%d\n", b, a);
  }
  return 0;
}

else文はif文の後ろになりますが、これはifの論理式が偽の場合のみ実行されます。{}はif と else の左右するコードを指定します。{}の中に複数の文を書くことができます。

このプログラムは? : という条件演算子(じょうけんえんざんし)、または三項演算子ともいいますが、によってif文を省略することができます。

#include <stdio.h>
int main() {
  int a = 10, b = 5;
  printf("Max:%d\nMin:%d\n", (a>b)?a:b, (a>b)?b:a);
  return 0;
}

三項演算子は (論理式)?(式1):(式2) という形をしていますが、論理式が真の場合は式1の値に、偽の場合は式2の値になります。

ループ

whileループ

C言語では繰り返しを表現するにはwhile や forループが用意されていました。まずサンプルを見てみましょう。

#include <stdio.h>
int main() {
  int i = 0;
  while (i<10) {
    printf("%d ", i);
    i = i + 1;
  }
  return 0;
}

0から9までの数字が出力されました。

while文後ろに論理式がありますが、これが真の場合のみ、{}なかの文がずっと(くりかえし)実行されます。上のサンプルでは、{}の部分が実行される度にiの値がプラス1になり、i=10になりますと、くりかしの条件 i < 10 が偽になってwhileループが終了します。

while (1) { } のようなループもありますが、これが終了しませんので、デッドループと呼びます。特殊な場合を除いて、デッドループにならないよう注意しましょう。

doループ

#include <stdio.h>
int main() {
  int i = 0;
  do {
     printf("%d ", i);
     i = i + 1;
  } while (i<10);
  return 0;
}

ほぼwhileループと同じですが、条件式がブロックの後ろに移動されました。

whileループとの決定的な違いはdoループのブロックが必ず一回実行されます。whileループは条件があわなければ一度も実行しない可能性がありますね。

forループ

上のwhileループのプログラムをforループで書き換えることができます。

#include <stdio.h>
int main() {
  int i;
  for (i=0; i<10; i++) {
    printf("%d ", i);
  }
  return 0;
}

forループは3つの部分で構成され、; で区切っていますね。i=0の部分は初期化(しょきか)条件といいます。forループのブロック({}の部分)を実行する前に一度だけ実行されます。i<10 は whileループと同じく終了条件です、これが真であるかぎり、ループが継続されます。i++はループのブロックが実行された後に実行されます。

for (;;) {}  と書いたらこれもデッドループですね。

breakとcontinue

3つのループの中にbreakとcontinueを書くことができます。breakは終了条件を無視しループから脱出(だっしゅつ)します。continueはブロック残りの部分を無視し次のループを回します。サンプルで動作を見てみましょう。

#include <stdio.h>
int main() {
 int i = 0;
 do {
  printf("%d ", i);
  if (i>5) break;
  i++;
    } while (i<10);
  return 0;
}

このサンプルでは 0 1 2 3 4 5 6 と出力します。breakによって、i==6のときにループが終了されました。

i++ は i = i + 1 の簡略な形です、i += 1も同じ機能がします。

#include <stdio.h>
int main() {
  int i;
  for (i=0; i<10; i++) {
    if (i%2==1) continue;
    printf("%d ", i);
  }
  return 0;
}

このプログラムは偶数(ぐうすう)だけを出力します:0 2 4 6 8 。つまりcontinue文によってうしろのprintf文が飛ばされました。

変数、if文、演算子、ループによって、我々(われわれ)はついにつよい武器を手にいれました。これらの組み合わせによって、強力(きょうりょく)なプログラムをつくることができます。いよいよJOIの問題を解くことも可能になります。

まずいくつか簡単なプログラムをつくりましょう。

問題 九九(くく)を出力せよ。

分析: a ✕ b の場合は、a が 1〜9 でループになってますし、 bも 1〜9でループしてますよね。このaとbをループでまわせばいい。

#include <stdio.h>
int main() {
  int a, b;
  for (a=1; a<=9; a++) {
    for (b=1; b<=9; b++)
      printf("%d ✕ %d = %d ", a, b, a*b);
    printf("\n");
  }
  return 0;
}

これでは1✕9と9✕1が両方出力されましたね。プリンターで印刷されたら紙の無駄遣いになりますので節約(せつやく)しましょう。1✕9と9✕1の場合は、1✕9だけ出力しましょう。つまり、a <= b だけの式を出せばよい。プログラムを修正します。

#include <stdio.h>
int main() {
  int a, b;
  for (a=1; a<=9; a++) {
    for (b=a; b<=9; b++)
      printf("%d ✕ %d = %d ", a, b, a*b);
    printf("\n");
  }
  return 0;
}

一文字を変えるだけで、すっきりしましたね。ちなみに、ループ中のループは二重ループといいます。

練習問題 
1)インドでは小学生が19✕19まで暗記するらしい。上のプログラムを修正し19✕19の九九を出力せよ。

2)長さNの四角形を出力せよ。たとえばN=5の場合以下の図形になります。

*****
*****
*****
*****

3)素数とは1と自分自分以外に約数を持たない数である。たとえば2, 3, 5, 7, 11, 13などがあります。10000以内のすべての素数を出力せよ。

4)長さNの三角形を出力せよ。たとえばN=5の場合以下の形になります。

*
**
***
****
*****

5)N/Mの分数を約分せよ。たとえば 2/6 = 1/3。39/26 = 3/2

次の動画をみて、アルゴリズムの重要性を認識せよ。

Day3 まとめ

出力関数 printf
整数型 int
実数型 float
変数
算術演算子 + - * / %
論理演算子 && || !
論理式
条件判断 if文
while, do, forループ

この記事が気に入ったらサポートをしてみませんか?