ユーニックス総合研究所

  • home
  • archives
  • c-pointer-decl-init

C言語のポインタの宣言と初期化方法

  • 作成日: 2021-09-29
  • 更新日: 2024-03-22
  • カテゴリ: C言語

C言語のポインタの宣言と初期化方法

C言語のポインタの宣言と初期化方法を解説します。

C言語ではポインタを使わないと高度な処理を書くことができません。
そのためポインタの宣言と初期化方法を知るのは非常に有用です。

たとえばファイル入出力ではFILE型のポインタ変数を使う必要があります。
そのためこのFILE型ポインタ変数の宣言と初期化方法を知っておかないといけません。

この記事ではまず「NULLポインタとはなにか?」というところから始めます。
そして順を追ってポインタの宣言と初期化方法、それらが必要な理由などを解説します。

関連記事
C言語のポインタをC言語歴17年が解説
C言語の文字列のポインタの使い方
C言語の配列とポインタについて

C言語や他の言語を扱うYoutubeも公開しています。
興味がある方は以下のリンクからご覧ください。

Youtubeの当チャンネル

初期化で使われるNULLポインタとは?

まずポインタ変数の初期化で使われるNULLポインタとはなんでしょうか?
NULLポインタとは何も存在しないことを表すポインタです。
このNULLポインタはマクロで定義されています。
コードでは「NULL」と書くことで使うことができます。

関連記事
C言語でnull判定する方法【NULL, 比較】
C言語の終端を表すEOF, NULL, ナル文字について

NULLポインタとポインタ変数の関係

NULLポインタはポインタ変数に代入することができます
このNULLポインタが代入されたポインタ変数は「何もない」という状態を持ちます。
そのためNULLポインタはポインタ変数の初期化で使われます

ポインタ変数を宣言したら「NULLポインタで初期化できる」ということを覚えておきましょう。

NULLポインタの定義は?

NULLポインタは多くの環境で↓のように定義されています(定義が違う場合もあります)。

#define NULL ((void *)0)  

定義を見るとわかりますが、NULLポインタは0(void *)にキャストしたポインタです。
つまりこのNULLポインタの値は0になります。
NULLポインタで初期化されたポインタはつまり0クリアされているということになります。

ポインタの宣言方法

ポインタ変数はどのように宣言するのでしょうか?
具体的に見ていきます。

関連記事
C言語の配列の宣言方法: 配列、可変長配列、内部結合な配列、外部結合な配列、ポインタ配列

int型ポインタの宣言

int型のポインタ変数を宣言するには↓のようにします。

    int *i;  

↑はint型のポインタ変数iの宣言です。
iにはまだ何も値が入っていません。

またポインタ変数の宣言は↓のように一行に複数書くことができます。

    int *a, *b, *c;  

↑の場合、変数a, b, cはともにint型のポインタ変数になります。

文字列の宣言

文字列定数を保存するポインタ変数を宣言するには↓のようにします。

    const char *s;  

↑のconst char型のポインタ変数sにはまだなにも値が入っていません。

FILE型ポインタの宣言

ファイル入出力で使われるFILE型のポインタ変数を宣言するには↓のようにします。

    FILE *fp;  

↑のFILE型のポインタ変数fpにはまだなにも値が入っていません。

関連記事
C言語のファイルの読み込み方法【fopen, fclose, fgets, fgetc, fread, read】
C言語でファイルを一行ずつ読み込む方法【fgets, getline】

ポインタの初期化方法

ポインタ変数はどのように初期化するのでしょうか?
具体的に見ていきます。

int型ポインタの初期化

int型のポインタ変数をNULLポインタで初期化するには↓のようにします。

    int *i = NULL;  

↑のint型のポインタ変数iはNULLポインタで初期化されています。
そのため値はNULLポインタの値(多くの場合0)になります。

また、初期化ではNULLポインタの他に他の変数のアドレス値で初期化することも可能です。

    int a = 1;  
    int *b = &a;  

↑の場合、ポインタ変数はbですが、これは変数aのアドレス値で初期化されています。
そのため変数bには変数aのアドレス値が入ります。

またポインタ変数の初期化は↓のように一行に複数書くことが可能です。

    int *x = NULL, *y = NULL, *z = NULL;  

文字列の初期化

文字列定数を保存するポインタ変数をNULLポインタで初期化するには↓のようにします。

    const char *s = NULL;  

↑のポインタ変数sはNULLポインタで初期化されています。
また、このconst char型のポインタ変数は文字列定数で初期化することも出来ます。

    const char *s2 = "Hello, World!";  

↑のポインタ変数s2には文字列定数「Hello, World!」のアドレスが保存されます。
このポインタ変数をprintf()などで出力すると画面には「Hello, World!」と表示されます。

関連記事
C言語の文字列の使い方: 文字配列と文字列定数

FILE型ポインタの初期化

FILE型のポインタ変数をNULLポインタで初期化するには↓のようにします。

    FILE *fp = NULL;  

