第 1 回 復習

本日の内容


このドキュメントは http://edu.net.c.dendai.ac.jp/ 上で公開されています。

1-1. この講義について

この講義では C 言語を使って、データ構造とアルゴリズムについ て学びます。

1-2. Visual C++ について

本講義では簡単のため、主にコンソールアプリケーションを作ります。 Visual Studio .NET C++ では次のようにします。

  1. まず Visual Studio .NET 2003 を立ち上げます。 「スタート」→「すべてのプログラム」→「プログラミング」→「Microsoft Visual Studio .NET 2003」→「Microsoft Visual Studio .NET 2003」で起動 します。
  2. 一つの実行可能なプログラムを作るために、プロジェクトを次のように毎 回用意します。
  3. 「ファイル」→「新規作成」→「プロジェクト」
  4. 「新しいプロジェクト」ダイアログで、プロジェクトの種類は「Visual C++ プロジェクト」を選び、テンプレートは一番下にある「空のプロジェクト (.NET)」を選びます。 プロジェクト名は適当につけて下さい。 場所は「参照」を選び「デスクトップ」→「マイコンピュータ」→「D:」を使 用して下さい。 H: では正常に動作しません(20040916)。
  5. OK を選びます。
  6. もし、ソリューションエクスプローラが表示されてなければ、「表示」→ 「ソリューションエクスプローラ」でソリューションエクスプローラを表示さ せておきます。
  7. ソリューションエクスプローラ中の「ソースファイル」を右クリックして、 出てきたメニューに対して、「追加」→「新しい項目の追加」を選びます。
  8. 出てきた「新しい項目の追加」ダイアログで、テンプレートで「C++ ファ イル」を指定し、ファイル名に「hello.c」など作成したい C 言語のファイル 名をそのまま入れます。
  9. 画面にそのファイルの入力欄が出てきたらプログラムを書き込みます。
  10. 「プロジェクト」→「○○(プロジェクト名)のプロパティ」でプロパティ ページを開き、次のように設定します。
  11. プログラムの入力が終ったら、「ビルド」→「ソリューションのビルド」 でコンパイルし実行ファイルを作ります。
  12. 「デバッグ」→「デバッグなしで開始」でプログラムを実行します。

演習1-1

次のプログラムを実行させなさい。

#include <stdio.h>
main(){
  printf("Hello World\n");
}

1-3. C 言語の基礎

プログラムの全体の構造

C 言語のプログラムは最後が「.c」で終るテキストファイルに書きます。

構造1

#include <stdio.h>
main(){
  ここに文を書く
}

構造2

#include <stdio.h>
#include <math.h>
main(){
  ここに文を書く
}

構造 2 は平方根 sqrt() や三角関数 sin() など数学的な関数を使用する時だ け使い、通常は構造 1 を使います。

文はセミコロン「;」で区切ります。

またプログラムの任意の場所に /* で始まり */ で終るコメントを書くことが できます。

プログラムの組み立て

プログラムは宣言をするところと、手順を記述するところにわけることができ ます。

構造3

#include <stdio.h>
main(){
  宣言

  手順
}

宣言

宣言とは変数の登録をすることです。 変数には型と名前があります。 型は文字型 char、整数型 int、単精度浮動小数点型 float、倍精度浮動小数 点型 double があります。 名前は英字で始まる任意の英数字の列を使用できます。


int i,j;
float kotae1,kotae2;
char a,b,c;

また、通常の変数の他に配列変数を扱うこともできます。 これは、数学で扱う数列 a0, a1 のように、添字の番 号を指定して a[0], a[1] のように値を呼び出すことができます。 宣言する時は使用する数を与える必要があります。 但し、添字は 0 から始まりますので、5 個の配列を宣言した時、使用できる 添字は 0,1,2,3,4 になります。 手続き中の配列変数の添字には整数型の変数を使用することもできます。


