29
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

多次元配列を関数に渡す

Last updated at Posted at 2014-01-23

こんなタイトルだと、
そもそも C に多次元配列はないとか、
関数に配列は渡せないなどと怒られそうだな。ごめんなさい。

サイズ指定のない2次元配列を渡せるようにする。
3次元以上も同じようにできると思う。多分。おそらく。きっと。

上手くいった例

2次元配列の各要素(配列)の先頭アドレスを格納した配列を用意し、
その配列の先頭アドレスを関数に渡している

もっと簡単な方法があるのかな。

#include <stdio.h>

void push(int **A);

int main(void){
    int A[3][3];
    int i,j;

    int *B[3];
    for (i=0;i<3;i++) B[i] = A[i];
    push(B);

    for (i=0;i<3;i++){
        for (j=0;j<3;j++) printf("%d ",A[i][j]);
        puts("");
    }   
    return 0;
}

void push(int **A){
    int i,j,k;
    for (i=0,k=0;i<3;i++){
        for (j=0;j<3;j++,k++) A[i][j] = k;
    }   
}

間違った例

次のコードはコンパイル時に警告が出て、実行すると Segmentation fault になる。

#include <stdio.h>

void push(int **A);

int main(void){
    int A[3][3];
    int i,j;

    push(A); // 型が違う

    for (i=0;i<3;i++){
        for (j=0;j<3;j++) printf("%d ",A[i][j]);
        puts("");
    }   
    return 0;
}

void push(int **A){
    int i,j,k;
    for (i=0,k=0;i<3;i++){
        for (j=0;j<3;j++,k++) A[i][j] = k;
    }   
}
警告: 互換性のないポインタ型から 1 番目の ‘push’ の引数に渡しています
備考: expected ‘int **’ but argument is of type ‘int (*)[3]’

追記 C++ の場合

多次元配列をラップするクラスを定義してその参照を関数に渡すっていう方法がありそう。

DoubleArray.h
class DoubleArray {
    // N*M の配列
    int N;
    int M;
    int *top; // 先頭の要素のポインタ
public:
    DoubleArray(int *p,int n,int m); 
    int *operator[](int i); 
    int getN();
    int getM();
};
DoubleArray.cpp
#include "DoubleArray.h"

DoubleArray::DoubleArray(int *p,int n,int m){ 
    top = p;
    N = n;
    M = m;
}

int *DoubleArray::operator[](int i){ return top + M*i;}

int DoubleArray::getN(){ return N;} 

int DoubleArray::getM(){ return M;} 
main.cpp
#include <iostream>

#include "DoubleArray.h"

using namespace std;

void push(DoubleArray &D);

int main(){
    int A[3][3];
    DoubleArray D(&A[0][0],3,3); // ここがちょっとかっこわるい
    push(D);

    for (int i=0;i<D.getN();i++){
        for (int j=0;j<D.getM();j++) cout << D[i][j] << ' ';
        cout << endl;
    }   

    return 0;
}

void push(DoubleArray &D){
    for (int i=0,k=0;i<D.getN();i++){
        for (int j=0;j<D.getM();j++,k++) D[i][j] = k;
    }   
}

追記(2)

プログラミング言語 C の新機能
にある可変長配列を使うことで解決した気がする。
こんなコードが許されるとは思わなんだ。

追記(3)

C++ では可変長配列がサポートされていないっぽい。。。 orz

c++ Wikipedia より

C99では、可変長配列、複素数型の組み込み変数、指示初期化子、複合リテラルといった、
C++でサポートしていない数多くの新機能が追加された

可変長配列使おうとするとコンパイルエラーになった。

29
25
14

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?