ce-14. プログラムの実行順序
1
金子邦彦
(C プログラミング応用)(全14回)
URL: https://www.kkaneko.jp/pro/c/index.html
C言語プログラムの実行順序の理解、Microsoft Visual
Studio C++のステップ実行機能を用いた変数値変化の観察。
【学習内容の構成】
1. プログラムの順次実行:メイン関数から始まり上から下
へ順に実行される基本原理
2. ビルドと実行ファイル生成:C++ソースファイルからの
実行ファイル生成、構文エラー時の対処
3. 条件分岐:if文・else文による条件式の成否に応じた処理
の切り替え
4. 関数呼び出しと戻り:関数呼び出しによるジャンプと
return文による呼び出し元への復帰
5. デバッグ機能:ステップ実行(F10)、ステップイン
(F11)、ブレークポイントによる実行制御と変数観察
• 前提:Microsoft Visual Studio C++の基本操作、C言語の変
数・繰り返し・関数の基礎知識
• 意義:プログラムの動作原理の理解、デバッグ技法の習得
2
自由落下距離
• 前回の授業の「例題1」の復習と重要事項の確認
• 地上で物を落とし始めた後の自由落下距離を求める
• 重力加速度 g は 9.8 とする
• 自由落下距離を求めるために,プログラム中に,計算
式 y = ( 9.8 / 2.0 ) * x * x を書く
•3
Microsoft Visual Studio C++ の画面構成
•4
ファイルなど
が表示される
C++ソースファイ
ルの編集はここで行
う
ビルド結果が現れ
る
#include "stdio.h"
#include <math.h>
#pragma warning(disable:4996)
int main()
{
double x;
double y;
char buf[256];
int i;
double start_x;
double step_x;
FILE* fp;
printf( "start_x =" );
fgets( buf, 256, stdin );
sscanf_s( buf, "%lf¥n", &start_x );
printf( "step_x =" );
fgets( buf, 256, stdin );
sscanf_s( buf, "%lf¥n", &step_x );
fp = fopen( "d:¥¥data.csv", "w" );
for( i = 0; i < 20; i++ ) {
x = start_x + ( i * step_x );
y = ( 9.8 / 2.0 ) * x * x;
printf( "x= %f, y= %f¥n", x, y );
fprintf( fp, "x=, %f, y=, %f¥n", x, y );
}
fprintf( stderr, "file d:¥¥data.csv created¥n" );
fclose( fp );
return 0;
}
•5
自由落下距離の
計算を行っている部分
データファイル名
d:¥¥data.csv
は適切に設定すること
#include "stdio.h"
#include <math.h>
#pragma warning(disable:4996)
int main()
{
double x;
double y;
char buf[256];
int i;
double start_x;
double step_x;
FILE* fp;
printf( "start_x =" );
fgets( buf, 256, stdin );
sscanf_s( buf, "%lf¥n", &start_x );
printf( "step_x =" );
fgets( buf, 256, stdin );
sscanf_s( buf, "%lf¥n", &step_x );
fp = fopen( "d:¥¥data.csv", "w" );
for( i = 0; i < 20; i++ ) {
x = start_x + ( i * step_x );
y = ( 9.8 / 2.0 ) * x * x;
printf( "x= %f, y= %f¥n", x, y );
fprintf( fp, "x=, %f, y=, %f¥n", x, y );
}
fprintf( stderr, "file d:¥¥data.csv created¥n" );
fclose( fp );
return 0;
}
•6
計算を行っている部分
キーボードからの
データ読み込みを
行っている部分
ファイルへの書き出し
を行っている部分
#include "stdio.h"
#include <math.h>
#pragma warning(disable:4996)
int main()
{
double x;
double y;
char buf[256];
int i;
double start_x;
double step_x;
FILE* fp;
printf( "start_x =" );
fgets( buf, 256, stdin );
sscanf_s( buf, "%lf¥n", &start_x );
printf( "step_x =" );
fgets( buf, 256, stdin );
sscanf_s( buf, "%lf¥n", &step_x );
fp = fopen( "d:¥¥data.csv", "w" );
for( i = 0; i < 20; i++ ) {
x = start_x + ( i * step_x );
y = ( 9.8 / 2.0 ) * x * x;
printf( "x= %f, y= %f¥n", x, y );
fprintf( fp, "x=, %f, y=, %f¥n", x, y );
}
fprintf( stderr, "file d:¥¥data.csv created¥n" );
fclose( fp );
return 0;
}
•7
Cプログラムはメイン関数から
実行開始
プログラムは順次実行
変数 x, y, buf, i, start_x,
step_x, fp をメモリエリア中に確保
printf でメッセージを表示
fgets でキーボードから1行を読み込み
sscanf で数値を読み取って変数に格納
printf でメッセージを表示
fgets でキーボードから1行を読み込み
sscanf で数値を読み取って変数に格納
20回の繰り返し (i = 0, 1, ... 19)
x の値から
( 9.8 / 2.0 ) * x * x
を求め,y に書き込む
「ビルド」による実行ファイルの生成
•8
#include "stdio.h"
#include <math.h>
#pragma warning(disable:4996)
int main()
{
double x;
double y;
char buf[256];
int i;
double start_x;
double step_x;
FILE* fp;
printf( "start_x =" );
fgets( buf, 256, stdin );
sscanf_s( buf, "%lf¥n", &start_x );
printf( "step_x =" );
fgets( buf, 256, stdin );
sscanf_s( buf, "%lf¥n", &step_x );
fp = fopen( "d:¥¥data.csv", "w" );
for( i = 0; i < 20; i++ ) {
x = start_x + ( i * step_x );
y = ( 9.8 / 2.0 ) * x * x;
printf( "x= %f, y= %f¥n", x, y );
fprintf( fp, "x=, %f, y=, %f¥n", x, y );
}
fprintf( stderr, "file d:¥¥data.csv created¥n" );
fclose( fp );
return 0;
}
C++ソースファイル
その他のファイル
ビルド
Microsoft Visual
Studio C++
「ビルド」により実行ファイル等
が生成される
実行ファイル
構文エラーがあると,
「ビルド」時にエラーメッセージが表示される
(実行ファイルは生成されない)
その他,ビルドの結果
として生成されるファイル
「消去(clean)」の操作
•9
その他のファイル
ビルド
Microsoft Visual
Studio C++
「消去(clean)」の操作により,
ビルドの結果が消える
(元のソースファイル等は消えない)
実行ファイル
その他,ビルドの結果
として生成されるファイル
#include "stdio.h"
#include <math.h>
#pragma warning(disable:4996)
int main()
{
double x;
double y;
char buf[256];
int i;
double start_x;
double step_x;
FILE* fp;
printf( "start_x =" );
fgets( buf, 256, stdin );
sscanf_s( buf, "%lf¥n", &start_x );
printf( "step_x =" );
fgets( buf, 256, stdin );
sscanf_s( buf, "%lf¥n", &step_x );
fp = fopen( "d:¥¥data.csv", "w" );
for( i = 0; i < 20; i++ ) {
x = start_x + ( i * step_x );
y = ( 9.8 / 2.0 ) * x * x;
printf( "x= %f, y= %f¥n", x, y );
fprintf( fp, "x=, %f, y=, %f¥n", x, y );
}
fprintf( stderr, "file d:¥¥data.csv created¥n" );
fclose( fp );
return 0;
}
C++ソースファイル
•10
「消去(clean)」の操作
「消去(clean)」の操作を行っても,元のソース
ファイルが消えるわけでは無い(ディスク使用量
の節約になる)
構文エラーの例
• 全角文字
• 全角文字はプログラム中の決められた場所にしか入れ
てはならない。
• コメント
• 文字列(ダブルクォートで囲まれた部分)
• 「"」 抜け
• 「;」 忘れ
• など
•11
ビルド結果が現れる.「1
正常終了,0 失敗・・・」
ならばビルドに成功
ビルドが正常終了し,実行ファイルが生成できた
ことを示すメッセージ
•12
•13
構文エラーの例(1)
ここでは,セミコロン「;」を入れるのを
忘れている(人間の目では発見が難しい)
ビルドが失敗したことを示すメッセージ
7行目に構文エラー
構文エラーの例(1)
マウスで「構文エラー」とある行をダブルクリックすると,
エディタのカーソルが動く
エラーの付近にマークが付く
•14
ここでは,セミコロン「;」を入れるのを
忘れている(人間の目では発見が難しい)
•15
構文エラーの例(2)
ここで,「doublr」とあるのはスペルミス
(正しくは,double)
ビルドが失敗したことを示すメッセージ
(ミスは1箇所なのに,エラーは多数)
9行目に「’doublr’:定義されていない識別子です」
データファイル
• プログラムでのファイル操作
• ファイル生成
• ファイル読み出し
• ファイル書き込み
•16
#include "stdio.h"
#include <math.h>
#pragma warning(disable:4996)
int main()
{
double x;
double y;
char buf[256];
int i;
double start_x;
double step_x;
FILE* fp;
printf( "start_x =" );
fgets( buf, 256, stdin );
sscanf_s( buf, "%lf¥n", &start_x );
printf( "step_x =" );
fgets( buf, 256, stdin );
sscanf_s( buf, "%lf¥n", &step_x );
fp = fopen( "d:¥¥data.csv", "w" );
for( i = 0; i < 20; i++ ) {
x = start_x + ( i * step_x );
y = ( 9.8 / 2.0 ) * x * x;
printf( "x= %f, y= %f¥n", x, y );
fprintf( fp, "x=, %f, y=, %f¥n", x, y );
}
fprintf( stderr, "file d:¥¥data.csv created¥n" );
fclose( fp );
return 0;
}
「自由落下距離」のプログラムを実行すると
データファイルが生成される
•17
C++ソースファイル
その他のファイル
ビルド
Microsoft Visual
Studio C++
実行ファイル
データファイル
自由落下距離のプログラムを実行すると,
データファイル data.csv が生成される
データファイルに関係
している部分
例題1.自由落下距離
• 「自由落下距離」のプログラムについて,実行順
を確認するとともに,変数の値の変化を観察する
• Microsoft Visual Studio C++ のステップ実行機能を使用
• 前回の授業で作成した「プロジェクト」を開く
•18
#include "stdio.h"
#include <math.h>
#pragma warning(disable:4996)
int main()
{
double x;
double y;
char buf[256];
int i;
double start_x;
double step_x;
FILE* fp;
printf( "start_x =" );
fgets( buf, 256, stdin );
sscanf_s( buf, "%lf¥n", &start_x );
printf( "step_x =" );
fgets( buf, 256, stdin );
sscanf_s( buf, "%lf¥n", &step_x );
fp = fopen( "d:¥¥data.csv", "w" );
for( i = 0; i < 20; i++ ) {
x = start_x + ( i * step_x );
y = ( 9.8 / 2.0 ) * x * x;
printf( "x= %f, y= %f¥n", x, y );
fprintf( fp, "x=, %f, y=, %f¥n", x, y );
}
fprintf( stderr, "file d:¥¥data.csv created¥n" );
fclose( fp );
return 0;
}
•19
自由落下距離の
計算を行っている部分
データファイル名
d:¥¥data.csv
は適切に設定すること
•20
ビルド後の画面
ビルドが正常終了したこと
を示すメッセージ
ビルドの手順:
「ビルド」→「ソリューションのビル
ド」
ビルドが正常終了しない
ときは,プログラム中の
構文エラーを疑う
「1.正常終了」を
確認
実行
を示すマーク
実行ウインドウ
が開く
「F10」キーを押すとステップ実行が
始まる.(マウスカーソルは,
Microsoft Visual Studio C++ 内に入れておく)
•21
変数の値を
観察できる
さらに「F10」キーを押すとス
テップ実行が続く
マークが進む
•22
表示されたメッセージ
「printf( "start_x=" );の実行が
終わったので,メッセージが出る
さらに「F10」キーを押すとス
テップ実行が続く
•23
変数の値を
観察できる
マークが進む
入力待ち状態
(「 fgets( buf, 256, stdin );の実行が
終わったので,実行ウインドウに
おけるキーボードからの入力待ち
状態に入っている)
さらに「F10」キーを押すとステップ実行
が続く(今度は入力待ち状態)
•24
マークが
変化
マークが現れる
読み込んだデータが変数 buf に
入ったことが確認できる
ここでは 0 Enter
実行ウインドウで,「0 Enter」と
すると,ステップ実行が再開する
実行ウインドウで「0 Enter」とすると実
行が続く(0 の部分は数値なら何でも良い)
•25
実行手順 (通常実行の場合)
• Microsoft Visual Studio C++ で 「デバック」→
「デバッグなしで開始」
• すると,新しいウインドウが開く
• 新しいウインドウが現れるので, start_x, step_x
の値をキーボードから与える
• 例えば
• start_x = 0
• step_x = 0.1
• ウインドウは消えるが,d: ドライブに data.csv
(データファイル)が作成されるので,Excel 等で
開き確認する
•26
実行手順 (ステップ実行の場合)
• Microsoft Visual Studio C++ で
「F10(ファンクションの10)」
→ すると,新しいウインドウが開く
「F10」は,Microsoft Visual Studio C++のウインドウ内
にマウスカーソルを入れた状態で押すこと
• 「F10」 を押すたびに,1ステップずつ実行が進
む
•27
例題2.平方根の計算
• 浮動小数データを読み込んで,平方根の計算と表
示を行うプログラムを作る.
• 但し,負の数の場合には,メッセージを表示する
• 負の数であるかどうかによって条件分岐を行うために if
文を使う.
例) 9のとき: 3
-1のとき: メッセージを表示
•28
#include "stdio.h"
#include <math.h>
int main()
{
double x;
double y;
char buf[256];
int ch;
printf("x=");
fgets( buf, 256, stdin );
sscanf_s( buf, "%lf¥n", &x );
if ( x < 0 ) {
printf("負なので計算できません¥n");
}
else {
y = sqrt(x);
printf("sqrt(%f)=%f¥n", x, y);
}
ch = getchar();
ch = getchar();
return 0;
}
条件が成り立つ場合
に実行される部分
条件式
条件が成り立たない
場合に実行される部分
•29
#include "stdio.h"
#include <math.h>
int main()
{
double x;
double y;
char buf[256];
int ch;
printf("x=");
fgets( buf, 256, stdin );
sscanf_s( buf, "%lf¥n", &x );
if ( x < 0 ) {
printf("負なので計算できません¥n");
}
else {
y = sqrt(x);
printf("sqrt(%f)=%f¥n", x, y);
}
ch = getchar();
ch = getchar();
return 0;
}
実行順
(x<0) の場合
①
②
③
④
⑤
⑥
⑦
•30
#include "stdio.h"
#include <math.h>
int main()
{
double x;
double y;
char buf[256];
int ch;
printf("x=");
fgets( buf, 256, stdin );
sscanf_s( buf, "%lf¥n", &x );
if ( x < 0 ) {
printf("負なので計算できません¥n");
}
else {
y = sqrt(x);
printf("sqrt(%f)=%f¥n", x, y);
}
ch = getchar();
ch = getchar();
return 0;
}
実行順
(x≧0) の場合
•31
①
②
③
④
⑤
⑥
⑦
⑧
平方根の計算
•32
マークが「if ( x < 0 ) {」に来たときに,
「F10」を押すと
「y = sqrt(x);」の行にジャンプする
•33
条件分岐とは
• 「ある条件式」が成り立てばAを、成り立たなけ
ればBを実行
•34
Yes
No
B A
条件式
if 文と else 文
「条件式」が成り立てばAを、成り立たなければB
を実行
•35
Yes
No
B
A
条件式
if ( 条件式 ) {
式;
...;
}
else {
式;
...;
}
B
A
if 文
if 文のみを書いて,else 文を書かないこともできる.
「ある条件」が成り立つときに限りAを実行
•36
Yes
No
A
条件式
if ( 条件式 ) {
式;
...;
}
A
比較演算
• 条件式の中には,ふつう,比較演算を書く
• 演算子 意味
< 左辺が右辺より小さい
<= 左辺が右辺以下
> 左辺が右辺より大きい
>= 左辺が右辺以上
== 左辺が右辺と等しい
!= 左辺が右辺と等しくない
•37
比較演算の例
if (age >= 20 ){
printf("You may drink alcoholic beverage. ");
}
else{
printf("You may not drink alcoholic
beverage.");
}
•38
「左辺が右辺以上」の意味
字下げとセミコロンを忘れないこと
• セミコロンを忘れる
と
• プログラムは動かない
• 字下げを忘れると
• プログラムは動くが,
読みづらい
•39
if ( 条件式 ) {
文;
...;
}
else {
文;
...;
}
if ( 条件式 ) {
文;
...;
}
字下げ
セミコロン
字下げ
セミコロン
セミコロン
字下げ
例題3.棒グラフでのステップ実行
• 整数から,その長さだけの棒を表示する関数 bar
を作る
例) 5 → *****
• 関数 bar を使って,「整数を読み込んで,読み込
んだ長さの棒を表示するメイン関数を作る
• ステップ実行(「F10」キー)を行う
•40
棒グラフ
#include "stdio.h"
#include <math.h>
void bar( int len )
{
int i;
for (i=0; i<len; i++) {
printf("*");
}
printf("¥n");
return;
}
int main()
{
int len;
char buf[256];
int ch;
printf( "len =" );
fgets( buf, 256, stdin );
sscanf_s( buf, "%d¥n", &len );
bar( len );
ch = getchar();
ch = getchar();
return 0;
}
•41
bar関数
main関数
プログラム実行は
main 関数(メイン
関数)から始まる
複数の関数を含む
プログラム
#include "stdio.h"
#include <math.h>
void bar( int len )
{
int i;
for (i=0; i<len; i++) {
printf("*");
}
printf("¥n");
return;
}
int main()
{
int len;
char buf[256];
int ch;
printf( "len =" );
fgets( buf, 256, stdin );
sscanf_s( buf, "%d¥n", &len );
bar( len );
ch = getchar();
ch = getchar();
return 0;
}
関数呼び出し
プログラム実行順
•42
①
②
③
⑦
④
⑤
⑥
戻り
メイン関数の先頭行
がプログラム実行の始まり
メイン関数内の return
がプログラム実行の終わり
⑧
⑨
•43
ビルド後の画面
ビルドが正常終了したこと
を示すメッセージ
ビルドの手順:
「ビルド」→「ソリューションのビル
ド」
ビルドが正常終了しない
ときは,プログラム中の
構文エラーを疑う
ステップ実行
•44
「F10」キーを押すとステップ実行が始ま
る.(マウスカーソルは,
Microsoft Visual Studio C++ 内に入れておく)
さらに「F10」キーを押すとス
テップ実行が続く
マークが進む
変数の値が変化する
•45
さらに「F10」キーを押すとス
テップ実行が続く
•46
実行ウインドウで「5 Enter」とすると実行
が続く(5 の部分は整数なら何でも良い)
•47
さらに「F10」キーを押すとス
テップ実行が続く
•48
例題3(b).棒グラフでのステップイン
• ステップ実行とステップインを行う
• ステップ実行(「F10」キー)
• ステップイン(「F11」キー)
• 例題2のプログラムをそのまま使う
•49
プログラム実行順
• 普通,プログラム中の文は,上から下へ順に実行
される
• 関数呼び出しでは,関数の先頭に「ジャンプ」す
る.
• 関数呼び出しの例 bar( len );
• 呼び出された関数の中で return 文に出会うと,関
数呼び出しの場所に戻る.
•50
このことは,C言語が「手続き型言語」と言われる理由の1つ
#include "stdio.h"
#include <math.h>
void bar( int len )
{
int i;
for (i=0; i<len; i++) {
printf("*");
}
printf("¥n");
return;
}
int main()
{
int len;
int ch;
printf( "len=" );
scanf( "%d", &len );
bar( len );
ch = getchar();
ch = getchar();
return 0;
}
プログラムの流れ
•51
bar 関数
メイン関数
bar( len );
関数呼び出し
return;
プログラムの実行開始
プログラムの実行終了
* printf, scanf の
呼び出しについては
図では省略
ステップイン機能
マークが「bar( len );」の行に来たときに
F11 キーを押して,ステップイン機能を使う
•52
ステップイン機能
マークが bar 関数の内部に移る
(後は,「F10」キーでステップ実行を続ける)
•53
補足説明事項
•54
ブレークポイント
• Microsoft Visual Studio C++ のブレークポイント
機能を試す
• ブレークポイント
•55
Microsoft Visual Studio.NET
でのブレークポイント設定
•56
ここをクリックして,ブレークポイントの設定
「●」はブレークポイント設定済みの印
ブレークポイントでプログラム実行が中断するので,
実行結果の画面が消えずに残る