int x[3]; /* 使用できる変数名は x[0], x[1], x[2] */
char word[2]; /* 使用できる変数名は word[0], word[1] */

宣言では変数の最初の値(初期値)を与えることができます。 文字型とは文字一文字のことで、文字型の定数を表すにはシングルクォーテー ションマーク「' '」で括ります。 なお、改行記号は '\n' で表します。 配列変数では 0 番目の値から順に { } の中にカンマで区切って与えることが できます。{ } で値を与える場合、使用する配列の数を与えなくても良いです。


int i=0;
char a='x', b='\n';
float y[2]={1.3 , 3.5}; /* y[0]=1.3, y[1]=3.5 */
int k[]={3, 2, 1}; /* k[0]=3, k[1]=2, k[2]=1 */

文字型の配列変数は文字列を使用するのに使うことができます。 その場合、文字列の最後に必ず特別な文字 '\0' を入れる必要があります。 また、文字型の配列変数の初期化には上記のような { } を使用する代わりに、 文字列を " " で括る方法もあります。この場合最後に自動的に '\0' が割り 当てられます。


char x[]="abc" /* x[0]='a', x[1]='b', x[2]='c', x[3]='\0' */

手順

本講義では手順として次のものを取り上げます。

  1. 代入文
  2. printf
  3. if
  4. while

代入文

代入文は「変数名 = 式」という形式で書き、式の値が変数に入ります。 ですから、「 i = i+1 」という代入文では i+1 の値が i に入りますから、 i の値が 1 増えます。 式には通常の四則演算の他、数学関数も使用できます。 但し、演算の優先順位を与えるカッコは丸カッコ ( ) しか使用できません。 また、変数を含む式は変数の型が考慮されます。整数型の変数 a,b にそれぞ れ 7,2 が入っていた時、 a/b の結果は整数型に直され、3 になります。 なお、 a を b で割った余りを求めるには a % b と書きます。


a = ((1+2)*3+4)*5;
x[2] = sqrt(y[1]);

C 言語ではあらゆるものが値を持ちます。代入文自体も代入された値を値とし て持つので、次のような記法が可能になります。


i=j=0;

C 言語独特の記法として代入演算子やインクリメント、デクリメントがありま す。代入演算子「変数 += 式」は式の値だけ左辺の変数を増やすという意味に なります。また、インクリメント、デクリメントは i++, --i などで、それぞ れ i が 1 ずつ増減します。但し、++, -- が先頭に来る場合の式の値は増え た後の値になりますが、後に来る場合は式の値は増える前の値になります。


s+=a[i];
z[i++]=y[j++];

printf

標準出力に文字を出力するのが printf です。指定した文字を出力するだけで なく、変数の内容も表示できます。 printf の最初の引数は文字列で、基本的にはその内容が表示されます。


printf("Hello World\n");

文字列の中に 「%+文字」 が含まれると、その位置に変数の値が表示されます。 文字型変数には %c, 整数型変数には %d, 浮動小数点型には(float も double も) %f を使用します。


char x='a';
int y=5;
float z=6.2;
printf("変数 x の値は %c",x);
printf("変数 y の値は %d, 変数 z の値は %f",y,z);

文字型の配列変数の内容を全て表示するには %s を使用します。 但し、配列の最後には '\0' が割り当てられている必要があります。


char x[]="abc"; /* x[0]='a', x[1]='b', x[2]='c', x[3]='\0' */
printf("配列変数 x には文字列 %s が入っている",x);

if

if 文には次の二つの構文があります。


if(条件){文1;}
if(条件){文2;}else{文3;}

始めの構文は条件が成立する時(0 でない時)だけ文1を実行し、成立しなかっ た時(0 だった時)はなにもしません。 二番目の構文は条件が成立する時(0 でない時)は文2を実行し、成立しなかっ た時(0 だった時)は文3を実行します。

条件式

二つの値を比較をする条件式には次の書き方があります。

