このドキュメントは http://edu.net.c.dendai.ac.jp/ 上で公開されています。
この講義では C 言語を使って、データ構造とアルゴリズムについ て学びます。
本講義では簡単のため、主にコンソールアプリケーションを作ります。 Visual Studio .NET C++ では次のようにします。
次のプログラムを実行させなさい。
#include <stdio.h> main(){ printf("Hello World\n"); }
C 言語のプログラムは最後が「.c」で終るテキストファイルに書きます。
#include <stdio.h>
main(){
ここに文を書く
}
#include <stdio.h>
#include <math.h>
main(){
ここに文を書く
}
構造 2 は平方根 sqrt() や三角関数 sin() など数学的な関数を使用する時だ け使い、通常は構造 1 を使います。
文はセミコロン「;」で区切ります。
またプログラムの任意の場所に /* で始まり */ で終るコメントを書くことが できます。
プログラムは宣言をするところと、手順を記述するところにわけることができ ます。
#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' */
本講義では手順として次のものを取り上げます。
代入文は「変数名 = 式」という形式で書き、式の値が変数に入ります。 ですから、「 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("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(条件){文1;}
if(条件){文2;}else{文3;}
始めの構文は条件が成立する時(0 でない時)だけ文1を実行し、成立しなかっ た時(0 だった時)はなにもしません。 二番目の構文は条件が成立する時(0 でない時)は文2を実行し、成立しなかっ た時(0 だった時)は文3を実行します。
二つの値を比較をする条件式には次の書き方があります。
これらの値は条件が成立すれば 1、成立しなければ 0 になります。
if(x>max){max=x;}
if(b==0){printf("全ての値\n");}
else{printf("解なし\n");}
二つの条件式を一つにまとめるため次の書き方があります。
if((a==0)&&(b!=0)){printf("解なし");}
if((a!=0)||(b!=0)){x=-b/a;}
while 文の構文は if と良く似ています。
while(条件){文;}
「条件を調べて、成立すれば文を実行する」というのを繰り返します。 適切な回数だけ繰り返させるためには何らかのアルゴリズムが必要になります。
なお、for 文は while 文を読みやすくするために導入された別の書き方です。 次の for と while は同じ意味になります。
for(A;B;C){
D;
}
A;
while(B){
D;
C;
}
#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]);
}
}
#include <stdio.h>
main(){
printf("Hello World!\n");
}
#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);
}
#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);
}
}
#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");
}
}
上のプログラム例 4 を改造して次を表示するプログラムを作りなさい。
○○○○○ ○○○○ ○○○ ○○ ○
○ ○○○ ○○○○○ ○○○○○○○
○○○○○ ○ ○ ○ ○ ○ ○ ○○○○○
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 sakamoto::C;
int main(){
C x;
x.show();
return 0;
}
using namespace sakamoto;
int main(){
C x;
x.show();
return 0;
}
このうち最後の名前空間を登録する方法は簡便ですが、名前の衝突を避けると いう本来の名前空間の目的に反しているので推奨できません。
なお、C++ はもともとは名前空間を持たず、途中から導入されました。 名前空間を持たなかった頃のヘッダファイルには C 言語同様に .h の拡張子 が付いていました。 ですから、iostream.h は名前空間が定義されていません。 一方 iostream と .h の付かないヘッダファイルには std という名前空間が 定義されています。 従って、例えば iostream を使って標準出力に値を出力するには次のようにし ます。
#include <iostream>
int main(){
std::cout << "Hello World!" << std::endl;
return 0;
}
#include <iostream>
using std::cout;
using std::endl;
int main(){
cout << "Hello World!" << endl;
return 0;
}
#include <iostream>
using namespace std;
int main(){
cout << "Hello World!" << endl;
return 0;
}
C++ 言語は C 言語の拡張という位置づけで開発されたため、 C 言語のプログ ラムそのものもほとんど C++ コンパイラでコンパイルできます。 多くは機能を追加されたもので、変更されたものはごくわずかです。
main 関数は常に int で宣言する必要があり、また必ずプログラムの最後に return で整数値を返す必要があります。 int で宣言しなかったり、 return で整数値を返してないとコンパイラから警 告を受けます。
なお、プログラムの全体構造として
#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;
}
std::cout は画面に出力するためのオブジェクトで演算子 << がオーバー ライドされ、演算子直後のものを出力します。 演算子直後に int, char, string など様々なものを置いても自動的に出力 されます。 また複数のものを出力する時はすべて << でつなげればつながって出力 されます。 上に書いたように std::endl は改行の他に実際に文字の出力始めるという意 味があるので、単なる改行である '\n' を送るのとは意味が違ってきます。