こんにちは、ナナです。
前回のデバッグ技術の記事『関数のデバッグ方法と脳内デバッグの鍛錬【初心者向け】』では、関数をいかにデバッグするかというデバッグ方法を解説しました。
新しく『配列』『構造体』『ポインタ』という概念を手に入れたのであれば、さらなるデバッグ技術を手に入れましょう。
本記事では次の疑問点を解消する内容となっています。
では、『デバッガ』の使い方を解説していきましょう。
デバッグ技術 Level3:メモリ情報の参照
前回「Level2」で学んだデバッグ技術によって、基本的なステップ実行の方法と、変数の値を監視するための『ローカル』『ウォッチ』画面の使い方を学びました。
「Level3」ではC言語で最も重要なメモリに関するデバッグ手法を解説しましょう。読者としては、次の人を対象としています。
デバッグ技術:『配列』と『文字列』の値を表示する
『文字列』とは文字情報を配列化したものなので、『配列』と『文字列』はほとんど同じものです。
デバッガを使って連続する情報が、どのように管理できるのかを見ていきましょう。
『配列』の値を確認する方法
C言語では『配列』や『文字列』といった情報を扱うことは日常茶飯事です。これらの情報は連続したメモリ領域に格納されている特徴があります。
変数の値を確認したいと言えば、「ローカル」や「ウォッチ」画面を利用することでできますね。
それでは次のようにプログラムした『配列』と『文字列』がどのようにデバッガで確認できるかを見てみましょう。
#include <stdio.h>
// 文字列の定義
char moji[10] = "Hello";
int main(void)
{
int i;
short num[] = {1,2,3,4,5}; // 配列の定義
for (i=0 ; i < sizeof(num) / sizeof(num[0]) ; i++)
{
printf("%d\n", num[i]);
}
printf("%s", moji);
return 0;
}
それではまずは配列numの確認方法から説明しましょう。今回のプログラムでは配列numはmain関数内のローカル変数として定義されています。そのため「ローカル」画面にて確認可能です。
デバッガでは配列numの要素数も管理できているため、全ての配列要素の値を確認することができます。
C言語における配列名とは、配列の番地を示すのでしたね。
そのため、「ローカル」画面には番地情報もしっかりと表示されています。Visual Stuidioは至れり尽くせりでプログラマーをサポートしてくれます。
Visual Stuidioは世界一使われている統合開発環境なだけあって、役に立つ機能も豊富です。
機能は使ってこそ効果を発揮するのです。眠らせていても意味はないですよ!
デバッガを使って『文字列』の値を確認する方法
続いて、『文字列』も確認してみましょう。文字列は配列mojiにグローバル変数として定義されています。そのため、「ウォッチ」画面で値を確認してみましょう。
配列mojiは10個分の領域を確保しているため、デバッガにおいても10個分の配列として表示しています。
char型の情報は文字として管理する型のため、数値とASCIIコードを並列表記してくれています。
16進数表記への切り替え方法
補足ですが、ウォッチ画面やローカル画面に表示される値は10進数が基本になりますが、16進数の方が便利なシーンもあります。右クリックしたメニューから表示を切り替えることができます。
シーンに合わせて見たい進数へ切り替えると作業効率が上がります。
デバッグ技術:『構造体』の値を表示する
『配列』の情報が表示できるのですから、『構造体』のような複合データに関しても、もちろんデバッガは管理することができます。
#include <stdio.h>
typedef struct
{
char name[8];
int age;
double height;
} S_PERSON;
int main(void)
{
S_PERSON player = { "Ichiro", 45, 180.0 };
printf("%s\n", player.name);
printf("%d\n", player.age);
printf("%lf\n", player.height);
return 0;
}
次のように「ローカル」や「ウォッチ」画面において、構造体変数を参照することができます。
『構造体』の中身が見られることは当然なんですが、『構造体』の中に『構造体』のメンバがいても、どこまでも階層的に表示してくれるのが便利なところです。
デバッグ技術:『ポインタ』を使ったメモリの参照
ポインタ変数とは、「他のメモリを指し示す変数」のことです。
ポインタ変数自身は「番地」である数を保持しており、その「番地」を持つメモリを参照することができるのが「ポインタ変数」ですね。
その機能からデバッガも、ポインタを表現できる形式になっています。
#include <stdio.h>
int main(void)
{
int Num = 100;
int * pNum = &Num;
printf("%d", *pNum);
return 0;
}
このプログラムを動かしてデバッガで見てみましょう。
このようにポインタ変数の場合は「番地情報」と「参照先メモリの値」が両方とも表記される形となります。
メモリ画面:メモリ情報を可視化する
C言語で『文字列』の制御をしていると、思い通りにプログラムが動かない時に何がうまくいっていないのかが判断しづらいことがあります。
そんな時に使えるのが『メモリ画面』です。このメモリ画面を活用すると、メモリという情報の一覧を、がっつりと見ることができます。
次のプログラムのstrcat関数は第1引数へ文字列を結合する関数です。この様子をメモリ画面でチェックしてみましょう。白い箇所にブレークポイントを設定し実行しましょう。
#include <stdio.h>
void strcat(char *dest, const char *src)
{
while (*dest != '\0')
{
dest++;
}
while (*src != '\0')
{
*dest = *src;
dest++;
src++;
}
*dest = '\0';
return;
}
int main(void)
{
char hello[16] = "Hello";
char world[16] = "World";
strcat(hello, world);
printf("%s", hello);
return 0;
}
ポインタ変数destには番地が含まれています。この番地の数は覚えておきます。
メモリ画面を表示するには[デバッグ]-[ウィンドウ]-[メモリ]を選択します。
16進数2ケタが順番に羅列されていますね。これがメモリの1バイトになります。この羅列こそがメモリそのものなんです。
それではプログラムを動かして、「Hello」の後ろに「World」を結合してみます。
このようにメモリ上において確かに「World」の文字が赤字で反映されているのがわかります。
プログラムが上手く動かない時は、この画面を見て何が狙いと違う結果になっているかを簡単に確認することができます。
メモリ画面はメモリ内容を簡単に一覧表示できるので、メモリの全体像を把握しやすいのが特徴です。
この辺りの機能をうまくデバッガで活用できるようになると、問題の原因究明から解決までスピーディにできます。