a == b
a と b は等しい
a != b
a と b は等しくない
a < b
a は b より小さい
a > b
a は b より大きい
a <= b
a は b 以下
a >= b
a は b 以上

これらの値は条件が成立すれば 1、成立しなければ 0 になります。


if(x>max){max=x;}

if(b==0){printf("全ての値\n");}
else{printf("解なし\n");}

二つの条件式を一つにまとめるため次の書き方があります。

(A) && (B)
A と B の両方が成り立つ(両方が 0 でない)
(A)||(B)
A か B のどちらかが成り立つ(どちらかが 0 でない)
!(A)
A が成り立たない(A が 0 である)

if((a==0)&&(b!=0)){printf("解なし");}
if((a!=0)||(b!=0)){x=-b/a;}

while

while 文の構文は if と良く似ています。


while(条件){文;}

「条件を調べて、成立すれば文を実行する」というのを繰り返します。 適切な回数だけ繰り返させるためには何らかのアルゴリズムが必要になります。

なお、for 文は while 文を読みやすくするために導入された別の書き方です。 次の for と while は同じ意味になります。


for(A;B;C){
  D;
}


A;
while(B){
  D;
  C;
}

#define

#define を使用すると、定数を使用することができます(実際はマクロの定義)。 次のように使用します。


#include <stdio.h>
#define N 3
main(){
  int x[N]={7, 3, 4};
  int i;

  for(i=0;i<N;++i){
    printf("%d\n",x[i]);
  }
}

1-4. プログラム例

  1. 
    #include <stdio.h>
    main(){
      printf("Hello World!\n");
    }
    
  2. 
    #include <stdio.h>
    main(){
      int a=1;
      float b=3.14;
      char c='a';
      char d[]="bcdef";
      printf("%d %f %c %s\n",a,b,c,d);
    }
    
  3. 
    #include <stdio.h>
    #include <math.h>
    main(){
      float a=2,b=3,c=1;
      float d,x1,x2;
      printf("%f x^2 + %f x + %f = 0 の解は",a,b,c);
      d=b*b-4*a*c;
      if(d>0){
        x1=(-b+sqrt(d))/2/a;
        x2=(-b-sqrt(d))/2/a;
        printf("%f , %f \n",x1,x2);
      }else if(d==0){
        x1=-b/2/a;
        printf("%f\n",x1);
      }else{
        x1=-b/2/a;
        x2=sqrt(-d)/2/a;
        printf("%f±%f\n",x1,x2);
      }
    }
    
  4. 
    #include <stdio.h>
    #define N 10
    main(){
      int i,j;
      for(i=0;i<N;i++){
        for(j=0;j<N;j++){
          printf("○");
        }
        printf("\n");
      }
    }
    

演習1-2

上のプログラム例 4 を改造して次を表示するプログラムを作りなさい。

  1. ○○○○○
    ○○○○
    ○○○
    ○○
    ○
    
  2.       ○
        ○○○
      ○○○○○
    ○○○○○○○
    
  3. ○○○○○
    ○      ○
    ○      ○
    ○      ○
    ○○○○○
    

1-5. C++との対比

Hello World

C++ ではファイル名の最後に .cpp, .cxx, .C などを付けます。 また、ANSI C 以降、C++ では main 関数も int で宣言し、return で戻り値 を指定します。

C++ では画面に表示させるには std::cout オブジェクトに対して << 演算子で表示したいものを指定します。 また、改行は std::endl です。 これらは iostream を include で指定します。 つまり Hello World を表示させる C++ 次のプログラムは次のようになります。

#include <iostream>
int main(void){
  std::cout << "Hello World"
            << std::endl;
  return 0;
}

名前空間

C++ では大規模な開発の中で、個々に関数名や変数名が衝突しないようにする ため名前空間を使うことができます。 これは言わば関数や変数に名字を与えるようなものです。 一つのグループが一つの名前空間を管理することにより、管理責任を分散せず に関数名、変数名を管理できます。


