「C言語】ポインタを使って配列を操作する方法を解説

ポインタを使った配列の操作方法を理解することで、より効率的なC言語プログラミングが可能になります。

本記事では、ポインタを使用した配列の宣言や初期化方法、要素へのアクセス方法などについて詳しく解説します。

目次

ポインタを使った配列の宣言方法

ポインタを使った配列の宣言方法について説明します。

まず、通常の配列の宣言方法は以下のようになります。

int array[5];

これは、要素数が5である整数型の配列を宣言しています。しかし、ポインタを使った場合は以下のように書くことができます。

int *array;

この場合、*(アスタリスク)が付いていることに注目してください。

これは、「ポインタ型」と呼ばれるものであり、変数名の前に「*」を付けることで定義されます。

また、この時点ではまだメモリ上に領域が確保されておらず、配列として扱えません。

次に、先程定義したポインタ array に、配列の要素数分だけメモリ領域を確保して、アドレスを代入する必要があります。その際は malloc() 関数を使用します。

malloc()関数は、stdlib.hのインクルードが必要なので注意してください。

array = (int*)malloc(sizeof(int) * 5);

上記コードでは sizeof(int) をかけることで1つ分(4バイト)確保し、それを5倍することで全体的なサイズ(20バイト)を計算しています。そして (int*) というキャスト演算子を用いて int型のポインタへキャストし代入しています。

これにより、要素数5個の配列が生成されます。

この方法の場合、動的に要素数を指定できるため、データ量に合わせて柔軟に配列の要素数を最適化することが出来ます。

ポインタを使った配列要素へのアクセス方法

ポインタを使った配列要素へのアクセス方法について説明します。

まず、配列名はその先頭要素のアドレスを表しています。例えば、int型の配列aがある場合、aと書くことで最初の要素a[0]のアドレスを表します。

次に、ポインタ変数を用意し、その中に配列を代入することで、ポインタ変数でも同じアドレスが指されます。例えば、

int a[5] = {1, 2, 3, 4, 5};
int *p;
p = a; // pにa[0]のアドレスが代入される
printf("%d\n", p[2]); //p[2] は a[2]と同じ

このようにすることで、pからもa[0]~a[4]まで全ての要素にアクセスすることが出来ます。

また、「*(ポインタ変数 + インデックス)」という書き方でも特定の要素に直接アクセスすることが出来ます。例えば、

*(p + 2) = 10; // a[2] = 10; と同じ意味

このような書き方であれば、「+」や「-」演算子を使って任意の位置から始めることも可能です。

関数におけるポインタを使った配列の渡し方

関数において、配列を引数として渡す場合、その配列の先頭アドレスが渡されます。このため、ポインタを使って配列要素にアクセスすることができます。

以下は、ポインタを使った配列の渡し方の例です。

#include <stdio.h>

void printArray(int *arr, int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
}

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int size = sizeof(arr) / sizeof(arr[0]);

    // 関数呼び出し時にポインタを渡す
    printArray(arr, size);

    return 0;
}
1 2 3 4 5 

上記のコードでは、printArray()関数内で受け取ったポインタ *arr を使用して、配列要素にアクセスしています。また、main()関数内で定義した arr 配列を printArray()関数に引数として渡しています。

このような方法であれば、大量のデータや複雑な処理でも、関数化して処理を分けることで、効率的かつ簡単にプログラムを実装することが可能です。

ポインタを使った多次元配列の宣言方法と要素へのアクセス方法

多次元配列は、2次元以上の配列を指します。例えば、行列や画像処理などでよく使われます。

二次元配列の宣言方法

まずは、2次元配列の宣言方法から説明します。以下のように、int型の要素を持つ3×3の2次元配列を宣言する場合を考えてみましょう。

int array[3][3];

このように書くことで、9個分のメモリが確保されます。また、各要素へは以下のようにアクセスすることが出来ます。

array[0][0] = 1;
array[0][1] = 2;
array[0][2] = 3;

array[1][0] = 4;
array[1][1] = 5;
array[1][2] = 6;

array[2][0] = 7;
array[2][1] = 8;
array[2][2] = 9;

ポインタを使った二次元配列の宣言方法

ポインタを使っても、二次元配列の宣言やアクセスが可能です。以下では上記と同じ内容をポインタで表現した場合です。

#include <stdio.h>
#include<stdlib.h>

int main() {
   int **p_array; // ポインタ変数
    
    int dim1_size = 3;
    int dim2_size = 3;
    // 配列全体用にメモリ確保
    p_array=(int**)malloc(sizeof(int*) * dim1_size);

    // 各行用にメモリ確保
    for(int i=0; i < 3; i++){
        p_array[i]=(int *)malloc(sizeof(int) * dim2_size);
    }
    
    // 値代入(初期化)
    p_array [0][0]=10 ;
    p_array [0][1]=20 ;
    p_array [0][2]=30 ;
    
    p_array [1][0]=40 ;
    p_array [1][1]=50 ;
    p_array [1][2]=60 ;
    
    p_array [2][0]=70 ;
    p_array [2][1]=80 ;
    p_array [2][2]=90 ; 
    
    for(int i = 0; i < dim1_size; i++){
        for(int j = 0; j < dim1_size; j++){
            printf("p_array[%d][%d] = %d\n", i, j, p_array[i][j]);
        }
        
    }

    return 0;
}
p_array[0][0] = 10
p_array[0][1] = 20
p_array[0][2] = 30
p_array[1][0] = 40
p_array[1][1] = 50
p_array[1][2] = 60
p_array[2][0] = 70
p_array[2][1] = 80
p_array[2][2] = 90

三次元以上でも同様にポインタを使って宣言・代入・取得が扱えますが、ポインタ変数の扱いやメモリ確保部分が複雑化していきます。

使いこなせれば非常に便利ですが、バグの温床にもなりやすいため、次元数が大きくなりすぎる場合は構造体を定義するなどをして、対策するようにしましょう。

まとめ

ポインタを使った配列は、初めは少し難しく感じるかもしれませんが、慣れてくると便利な機能です。特に関数で配列を扱う場合は必須の知識です。

また、注意点としてはポインタが指すメモリ領域が確保されていない場合や範囲外を指定した場合にプログラムが異常終了することがあるため、注意深く使用するようにしてください。

目次