C言語 - Part.3:条件分岐・繰り返し

Part.3 では前回説明できなかった scanf関数, キャスト演算子条件分岐, 繰り返し処理 について解説して行きたいと思います。

scanf関数

scanf関数とは、printf関数と同じように stdio.h に定義されている標準入力系の関数です。この関数が書かれた行までプログラムが来ると、キーボードからの入力待ち状態になります。scanf関数の使い方は以下のようになります。

scanf("変換指定子", &変数名);

変換指定子とは、Part. 1で紹介した printf関数 に使う書式と同じです。

書式 対応する型 意味 使い方
%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"

つまりこういうこと。

#include <stdio.h>

int main (void)
{
  int a;
  float b;
  double c;
  
  scanf("%d", &a);
  scanf("%f", &b);
  scanf("%lf", &c);
  printf("%d, %f, %lf\n", a, b, c);
  return 0;
}

実行時、入力する時にはこうなります

1 (Enter)
2 (Enter)
3.4 (Enter)
1, 2.000000, 3.400000

また、scanf では一度に複数入力させることができます。上のプログラムを簡単にしてみると...

#include <stdio.h>

int main (void)
{
  int a;
  float b;
  double c;

  scanf("%d, %f, %lf", &a, &b, &c);
  printf("%d, %f, %lf\n", a, b, c);
  return 0;
}

こうした場合、キーボードで入力するときには以下のように入力しなければなりません。

1, 2, 3.4 (Enter)
1, 2.000000, 3.400000

ようは、scanf関数の第1引数に書いた書き方通りで入力しなければいけません。書式文字列に変換指定以外の文字を書くと,その文字まで正確に入力しなくてはならないということです。以下のように書いたとすると

scanf("%d : %f : %lf", &a, &b, &c);

このように入力しないと、正常に変数へ値が代入されません。

1 : 2 : 3.4 (Enter)

また、配列(文字列)を入力する際には、このように書きます。

char str[128]; 
scanf("%s", str);

変数名に & の記号は必要ありません。これの意味は、後々書くと思う ポインタ のところで解説しますが、気になる方は調べてみてください。

ただし、変数の要素にデータを入力する場合には以下のようになります。

char str[128];
scanf("%c", &str[0]); // strの0番目に1文字入力する

型変換とは

型変換によって、異なる変数の型を同一演算上で用いることが許されます。

暗黙の型変換

コンパイラが自動的に無難な型変換を行うものです。

代入時の変換

代入時に左辺と右辺の型が異なっている場合、左辺の型に変換します。

式中の変換

演算の中に型の違う変数が混在した状態で行われる演算は、精度の高い型に統一されます。一般的な型における精度は以下のようになっていて、左から右に行くにつれて精度が上がって行きます。

char → int → long → float → double

明示的型変換(キャスト)

強制的に別の型に変換したいときに使ったりします(整数を小数として扱うみたいな)

例えば、下の演算プログラム

int a = 3;
int b = 2;
double c = a / b;

c に代入されるのは何だと思いますか?...。1.5 ではないですよ??

実は、c には 1.0 が入っています。その原因は a / b の精度です。それぞれの型は int 型です。つまり整数です。よって計算された結果も整数型として保持されるため整数になります。

一般的に計算すれば 1.5 になりますが、これはプログラム上は実数型です。そのため整数型として保持するために小数部は無かったことになり 1.0 として保持されてしまうのです。

これを回避するために用いるのが キャスト と呼ばれるものです。c に 1.5 を入れるためには以下のようにします。

int a = 3;
int b = 2;
double c = (double)a / b;

こうすることで、a は演算時のみ double型 として演算しろ。という命令になり、演算結果も精度を合わせるため double型 になり 1.5 という結果を得ることができるようになるのです。

さて、ここからが Part.3 の本題である 条件分岐繰り返し になります。

条件分岐

プログラムを組む上で、条件によって異なった処理を行う必要がある場面が必ず出てきます。条件に応じて行う処理を変える処理を『分岐処理』と呼びます。

この分岐処理を行うために、C言語には if(イフ) と最近では(僕自身が)あまり使いませんが switch(スイッチ) という命令があります

if(if ~ else if ~ else)

『if』とは英文にもある通り、もし〜ならばという意味です。つまり もし〜だったら、...をしろ というようにプログラムを組むことができます。

#include <stdio.h>

