Nodachisoft Nodachisoft logo, Katana Sword Icon
  
@あまじ✎ 2021年1月18日に更新

第2章39 ヌルポインタ(NullPointer) と Void について

第2章39 ヌルポインタ(NullPointer) と Void について
イチからゲーム作りで覚えるC言語
第2章38 ポインタ変数への足し算 : PREV
NEXT : 第2章40 swap関数を作ってポインタ変数の中身を交換する :

この記事でやること

ここでは C言語の null pointer について確認していきます。

null pointer を使うことで、ポインタ変数が「まだ初期化していないですよ!」という状態を確認することができます。

例えば、ゲームデータの読み込みが未完了であるなど、特定のデータが(まだ)参照できない 状態であることを表すことができます。

Null ってどういう意味?

元々のドイツ語の「0」という意味から来ているようです。 単語には他に、「無効の」「無価値の」とか「空の」といった意味があります。

発音記号は /nʌl/ なので、個人的には「ナル」という読み方のほうがカタカナ読みとしてはしっくりくる気がしますが、日本では「ヌル」と呼ばれることの方が感覚的には多い気がします。 こういったカタカナ表記は現場にあわせて伝わる読み方を話すのが良いですね。

Null Pointer の定義

C言語で ヌルポインタ(null pointer) とはNULLが代入されているポインタの事です。

NULL ってなに?

では、大文字で書かれた NULL とは何でしょう。 使い方を見てみます。

NULLを使ったファイル
#include  <stdio.h>
int main() {
    int *pointer=NULL;
}

C言語では、定数などを大文字で書いておく、という慣習があります。

私のプログラミング環境でも NULL は #define 文などを使って、ヘッダーの中で定義されていました。

上記の NULL を使ったソースコードを、プリプロセスだけ実行して結果を確認してみます。

例えば gcc という開発環境を使っている方であれば、gcc -E test.c > preprocessed.c とコマンドを打つことで、コンパイルはせずにプリプロセス処理までを実施した結果の Cソースコードが出力されます。

参考として、出力されたコードを確認すると、下のように変換されていることがわかります。

変換後
int main() {
  int *pointer=
    ((void *)0)
      ;
}

想定通り、NULL の箇所が変換されており、具体的には「 ((void *)0) 」に変換されてました。

つまり、NULL は stdio.h を #include(取り込み)したことで、 どこかで下のように定義がされたことがわかります。

define
#define NULL ((void *)0)

NULLの定義場所 具体的には stddef.h のヘッダファイルの中で#define NULL ((void *)0) が定義されています。
stddef.h は "STanDardDEFinitions.h" の略でC言語の標準的な定義を書いているヘッダーファイルです。
stdio.h を取り込んだ時、stdio.h からさらに必要な様々なヘッダーが #include されていて、そのうちの一つとして 取り込まれています。

汎用ポインタ

この、((void *)0) という式について見ていきましょう。 (void *) は汎用ポインタと呼ばれます。

void は「空虚」とか、空みたいな意味があります。強そう。

いろんなポインタの型をキャストして使える、汎用的なポインタ、という ところからこう呼ばれます。

null pointer ってなに?

以前、型を明示的にキャストする方法を書きました。例えば、

short a = (short)100;

みたいな感じです。これは、右辺で定数 100 をまず short 型にキャストした後、short型の変数 a に代入していることになります。

ちょっと読みづらいですが、((void *)0) も似たようなことをしており、 (キャストする型) 値 の文法に従って、 0 という定数を、型 「void *」にキャストしています。

つまり、定数 0 を void 型のポインタに整数 変換しています。

この、((void *)0) のことをヌルポインターnull pointer)と呼びます。

つまり具体的には、NULL には定数 0 へのポインタが入りますので、参照すると定数 0 です。

NULLは0なの?NULLと0の違いは NULL と 定数 0 の違いはあるのでしょうか。
C言語(C11)の仕様書には、 0 のような定数を (void *) にキャストして NULL として定義しておこう という記載があり、かならずしも NULL イコール 0 であるとは限らず、 処理系(C言語の標準ヘッダー定義を作成している人たち)によっては、#define NULL ((void *)1) のように、NULL は定数 1 と定義している可能性もあります。
ただ、私が普段使うような gcc や Microsoft VisualStudio に付随する C言語の ビルド環境では定数 0 で定義されてます。

null pointer って何に使うの?