↑のポインタ変数fpはNULLポインタで初期化されています。
FILE型のポインタ変数は宣言と同時にfopen()の返り値で初期化するのも一般的です。
その場合は↓のようにします。

    FILE *fin = fopen("init.c", "r");  

ポインタの宣言と初期化の違い

ところでポインタ変数の「宣言」と「初期化」の違いはなんでしょうか?
なぜこれらは2つに分かれているのでしょうか?
その意味は?
具体的に見ていきます。

宣言とは?

宣言」とは、開発者がコンパイラに「この変数、関数を使うよ」ということを知らせるためのコードのことを言います。
宣言と初期化は厳密には違います。
関数宣言などはヘッダーファイルに書かれることがあります。
変数も宣言することでコンパイラに変数を使うことを知らせることができます。
ただし宣言の段階では変数には値は入っていません。
値が入るのは「初期化」の時です。

初期化とは?

初期化」とは、変数に特定の値を実際に代入することを言います。
厳密には代入だけではなく、関数で変数の値をクリアすることも初期化と呼ばれます。
その場合も関数の中では変数に対して代入を行っているわけです。

宣言の段階では変数の使用をコンパイラに知らせるだけなので、実際にはまだ変数に値は入っていません。
しかし、初期化すると変数に値が入ります。

初期化の他に存在するのが「定義」です。
定義も値を初期化するのは同じですが、定義は文脈上で一回しかできません。
しかし初期化は文脈上で何回も行うことができます。

ポインタの初期化が必要な理由

なぜポインタの初期化は必要なのでしょうか?
ポインタ変数の初期化が必要とされる理由は?
初期化しておかないとどうなるのでしょうか?
具体的に見ていきます。

初期化しておかないとどうなるか?

ポインタ変数ですが、宣言の段階ではデタラメな値が入ることがあります。
たとえば↓のコードを見てください。

#include <stdio.h>  

int main(void) {  
    int *a;  
    int *b;  

    printf("%p\n", a);  // (nil)  
    printf("%p\n", b);  // 0x7ffcd1584230  

    return 0;  
}  

↑のポインタ変数a, b宣言だけして初期化していません
これの値をprintf()で出力すると↑のように(コメントが結果部分)なります。
1つ目のポインタaの値は(nil)になって初期化されているように見えます。
しかし2つ目のポインタbの値はデタラメな値が入ってしまっています

このように変数と言うのは宣言の段階ではデタラメな値が入ることがあります。
そのため値を統一した値(NULLポインタ)でクリアするという意味でも、初期化を行う必要があります。

初期化せずに使う人たち

しかし世の中は広く、C言語の中級者以上の人の中にはポインタを宣言だけして初期化せずに使う人もたくさんいます
これの理由は、初期化する必要が無いからです。
宣言の後の処理で値が代入されるから、わざわざ初期化する必要がないということです。

こういった理由により宣言だけして初期化をしないという人がけっこういます。
そしてそれは悪いことではありません。
なぜならそれはその人の経験とスキルによって判断されていることだからです。

しかし、初心者の内はポインタ変数は必ずNULLポインタなどで初期化するクセを付けておいた方が良いかもしれません。
そのほうが予期しないバグを防止することができますし、安全だからです。
たとえばデタラメな値が入っているポインタを使って、不思議なバグを生む可能性を排除することができます。
こういったバグは解決するのが非常に大変で、初心者は特に大変です。

ポインタの初期化のメリット・デメリット

ポインタの初期化のメリット・デメリットはなんでしょうか?
ポインタの初期化のメリットを知っていれば初期化の手間を惜しまずに済みます。
実際の開発ではその実践が役に立つでしょう。
ではポインタの初期化のメリット・デメリットを紹介します。

メリット: バグを防止できる

ポインタをNULLポインタで初期化することでバグを防止することができます。

ポインタをNULLポインタで初期化すると、ポインタには必ずNULLポインタの値が入ります。
そのためデタラメなメモリ領域にアクセスするということがなくなります。

たとえばデタラメなメモリ領域にアクセスしてしまった場合、予期しないバグやエラーになる可能性があります。
さいあく、エラーにもなりません。
そのまま動き続けて、ヘンテコな動作をするプログラムになる可能性もあります。

ポインタをNULLポインタで初期化してバグを防止しておきましょう。

デメリット: 特になし

ポインタを初期化するデメリットは特にありません
初期化のぶん処理が遅くなるんじゃないか? という懸念はあります。
しかし実際はその程度のコストはほとんど問題になりません。
それよりも初期化することのメリットに目を向けるべきです。

おわりに

今回はC言語のポインタの宣言と初期化について見てみました。
初心者の内はポインタはNULLポインタで初期化しておくクセを付けておきましょう。
そうすることで予期しないバグを防止することができます。

🦝 < NULLポインタで初期化しちゃう

🐭 < 初期化されちゃう