👓

C言語のポインタ概要とおすすめの学習参考書

2024/07/11に公開

はじめに

今となってはだいぶ昔のことですが、
新人のころ配属された案件(いわゆるSES案件)はC言語でした。
学生の頃には、プログラムに触れたこともなかった私は、
四苦八苦したのが今でも思い出されます。

そして、学習者のテンプレートのようにポインタでもつまずきました。
アドレスがどうして必要なのか、初めは全く理解できませんでした。
間違ったポインタを使うと、プログラムが突然クラッシュすることもあり、
それが原因で数時間デバッグに追われたこともあります。
さらにポインタのポインタという概念が出てきた時は、
エンジニア辞めようかなとちょっとだけ思いました。

でも、少しずつ、メモリの管理がどういうことかを理解し始め、
自分のプログラムがメモリ上でどう動いているのかを見えるようになると、
最初はただのアドレスを指すものだと思っていたけれど、その深さに驚かされました。
そんなことを思い出しながら今回はポインタの要点についてまとめてみようと思います。

ポインタとは

C言語を代表する非常に重要で強力な機能の一つで、メモリのアドレスを格納する変数のことです。
これにより、変数やデータの場所を直接操作することができます。
メモリ管理や関数の引数の受け渡し、動的メモリ確保、
配列や文字列の操作など、様々な場面で使用されます。
ポインタを使用することで、
関数間でのデータの受け渡しや、配列や構造体の操作が効率的になります。

ポインタの基本概念

  1. メモリアドレス:

    • コンピュータのメモリは、一連のバイトの集合体であり、各バイトには固有のアドレスが割り振られています。ポインタはこのアドレスを格納します。
  2. ポインタ変数:

    • ポインタ変数は、特定のデータ型のアドレスを格納する変数です。たとえば、int型の変数のアドレスを格納するポインタ変数は、int*として宣言されます。

ポインタの宣言と使用

ポインタ変数の宣言

ポインタ変数は、特定のデータ型のアドレスを保持する変数です。
宣言は以下のように行います。

int* ptr; // int型のポインタ変数ptrの宣言

ここで、ptrint型の変数のアドレスを格納するポインタです。
*はポインタであることを示しています。

アドレス演算子 (&) と間接演算子 (*)

  • アドレス演算子 (&)
    • 変数のアドレスを取得します。
  • 間接演算子 (*)
    • ポインタが指すメモリ位置の値にアクセスします。
int a = 10;
int* ptr = &a; // 変数aのアドレスをポインタptrに格納
printf("%d", *ptr); // ptrが指すアドレスの値を表示(10)

ポインタによる値の変更

ポインタを使って、変数の値を間接的に変更することができます。

int a = 10;
int* ptr = &a;
*ptr = 20; // ptrが指すアドレスの値を20に変更
printf("%d", a); // aの値を表示(20)

ポインタと配列

配列の名前はポインタ

配列の名前は、その配列の最初の要素のアドレスを指すポインタとして扱われます。

int arr[3] = {1, 2, 3};
int* ptr = arr; // arrは配列の最初の要素のアドレス
printf("%d", *(ptr + 1)); // 2を表示

ポインタを使った配列の操作

ポインタを使って配列の各要素にアクセスし、操作することができます。

for(int i = 0; i < 3; i++) {
    printf("%d ", *(ptr + i)); // arrの各要素を表示
}

ポインタと関数

ポインタを使った関数の引数渡し

ポインタを使って関数に引数を渡すことで、関数内で元の変数の値を変更することができます。

void increment(int* num) {
    (*num)++;
}
int main() {
    int a = 10;
    increment(&a); // aのアドレスを渡す
    printf("%d", a); // aの値は11になる
    return 0;
}

動的メモリ管理

mallocとfree

C言語では、malloc関数を使用して動的にメモリを確保し、free関数を使用して確保したメモリを解放します。

int* ptr = (int*)malloc(sizeof(int) * 5); // int型の5つ分のメモリを確保
if (ptr == NULL) {
    // メモリ確保失敗時の処理
}
// 使用後にメモリを解放
free(ptr);

ポインタのポインタ(多重ポインタ)

ポインタそのもののアドレスを保持するポインタを多重ポインタと呼びます。

int a = 10;
int* ptr = &a; // aのアドレスを格納
int** dptr = &ptr; // ptrのアドレスを格納
printf("%d", **dptr); // 10を表示

関数ポインタ

関数のアドレスを保持するポインタもあります。
関数ポインタを使うと、関数を引数として渡したり、動的に呼び出したりすることができます。

int add(int a, int b) {
    return a + b;
}
int main() {
    int (*func_ptr)(int, int) = &add; // 関数ポインタの宣言と初期化
    printf("%d", func_ptr(2, 3)); // 関数ポインタを使って関数を呼び出し
    return 0;
}

まとめ

ポインタは、C言語の強力な機能であり、
効率的なメモリ管理や直接的なハードウェア操作を可能にします。
ポインタを理解し、正しく使用することで、
プログラムの性能や柔軟性を大幅に向上させることができます。

さいごに

学習におすすめの本を紹介しておわりたいと思います。

C言語のポインタがゼッタイにわかる本

ポインタの基礎を繰り返し丁寧に解説してくれています。
今だと入手し難いと思いますが、とても良著です。
(応用的な学習をしたい人は他の本の方が満足できるかもしれません)

https://amzn.asia/d/00yyJzEp

新・明解C言語 ポインタ完全攻略

こちらも良著で、ポインタとアドレスの関係など丁寧に書かれています。
安定の柴田先生の本です。
私はC言語の基本は柴田先生の本で学びました。
こちらはkindle版もあり、今でも容易に入手可能です。

https://amzn.asia/d/05HgNgCJ

新・標準プログラマーズライブラリ C言語 ポインタ完全制覇

ロングセラー『C言語 ポインタ完全制覇』の改訂版です。
ポインタ学習の定番と言ってもいいかもしれません。
kindle、紙ともに販売されているので一番入手は容易かと思います。

https://amzn.asia/d/0a0iYRMy

合同会社カメレオンミーム Tech Blog

Discussion