スライドショー

C#でポインタは使えるの?unsafeの使い方と基礎知識まとめ

C#でポインタは使えるの?unsafeの使い方と基礎知識


ポインタってなに? どうやって扱うの?
参照情報自体を表示したい

こんにちは、エンジニアでC#ライターの遠藤です!

CC++で目にする事のあったポインタは、C#でも存在しています。今回の記事では、C#におけるポインタの基礎知識と使い方について紹介します。

この記事は以下のような方へ向けて書きました。

  • ポインタについて知りたい方
  • C#でポインタが使いたい方

この記事を読んでいただけると、基礎的な知識と使い方が分かります。是非最後までお付き合いください。

ポインタとは

コーディングする中で宣言する変数の値は、メモリに保存されます。そのさいメモリには値を格納する領域があり、そこにはそれぞれアドレスが付けられています。

そのアドレスそのものの値を示す事ができるのがポインタです。

ポインタの基本的な使い方は後ほど解説しますが、基本としては変数に「*(アスタリスク)」をつけたものがポインタとなります。

実際の例:

using System;

class Program
{
    public static void Main()
    {
        unsafe //unsafeブロックの宣言
        {
            int* p; //ポインタの宣言
            int n = 10;

            p = &n; //pにnのアドレスを代入している
            Console.WriteLine((int)p);
        }
    }
}

実行結果:

1735908748

※割り振られるアドレスは都度違うので、実行結果は毎回変わります。

ここで一つ注意していただきたいのが、C#ではポインタはCやC++などとは異なり、重大なバグの原因になりやすいことなどから原則としてポインタを使う事は制限されています

C言語との連携などでどうしても使用したいときは「unsafe」と記述されたブロックの中でだけ使用可能で、くわえてコンパイルのときに/unsafeオプションをつける事が条件となります。

unsafeとは

上述の通り、C#ではポインタをどこでも使えるという訳では無く、unsafeが記述されたブロックだけで使用可能です。

ここではunsafeブロックの書き方を紹介します。

unsafeの使い方

unsafeの基本的な使い方は先ほどの例の通りで、「unsafe{処理}」と記述します。

この処理の中でだけポインタが書けます。

using System;

class Program
{
    public static void Main()
    {
        unsafe //unsafeブロックの宣言
        {
            int* p; //ポインタの宣言
            int n = 10;

            p = &n; //pにnのアドレスを代入している
            Console.WriteLine((int)p);
        }
    }
}

unsafe修飾子

unsafeはブロックとするだけでなく、クラスやメソッドをunsafeとすることも可能です。

その時は、unsafe修飾子を付けます。

実際の例:

using System;

class Program
{
    unsafe void UnsafeMethod()
    {
        int* p; //ポインタの宣言
        int n = 10;

        p = &n; //pにnのアドレスを代入している
        Console.WriteLine(*p); //pのアドレスに格納されている値を出力
    }
    public static void Main()
    {
        Program test = new Program();
        test.UnsafeMethod();
    }
}

実行結果:

10

ポインタの使い方

前章のサンプルコードを再度ご確認ください。

11行目で値を出力する際、「*p」と記述されていることが分かりますね。*pは、pのアドレスに格納されている値を意味しています。

ポインタには他とは少し違う操作が必要になりますので、以下の一覧を見て基本的な操作を把握しておきましょう。

演算子意味備考
*アドレスに格納されている値を参照する(間接参照)
->ポインタからその構造体のメンバにアクセスするa->bは(*a).bと同じ意味
[]ポインタにインデックスを付ける
&変数のアドレスを取得する
++ポインタのインクリメント
--ポインタのデクリメント
+, - ポインタ演算をする
==、!=、<、>、<=、>=ポインタを比較する

fixedステートメントについて

C#にはメモリを整理する処理でガベージコレクション(以降GC)、コンパクションというものがあります。GCが発生すると、その前後でオブジェクトの配置場所が変更されてしまいます。

配置場所が変わってしまうと、当然アドレスが違うので参照ができなくなってしまいます。

これでは困るので、GCでオブジェクトの配置場所が変わってしまうリスクが伴う場合はfixedステートメントを付ける必要が出てきます。

実際の例:

using System;
using System.Runtime.CompilerServices;

class DummyClass
{
    public int x;
    public int y;
}
class Program
{
    unsafe void UnsafeMethod()
    {
        DummyClass test = new DummyClass();
        
        fixed(int* p = &test.x)
        {
            //無理やりGCを行う
            for (int i = 0; i < 99999999; i++) { var obj_dummy = new object(); }
            Console.WriteLine("pのアドレス: " + (int)p);
            Console.WriteLine("GC前のメモリ: " + GC.GetTotalMemory(false));

            GC.Collect(0, GCCollectionMode.Forced);
            Console.WriteLine("+++GCを行います+++");

            Console.WriteLine("pのアドレス: " + (int)p);
            Console.WriteLine("GC後のメモリ: " + GC.GetTotalMemory(false));
        }
    }
    public static void Main()
    {
        Program test = new Program();
        test.UnsafeMethod();
    }
}

実行結果:

pのアドレス: -2092473304
GC前のメモリ: 3242112
+++GCを行います+++
pのアドレス: -2092473304
GC後のメモリ: 119232

GCが発生しても、fixedステートメント内ではアドレスが固定されている事が分かります。

まとめ

今回の記事では、以下のことを解説致しました。

  • ポインタとは
  • unsafeとは
  • ポインタの使い方
  • fixedステートメントについて

ポインタは基本的にNGですが、どうしても必要になったケースでは"使わざるを得ない"状態になっていることと思います。

別の方法がなければ覚えるしかないので、ここでC#におけるポインタの基礎的な使い方を覚えて役立ててください。

LINEで送る
Pocket

無料でSEからWebエンジニアへ転職しませんか?



侍エンジニア塾では、完全未経験の方から現在SEだけどプログラミングはやっていないという経験者まで、幅広い方々の人生を好転させるプログラミング指導を行ってきました。SEの方とお話していくなかで、

  • システムエンジニアという職業だけどコードが書けない
  • 事務作業が多くスキルがないため将来が不安
  • スクールに通うと完全未経験者と同じスタートになるからレベルが合わない
という、すでに知識があるSEならではのお悩みがあることに気づきました。そんな方におすすめなのが、弊社の「転職コース 」です。

弊社では、マンツーマンでレッスンを行いますので、現在お持ちの知識レベルからカリキュラムを作成いたします。さらにこちらの転職コースは無料で受講を始められて転職成功でそのまま卒業できるというとてもお得なコースとなっています。

既に知識のあるSEといっても転職は年齢が若いほど受かりやすいため、まずは無料体験レッスンで今の現状や理想の働き方について一緒に考えていきましょう。

まずは無料体験レッスンを予約する

書いた人

遠藤貴大

遠藤貴大

1991年生まれ。双子座。
理系大学で認証システムを学んだ後、アプリ開発者となる。
新しく学ぶ人に寄り添った記事を心がけて執筆します。
芸術が好き。いつか猫と暮らすのが夢。

おすすめコンテンツ

あなたにぴったりなプログラミング学習プランを無料で診断!

プログラミング学習の効率を劇的に上げる学習メソッドを解説