namespace sakamoto {
  int i;
  double f(double x);
  class C {
    C* create(); 
  };
}

また namespace でプロトタイプを定義した場合、 namespace 外でスコープ演算子 :: を用いて定義できます。


double sakamoto::f(doube x){
  return 1.2;
}
sakamoto::C* sakamoto::C::create(){
  return new sakamoto::C();
}

このように定義すると他で定義された変数 i や関数 f(x) やクラス C と分け ることができます。 実際に使う際には次のようにします。

スコープ演算子を使用

int main(){
  sakamoto::C x;
  x.show();
  return 0;
}
using を使って、使用する名前を登録

using sakamoto::C;
int main(){
  C x;
  x.show();
  return 0;
}
using を使って、名前空間を登録

using namespace sakamoto;
int main(){
  C x;
  x.show();
  return 0;
}

このうち最後の名前空間を登録する方法は簡便ですが、名前の衝突を避けると いう本来の名前空間の目的に反しているので推奨できません。

なお、C++ はもともとは名前空間を持たず、途中から導入されました。 名前空間を持たなかった頃のヘッダファイルには C 言語同様に .h の拡張子 が付いていました。 ですから、iostream.h は名前空間が定義されていません。 一方 iostream と .h の付かないヘッダファイルには std という名前空間が 定義されています。 従って、例えば iostream を使って標準出力に値を出力するには次のようにし ます。

  1. 
    #include <iostream>
    int main(){
      std::cout << "Hello World!" << std::endl;
      return 0;
    }
    
  2. 
    #include <iostream>
    using std::cout;
    using std::endl;
    int main(){
      cout << "Hello World!" << endl;
      return 0;
    }
    
  3. 
    #include <iostream>
    using namespace std;
    int main(){
      cout << "Hello World!" << endl;
      return 0;
    }
    

C++ 言語の基礎

C++ 言語は C 言語の拡張という位置づけで開発されたため、 C 言語のプログ ラムそのものもほとんど C++ コンパイラでコンパイルできます。 多くは機能を追加されたもので、変更されたものはごくわずかです。

プログラム全体の構造

main 関数は常に int で宣言する必要があり、また必ずプログラムの最後に return で整数値を返す必要があります。 int で宣言しなかったり、 return で整数値を返してないとコンパイラから警 告を受けます。

なお、プログラムの全体構造として #includeなどがあるのは C 言語と 同じです。 但し、名前空間の導入とともにシステム関連のヘッダファイルから .h が取れ、 std という名前空間に入れられました。 もし C 言語の printf が使いたい場合、stdio.h の代わりに cstdio を include し、 std::printf をお使い下さい。


#include <cstdio>
int main(){
  std::printf("Hello World!\n");
  return 0;
}

但し、画面に改行文字を書くことと std::endl を送ることは厳密に意味が違 うので、 C++ では std::printf はあまり使わない方が良いです。

プログラムの組み立て

(ANSI) C 言語と C++ で大きく違うことは、 C++ では変数宣言がどこでもで きるようになったということです。 それを利用して、変数は必要な部分で宣言するようにした方がプログラムが見 やすくなります。


#include <iostream>
int main(){
  int sum=0;
  for(int i=1; i<=10; i++){
    sum+=i;
  }
  std::cout << sum << std::endl;
  return 0;
}

printf と std::cout

std::cout は画面に出力するためのオブジェクトで演算子 << がオーバー ライドされ、演算子直後のものを出力します。 演算子直後に int, char, string など様々なものを置いても自動的に出力 されます。 また複数のものを出力する時はすべて << でつなげればつながって出力 されます。 上に書いたように std::endl は改行の他に実際に文字の出力始めるという意 味があるので、単なる改行である '\n' を送るのとは意味が違ってきます。

#define

プログラム例


坂本直志 <sakamoto@c.dendai.ac.jp>
東京電機大学工学部情報通信工学科