C言語でポインタと配列を入れ替える(スワップする)方法

412, 2022-02-15

目次

C言語でポインタと配列を入れ替える(スワップする)方法

C言語ではポインタと配列を扱えます。
これら2つは一部互換性があり、配列をポインタに代入することができます。
また関数の引数の配列とポインタは入れ替えも可能です。

ポインタと配列の入れ替え方法を知っておけば、C言語によるプログラミングの幅も広がります。
この記事ではポインタと配列を入れ替える方法を解説します。

関連記事

配列をポインタに代入する

C言語の配列はポインタに代入することができます

#include <stdio.h>

int main(void) {
    int ary[] = {1, 2, 3};  // 配列を定義
    int *p = ary;  // ポインタpに配列を代入

    printf("%d\n", p[0]);  // 1
    printf("%d\n", p[1]);  // 2
    printf("%d\n", p[2]);  // 3
    return 0;
}

配列をポインタに代入する場合はまず配列を定義しておきます。

    int ary[] = {1, 2, 3};  // 配列を定義

それからポインタ変数を定義してポインタ変数に配列を代入します。

    int *p = ary;  // ポインタpに配列を代入

↑のようにするとポインタ変数に配列を代入することができます。
この時、配列の型とポインタの型は同じにしておく必要があります。
aryの型はint型ですが、ポインタpの型もint型です。
これが型が異なっていると色々トラブルが起きます。

#include <stdio.h>

int main(void) {
    // double型の配列を定義
    double ary[] = {1, 2, 3};  

    // char型のポインタpに配列を代入
    // コンパイラによって警告が出力される
    // GCCでは「warning: initialization of ‘char *’ from incompatible pointer type ‘double *’」
    char *p = ary;

    return 0;
}

↑の例ではdouble型の配列をchar型のポインタに代入しています。
このような型の違う入れ替えはコンパイラによって警告が出力されます。
GCCでは

warning: initialization of ‘char *’ from incompatible pointer type ‘double *’

訳
警告: 'char *'が非互換なタイプ('double *')で初期化されています

↑のような警告メッセージが出ます。
つまりdouble型の配列とchar型のポインタは互換性がない、ということですね。

このような互換性のない型で入れ替えを行うとトラブルやバグの元になります。
ポインタと配列の入れ替えを行う場合は型を合わせておきましょう。

ポインタを配列に代入する

配列をポインタに代入することはできました。
その逆はどうでしょうか?
つまりポインタを配列に代入することは可能なのでしょうか?

結論から言うとできません。

#include <stdio.h>

int main(void) {
    int ary[3];  // 配列
    int *p;  // ポインタ変数

    ary = p;  // error: assignment to expression with array type

    return 0;
}

↑のように配列aryにポインタpを代入しようとするとエラーになります。
GCCでは↓のようなエラーメッセージが出力されます。

error: assignment to expression with array type

訳
エラー: 配列に代入しています。

このように配列にポインタを代入することはC言語の仕様上できなくなっています。

関数の引数の配列とポインタを入れ替える

配列とポインタのスワップは、配列型にポインタを代入できないことからできないことがわかりました。
しかし例外があります。
関数の引数の配列にポインタは代入できます。

#include <stdio.h>

// 引数に配列を取る関数
void func(int ary[]) {
    int *p = NULL;
    ary = p;

    printf("%p\n", ary);  // (nil)
}

int main(void) {
    int ary[] = {1, 2, 3};  // 配列を定義
    func(ary);
    return 0;
}

↑のコードをコンパイルしても警告やエラーは出力されません
生成されたプログラムも実行可能です。

なぜこんなことが可能なのかと言うと、関数の引数に定義する配列は、実質的にはポインタとして扱われるからです。

void func(int ary[]) {  // <- aryはポインタと同じ
    ...
}

そのため普通のポインタと互換性があり、代入やスワップを行うことができます。
これを利用して↓のように配列とポインタを入れ替えるスワップ(交換)処理を書くことができます。

#include <stdio.h>

// 引数に配列を取る関数
void func(int ary[]) {
    int *tmp;  // スワップで使用する一時変数
    int *p = NULL;  // スワップ対象のポインタ

    // aryとpのスワップ処理
    tmp = ary;
    ary = p;
    p = tmp;

    printf("%p\n", ary);  // (nil)
    printf("%d\n", p[0]);  // 1 
    printf("%d\n", p[1]);  // 2
    printf("%d\n", p[2]);  // 3
}

int main(void) {
    int ary[] = {1, 2, 3};  // 配列を定義
    func(ary);
    return 0;
}

おわりに

今回はC言語のポインタと配列を入れ替える方法について解説しました。
ポインタに配列を入れ替えることはできますが、その逆はできません。
しかし配列が関数の引数の場合は可能です。

(^ _ ^)

ポインタと配列は一部互換性がある

(・ v ・)

行儀よくスワップしましょう



この記事のアンケートを送信する