C言語のポインタについて

2021/12/10に公開

C言語のポインタはC言語を理解する上で一番難しい概念ですが、簡単に言うとメモリのアドレスが入った変数です。このおかげでアセンブラがあまり必要なくなり、高級な言語でメモリを直接扱えるようになってます。メモリに直接アクセスできるので、組み込み系ではLEDを点灯させたりすることができます。Pythonなどではなかなかできないことです。メモリへの直接のアクセスは例えばGCの実装や、OSの実装、ハードウェアの制御などで必要になります。変数のアドレスは&演算子で取ることができます。例を挙げると

int a = 123;
int* b = &a;

などです。このbには変数aのメモリ上のアドレスが入っています。なので、bを関数に渡せば、関数呼び出しのネストなどにかかわらず、aに直接アクセスできます。ただ、この操作はハードウェアの知識が必要となります。aの寿命はこのaが定義された関数内のみなので、aが定義された関数が終わるとaへのアクセスは不正なメモリ操作となります。この辺りのバグは初心者にはなかなか理解が難しいと思います。例えば

int* fun() 
{
    int a = 123;
    
    return &a;
}

int main()
{
    int* b = fun();
    printf("%d¥n", *b);
    return 0;
}

この操作は不正となります。int aはfun()の中でしか存在しないため、mainで呼び出されたprintf("%d¥n", *b);の操作は不正なメモリアクセスとなります。
こう言うバグはC言語を最初使った時には理解が難しく複雑なプログラムの場合特定ができず
C言語に嫌な印象を持つかもしれません。ただ、この辺りさえ理解すれば、そんなにC言語を恐れる必要はありません。ポインタを使えば変数の寿命がある限りプログラムのどの時点でもその変数にアクセスできる自由が得られます。またメモリを直接扱えるため、GCを実装してインタプリタを作ったりOSを作ったりすることができます。現在はスマートフォンやパソコンのアプリケーションを作ったりは他の言語を使うことが多いですが、依然としてOSを作ったりインタプリタを作ったり、その他高速な処理や、アプリケーションの基盤となるソフトウェア(ミドルウェア)ではC言語が主流となってます。まあ、そんな分野のソフトウェアはメーカーが作ることが多いため、あまり必要ではないかもしれませんが、インタプリタを自分で作ったりすることは大変面白く知的好奇心が高いエンジニアの方には刺激的な体験となるに違いありません。まあ、githubで公開してもあまりファボもつきませんし、あくまで過程を楽しむことに価値を見出すなら、C言語に挑戦することをお勧めします。
僕はRustはあまり知りませんけど、Rustほどは複雑な概念もなく、ポインタの概念さえ理解すれば、すぐマスターできる言語です。言語仕様はシンプルで、また美しく、潔い言語です。
インタプリタでいえばPythonのようにシンプルで潔さを感じる言語だと思います。
ただ、listやvectorなどは用意されていないため、C++を使うことも手かもしれません。
ただ、C++は言語仕様が複雑で、僕はあまり好きではありません。vectorやlistなどもC言語では
自分でその都度書いてしまうのが流儀です。慣れるとmapやvector, list, bufferなども諳んじてすぐかけてしまうでしょう。それを面倒と感じるか、楽しいと感じるかは人それぞれだとは思います。最近ではそのあたりのライブラリも、どこかgithubで用意されていると思います。確かApacheにそのようなライブラリが含まれていて、結構デファクトになっていると聞いたことがあります。

僕の言語ではboehmGCを使ってmap, vector, list, bufferなどを用意してます。C言語に魅力を感じられるなら、僕のコンパイラも試していただけると幸いです。

https://github.com/ab25cq/neo-c2

Discussion