null pointer は、どのようなオブジェクトや関数が指すポインタとも異なるポインタと定義されています。

  • ポインタの初期化
  • 配列の終わりを定義
  • 関数の結果がエラーだった時

などで利用することが出来ます。

初期化されていないポインタ

ポインタ変数を定義した直後は、 ポインタ変数は適当に使えそうなメモリアドレスを指した状態です。 実際に指示されたメモリアドレスの中身は初期化されていないので、 プログラムでこれまでに使ってきたメモリのゴミデータが入っている可能性があります。

 
初期化してないポインタの中身
#include <stdio.h>
int main() {
    int *monsterLevel;  // この時点では何が入っているか不明。
    printf("monsterLevel = %d\n", monsterLevel);
}

実行すると下のような結果になりました。 この表示される結果は、実行している人の環境によって変わるかと思います。

実行結果
monsterLevel = 16

ポインタの指しているメモリアドレスが 16 と表示されました。 想定外のレベルになってしまいました。

変数の中身が初期化されていない状態を NULL として 代入しておき、その後、データの初期化をする! という例を書いてみます。

実行結果
#include <stdio.h>
int main() {
  int *monsterLevel = NULL;
  int skeletonLevel = 5;
  if ( monsterLevel == NULL ) {
    // 初期化
    monsterLevel = &skeletonLevel;
  }
  printf("monsterLevel = %d\n", *monsterLevel);
}

初期化されているかを判断したい場合に、まずは 変数の宣言と初期化で NULL (つまり定数 0 へのメモリアドレス)を代入しておき、 初期化が必要になったタイミングで NULL との比較をし、変数が NULL なら初期化していない、と 判断し初期化をする、ということができます。

このコードの例ではプログラムが非常に単純すぎて、あまり便利なところがつかみづらいかもしれませんが、 「いつ初期化されるかわからない、必要になったら1度だけ初期化する」などの 処理で NULL との比較は非常に有用なので、覚えておくと便利です。

補足

C言語とC++言語では多くの互換性があり、NULL という概念も同様に存在していますが、 お互い微妙に定義が異なります。

C++ 言語では NULL であることを保証する nullptr という専用の型が存在するので、そちらの利用が推奨されます。

あとがき

今回はここまでです!おつかれさまでした。

非常に参考になったサイトさまや、参考文献など

ページの更新履歴

更新日 更新内容
更新なし
イチからゲーム作りで覚えるC言語
第2章38 ポインタ変数への足し算 : PREV
NEXT : 第2章40 swap関数を作ってポインタ変数の中身を交換する :
 
 
送信しました!

コメント、ありがとうございます。

なんかエラーでした

ごめんなさい。エラーでうまく送信できませんでした。ご迷惑をおかけします。しばらくおいてから再度送信を試していただくか、以下から DM などでご連絡頂ければと思います。

Twitter:@NodachiSoft_jp
お名前:
 
連絡先:
 
メッセージ:
 
戻る
内容の確認!

以下の内容でコメントを送信します。よろしければ、「送信」を押してください。修正する場合は「戻る」を押してください

お名前:
 
連絡先:
 
メッセージ:
 
Roboto からの操作ではないという確認のため確認キーを入れてください。
確認キー=95
戻る
 / 
送信確認へ
コメント欄
コメント送信確認へ

関連ありそうな記事(5件)です!

第1章01 Visual Studio Community 2019 のインストール手順

第1章01 Visual Studio Community 2019 のインストール手順

#C11仕様#C言語#ゲームプログラミング✎ 2021-08-08
C言語でプログラミングをするために、無料で使える Visual Studio Community を使った開発環境を揃えていく手順や注意点をお話しています。
目次
第2章39 ヌルポインタ(NullPointer) と Void について
第2章39 ヌルポインタ(NullPointer) と Void について
この記事でやること
この記事でやること
Null ってどういう意味?
Null ってどういう意味?
Null Pointer の定義
Null Pointer の定義
NULL ってなに?
NULL ってなに?
汎用ポインタ
汎用ポインタ
null pointer ってなに?
null pointer ってなに?
null pointer って何に使うの?
null pointer って何に使うの?
初期化されていないポインタ
初期化されていないポインタ
補足
補足
あとがき
あとがき
非常に参考になったサイトさまや、参考文献など
非常に参考になったサイトさまや、参考文献など
ページの更新履歴
ページの更新履歴
Nodachisoft © 2021