このドキュメントは http://edu.net.c.dendai.ac.jp/ 上で公開されています。
この講義では C 言語を使って、データ構造とアルゴリズムについ て学びます。
C++ は複雑ですので、この講義には向きません。 C 言語に特化して講義しま す。
今年度は各自のパソコンでC言語のコンパイラをインストールして、学習し ます。 授業を受けるにあたって必要なのは、Cコンパイラとプログラムを編集する エディタになります。 なお、C++言語はC言語と完全に互換性はありませんが、C++コンパイラにC言語モードが内蔵されていて、Cコンパイラとして使うことができるものもあります。
Cコンパイラには様々な種類がありますが、本講義で作る プログラムに対しては、せいぜい printf を使う程度という意味で、どんな C コンパイラでも講義資料のプログラムは動かせ、レポートも作成できます。
Linux の様々なディストロでは gcc や clang などをすぐにインストールで きるはずです。
MacOSX では Xcode をインストールすると gcc がインストールされます。 また、 Xcode で C 言語のプログラムを編集、実行することもできます。
工学部第二部情報通信工学科では Windows 10や11 を使用している学生が多い のではないかと思います。 従って、以後、講義中では、Windows 10 や Windows 11 を使用することを前 提とし、他の環境を使用している人については質問などを通じて対応するよ うにしようと 思います。
Windows11 を使用している場合、最初の選択肢としては、Microsoft Visual Studio で C++ の環境をインストールすることです。 実際にインストールしてみましたが、Community 2022 というバージョンで は、C++デスクトップ開発環境を選択すると数GB のダウンロードと、再起動が 必要です。
本講義での標準環境として、インストールが楽で、ダウンロード容量も少な くて、多機能なものとして、msys2 を採用したいと思います。 なお、似たような環境に Cygwin もあります。 とにかく、Cコンパイラが使える環境があれば、新しく準備する必要はありません。
MSYS2 では Windows 上で UNIX のコマンドライン風の環境を実現します。 但し、MSYS2ではWindowsのコマンドも使えます。
なおこの
道具を導入する場合にはいくつかの考え方があります。 以下に典型的な考え方を示しますが、どれが優れた考え方かは個人の考え方 とケースバイケースによるのではないでしょうか?
プログラムを編集するエディタとして、上記の考え方に対応させて紹介しま す。 どれを導入しても講義を受けることはできますが、利便性などは大きく異な ります。
プログラムはソースコードともソースファイルとも呼ばれ、文字が改行で 区切られたテキストファイルで表現されます。 さらに、C言語のソースファイルには、 .c という拡張子がファ イル名につけられます。
ソースファイルはそのままで実行できません。 実行可能なファイル形式は OS によって異なります。 基本的には、OSが読み込むと、コンピュータの機械語として実行できるよう なファイルで、これを実行ファイルなどとも呼びます。 特に Windows では .exe という拡張子がファイル名に付いています。
ソースファイルを実行ファイルに変換するのを翻訳と呼んだり、 コンパイルと呼んだりします。 コンパイルをする実行ファイルをコンパイラと呼びます。
GNUプロジェクト(http://www.gnu.org/)では自由なソフトウェアとして、C
コンパイラ GCC を提供しています。
次のプログラムを実行させなさい。
#include <stdio.h> main(){ printf("Hello World\n"); }
Visual Studio Community 2022 では次のようにします。
なお、「プロジェクト」→「○○(プロジェクト名)のプロパティ」でプロ パティページを開き、次のように設定すべきですが、しなくても通常問題あり ません。
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]; /* s=s+a[i]; と同じ */
--j; /* j=j-1; と同じ */
z[i++]=y[j++]; /* z[i]=y[j];i=i+1;j=j+1;z[i-1]; と同じ */
標準出力に文字を出力するのが 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を実行します。
if(0){y=1;} /* 何もしない */
if(1){y=1;} /* y=1; と同じ */
if(x){y=1;}else{y=2;} /* x が 0 でない時 y=1; x が 0 の時 y=2; */
二つの値を比較をする条件式には次の書き方があります。
これらの値は条件が成立すれば 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;
}
for(i=0;i<3;i++){
printf("あ");
}
i=0;
while(i<3){
printf("あ");
i++;;
}
#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±%fi\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 を改造して次を表示するプログラムを作りなさい。
〇〇〇〇〇 〇〇〇〇 〇〇〇 〇〇 〇
〇 〇〇〇 〇〇〇〇〇 〇〇〇〇〇〇〇
〇〇〇〇〇 〇 〇 〇 〇 〇 〇 〇〇〇〇〇