int main (void)
{
  int a;
  printf("数字を入力してください:");
  scanf("%d", &a);
  if ( a > 0 )
  {
    printf("正の数です\n");
  }

  return 0;

また『else』を使うことで条件に当てはまらなかった場合の処理を記述することができます。さらには『else if』で、前述の条件に当てはまらなかった場合、次の条件を定義することの可能です。

例として以下の文をプログラムで考えるとする。

『もし a が 0より大きければ、正の数と表示する。でなければもし a が 0より小さければ、負の数と表示する。どれでもなければ、数ではないと表示する』

するとこうなる

#include <stdio.h>

int main (void)
{
  int a;
  printf("数字を入力してください:");
  scanf("%d", &a);
  if ( a > 0 )  // もし a が 0より大きければ
  {
    printf("正の数\n");  // 正の数と表示する
  }
  else if ( a < 0 )  // でなければ、もし a が 0より小さければ
  {
    printf("負の数\n");  // 負の数と表示する
  }
  else  // どれでもなければ
  {
    printf("数ではない\n");  // 数でないと表示する
  }

  return 0;
}
数字を入力してください:1
正の数

数字を入力してください:-3
負の数

数字を入力してください:a
数ではない

Paiza.IO では動作したけど、一応文字も数になるし、よく分からない値になっても数値は数値だから else 入らないかも。コンパイラとか環境によっては。

まぁ、概念はこんな感じということです。

switch

感じとしては if と同じですが、記述方法が異なり、場合によっては switch文 の方が簡単にかけたりします。構文はこんな感じですが、『default』というのは、どの case にも当てはまらなかった場合って意味です。

switch (式 または 値 または 変数)
{
  case 定数式1 または 定数値1:
    処理1;
    break;
  case 定数式2 または 定数値2:
    処理2;
    break;
    :
    :
  case 定数式n または 定数値n:
    処理n;
    break;
  default:
    処理;
    break;
}

例えば...

『1~3が入力されたら『入力された数値は1~3です』、4~6が入力されたら『入力された数値は4~6』を表示させる。

というのを if で書くと、前のPartでも記述した 論理演算子の論理和 を用います

#include <stdio.h>

int main (void)
{
  int a;
  scanf("%d", &a);
  
  if ( ( a == 1 ) || ( a == 2 ) || ( a == 3 ) )
  {
    printf("入力された数値は1~3です\n");
  }
  else if ( ( a == 4 ) || ( a == 5 ) || ( a == 6 ) )
  {
    printf("入力された数値は4~6です\n");
  }

  return 0;
}

で、switch を使うと

#include <stdio.h>

int main (void)
{
  int a;
  scanf("%d", &a);
  switch( a )
  {
    case 1:
    case 2:
    case 3:
      printf("入力された数値は1~3です\n");
      break;
    case 4:
    case 5:
    case 6:
      printf("入力された数値は4~6です\n");
      break;
  }
  
  return 0;
}

繰り返し

『1 ~ 10を足した結果を表示してください』と言われたらどうしますか?

#include <stdio.h>

int main (void)
{
  int sum = 0;
  sum = sum + 1;
  sum = sum + 2;
  sum = sum + 3;
  sum = sum + 4;
  sum = sum + 5;
  sum = sum + 6;
  sum = sum + 7;
  sum = sum + 8;
  sum = sum + 9;
  sum = sum + 10;
  printf("%d\n", sum);

  return 0;
}

こんな風に書きますか?じゃあ、1 ~ 100だとどうでしょう。
これを100個書きますか?無理ですよね?笑

このように、同じ処理をある回数繰り返すような処理を 繰り返し処理 といい、『for文』を使って記述します。構文は以下のように

for ( 初期化; 条件式; 変化式 )
{
  実行する処理;
}

つまり...

#include <stdio.h>

int main (void)
{
  for ( int i = 1; i <= 10; i++ )
  {
    printf("%d回目です\n", i);
  }
}

このときの i++ は『後置インクリメント』と呼ばれ『i = i + 1』と同義です。

Q3: 条件分岐と繰り返し

Q3-1

以下のように入力されたとき、3つの値の和を求めるプログラムを組んでください。ただし、入力される記述は変更しないようにしてください。

1@2@3

Q3-2

以下のプログラムは正常に動作しません。正常に動作するように2ヶ所修正してください。
※ 修正する場所は2ヶ所です。

#include <stdio.h>

int main (void)
{
  double res;
  int a, b;
  scanf("%d, %d", &a, &b);

 res = a / b;
 printf("%d\n", res);
}

Q3-3

入力された、西暦がうるう年か判定するプログラムを組んでください。うるう年とは以下の条件を満たす西暦です。

  1. 4で割り切れる
  2. ただし、100で割り切れる場合は、うるう年ではない
  3. しかし、400で割り切れる場合はうるう年である。

Q3-4

以下の文章を満たすプログラムを switch文 を使って書いてください。

『お肉を100g単位で購入するとして、100 ~ 300gなら400円、400 ~ 600gなら700円、それ以外の重さなら1000円と表示する』

まとめ

今回はプログラムを書く上で必ず使うであろう 『if』『for』について解説しました。次回は何について解説するか未定です。

おたのしみに





A3: 条件分岐と繰り返し

A3-1

#include <stdio.h>

int main (void)
{
  int a, b, c;
  scanf("%d@%d@%d", &a, &b, &c);
  printf("%d\n", a + b + c);
  return 0; 
}

A3-2

#include <stdio.h>

int main (void)
{
  double res;
  int a, b;
  scanf("%d, %d", &a, &b);

 // res = a / b;
 res = (double) a / b;    // 型キャストしましょう。int / int は小数計算できません。
 // printf("%d\n", res);
  printf("%lf\n", res);    // res は double型なので %lf です。
  return 0;
}

A3-3

#include <stdio.h>

int main (void)
{
  int year;
  scanf("%d", &year);

  if ( year % 400 == 0 )
  {
    printf("うるう年\n");
  }
  else if ( year % 100 == 0 )
  {
    printf("うるう年ではない\n");
  }
  else if ( year % 4 == 0 )
  {
    printf("うるう年\n");
  }
  else
  {
    printf("うるう年ではない\n");
  }

  return 0; 
}

A3-4

#include <stdio.h>

int main (void)
{
  int meat;
  scanf("%d", &meat);
  switch( meat )
  {
    case 100:
    case 200:
    case 300:
      printf("400円\n");
      break;
    case 400:
    case 500:
    case 600:
      printf("700円\n");
      break;
   default:
      printf("1000円\n");
      break;
  }
  return 0; 
}

f:id:nomunomu0504:20190411151221p:plain:w0