2012-05-04 5 views
2

行列の乗算のためのC関数を書いています。 intの2つの2D配列が必要です。私は入力配列の寸法を知っていればこれを行うことができますが、より一般的な機能を作りたいと思います。寸法が不明な2D配列を使用するにはどうすればいいですか?

コンパイル時に製品の寸法がわからないときに寸法を見つける方法と配列を返す方法はありますか?

+1

また、別の引数としてサイズを渡す必要がありますか? – Andreas

+1

知る唯一の方法は、配列ディメンションをパラメータとして関数に渡すことです。 – Mahesh

答えて

5

配列の先頭にポインタを置いていれば、配列のサイズを知ることはできません。配列の次元を関数に渡す必要があります。

1

配列の寸法を渡す必要があります。次に、結果を保持するために3番目の配列を動的に割り当てる必要があります。結果行列を計算したら、ポインタを返すことができます。

int* matix_multiply(int* matrix_a, int* matrix_b, int n, m, int p){ 

    int *result = (int *) malloc(sizeof(int) * a_rows * b_cols); 
    if(result == NULL) 
     exit(EXIT_FAILURE); 
    //loops to do the actual multiplication and store the results in result[i][j] 
    return result; //returns the result array 
} 
2

あなたはアレイのマトリックス構造を作成するオフ最高です:

は、AがN×Mマトリクスであり、Bがm X pを行列であるこれらの線に沿って何かを試してみてください。 @Davidが指摘したように、Cでは、あなた自身の次元を追跡しなければならない。安全にこれを行うための言語に組み込まれた関数はありません。

文字列の場合はstrlen()のような関数があります(つまり、\ 0で終わるchar配列)が、配列などの場合はそうではありません。これを追跡する最も簡単な方法は、独自の抽象データ型とヘルパー関数を作成することです。

これを試してみてください:

typedef struct matrix { 
    int **array; 
    int rows; 
    int cols; 
} matrix_t; 


int createMatrix(matrix_t* mtx) { 
    int i; 
    if (!mtx) { 
    printf("INVALID POINTER TO MATRIX"); 
    return -1; 
    } 
    if ((mtx->rows == 0) || (mtx->cols == 0)) { 
    printf("Rows/columns cannot be zero!"); 
    return -1; 
    } 
    int status = 0; 
    // allocate the array 
    mtx->array = (int **)calloc(mtx->rows,sizeof(int*)); 
    if(mtx->array != NULL) { 
    // memory allocation succeeded 
    for(i = 0; i < mtx->rows; i++) { 
     if((mtx->array[i] = (int*)calloc(mtx->cols,sizeof(int))) == NULL) { 
     printf("Memory allocation error"); 
     status = -1; 
     break; 
     } else { 
     // Allocation successful 
     } 
    } 
    } else { 
    printf("Memory allocation error!"); 
    status = -1; 
    } 
    return status; 
} 

int destroyMatrix(matrix_t* mtx) { 
    // destroy the array 
    for(i = 0; i < mtx->rows; i++) { 
    if(mtx->array[i] != NULL) { 
     free(mtx->array[i]); 
     mtx->array[i] = NULL; 
    } 
    } 
    if(mtx->array) { 
    free(mtx->array); 
    mtx->array = NULL; 
    } 
    return 0; 
} 

は今、あなたはちょうど新しいマトリックス構造を作成することができ、設定された行/列の値、createMatrixを呼び出して、あなたが設定されています

matrix_t myMtx; 
    myMtx.array = NULL; 
    myMtx.rows = 3; 
    myMtx.cols = myMtx.cols; // Make it a square matrix 
    if(createMatrix(&myMtx) == 0) { 
    printf("Created matrix successfully"); 
    } else { 
    printf("Failed to create matrix!"); 
    } 

これらの機能をも親切メモリ割り当てが失敗したかどうかを確認し、すべてのポインタを使用する前にすべてのポインタをチェックしてプログラムをクラッシュさせないようにします(例:SEGFAULT)。

幸運を祈る!

+0

もしあなたが 'createMatrix()'を呼び出す前にそれらを初期化しなければならないので、このアプローチをとると、少なくとも行と列のパラメータを 'createMatrix()'に渡すことになります。 –

+0

異なった文体の選択、それはようである。私は構造体が自己完結型であることを好み、create関数は適切なチェックを行います。大きなコンテキスト変数を扱うときは、関数プロトタイプを長時間のIMHOとは対照的に、小さくて読みやすくするのがより理にかなっています。 – DevNull

+0

ええ、私は、関数プロトタイプを短くて甘く保つことが良い点だと思います。私はデータ隠蔽/カプセル化の観点からもっと考えていました。 –

2

Cには実際の2D配列はありません。配列の配列は全く同じものではありません。 (私はこれを言うために殴られることを知っています。私と一緒に抱きしめてください)

違いはそれほど重要でないように見えるかもしれませんが、配列を操作するには、コンパイル時にディメンションを知る必要はありません。

double dot_product (double a[], double b[], int size); 
/* an A-OK function */ 

インスタンス

のためにしかし、あなたは は、任意の配列 要素の大きさを知っている必要があります。あなたは完全に一般的な行列操作コードをしたい場合は、インスタンス

void matrix_product (double a[][], double b[][], double result[][], 
        int a_rows, int a_cols, int b_cols); 
/* Bad, would not compile. You are only permitted to say "double[N][]", 
    where N is known at compile time */ 

について、あなたはプレーンな1次元配列を使用して、行と列の数字のうち、自分でインデックスを計算する必要があります。また、次元を渡す必要があります。この例では

void matrix_product (double a[], double b[], double result[], 
        int a_rows, int a_cols, int b_cols) { 
    ... 
    for (col = 0; col < a_cols; ++col) { 
    for (row = 0; row < a_rows; ++row) { 
     ... 
     ... a[row*a_cols + col] ... 
     ... 

、発呼者はresultなく、乗算機能を割り当てます。


あなたはこのように、抽象行列データ型の何らかの形でその寸法と一緒に行列をカプセル化することになるでしょういくつかのより高いレベルで

struct matrix { 
    double* elements; 
    int rows, cols; 
}; 

が、それは全体の「Notherの話です。

+0

私は、単一のアレイが行く方法であることに同意します。ドッグベルトの答えは "他の"方法を示しています。構造体でカプセル化を行う方法の例については、私の答えを参照してください。 –

4

この回答はトータルオーバーキルですが、これは私のstructに基づく方法です。 「全体的な話」と呼ばれる。

これは新しいプログラム(つまり、関数の入力/出力がどのように見えるかを定義する)で、行列を使って多くの作業を行うつもりなら、構造体を使用してその構造体のインスタンスへのポインタを渡すだけです。

次のコードは、1つの考えられる方法を示しています。ここには2つの "トリック"があります。まず第一に、データはすべて1つの連続したブロックに格納されます。これは、さまざまな理由でパフォーマンスを向上させる可能性があります。この手法の潜在的な欠点の1つは、完全に新しいインスタンスを割り当ててデータをコピーする必要があるため、行列のサイズ変更が高価になるということです。しかし、問題があると分かっている場合は、常にmatrix_get()とmatrix_set()関数を使用して行列の値にアクセスすると仮定して、実装を変更することができます。

また、データポインタが指している行列構造体とメモリは、すべて1回のmalloc呼び出しで割り当てられます。この手法を使用する場合は、データの配置に関する問題のみを認識してください。たとえば、64ビットの整数または倍精度を指すようにデータを変更する場合は、すべてが8バイト境界になるようにパディングを追加する必要があります。代わりに、 free_matrix()で解放することを覚えていれば、new_matrix()関数内の別の配列としてデータポインタだけを使用することもできます。

私は、乗算機能を書くためにOPに練習問題として残しました。

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

struct matrix 
{ 
    int rows; 
    int cols; 
    int * data; 
}; 

struct matrix * new_matrix(int rows, int cols) 
{ 
    struct matrix * m = NULL; 

    /* Allocate a block of memory large enough to hold the matrix 'header' struct 
    * as well as all the row/column data */ 
    m = malloc(sizeof(struct matrix) + (rows * cols * sizeof(int))); 

    if(m) 
    { 
     m->rows = rows; 
     m->cols = cols; 

     /* Some ugly pointer math to get to the first byte of data */ 
     m->data = (int*) ((char *) m + sizeof(*m)); 
    } 
    return m; 
} 

void free_matrix(struct matrix * m) 
{ 
    free(m); 
} 

int matrix_set(struct matrix * m, int row, int col, int val) 
{ 
    if(col >= m->cols || row >= m->rows) 
     return -1; 
    m->data[ m->cols * row + col ] = val; 
    return 0; 
} 

int matrix_get(struct matrix * m, int row, int col, int * val) 
{ 
    if(col >= m->cols || row >= m->rows) 
     return -1; 
    else 
    { 
     *val = m->data[ m->cols * row + col ]; 
     return 0; 
    } 
} 

void print_matrix(struct matrix * m) 
{ 
    int r,c; 
    int val; 
    for(r = 0; r < m->rows; r++) 
    { 
     for(c = 0; c < m->cols; c++) 
     { 
     matrix_get(m, r, c, &val); 
     printf("%5d%s", val, c + 1 < m->cols ? "," : ""); 
     } 
     printf("\n"); 
    } 
} 

int main (int argc, char **argv) 
{ 
    int r,c; 
    struct matrix * m = new_matrix(5, 5); 

    for( r = 0; r < m->rows; r++) 
    { 
     for(c = 0; c < m->cols; c++) 
     { 
     matrix_set(m, r, c, (r +1)* 10 + c + 1); 
     } 
    } 

    print_matrix(m); 
    free_matrix(m); 
    return 0; 
} 
0
#include <stdio.h> 

void foo(int *a, int m, int n) 
{ 
    for(int i=0; i<m; i++) 
     for(int j=0; j<n; j++) 
      printf("%d\n", *(a+i*n+j)); 
} 
int main() 
{ 
    int a[][2] = {{1,2},{3,4}}; 
    foo((int *)a,2,2); 
    return 0; 
} 

一般の2Dアレイは、行の主要な方法で格納されています。 2D配列は、要素の配列を指すポインタの配列と考えることができます。 2次元を渡しているので、それに応じて要素にアクセスできます。

他のデータ型でも試すことができます。私は構造を使った。

#include <stdio.h> 
struct abc 
{ 
    int a; 
    float b; 
    char c; 
}; 
void foo(struct abc *a, int m, int n) 
{ 
    for(int i=0; i<m; i++) 
     for(int j=0; j<n; j++) 
      printf("%d %f %c\n", (a+i*n+j)->a, (a+i*n+j)->b, (a+i*n+j)->c); 
} 
int main() 
{ 
    struct abc a[][2] = {{{1,1.0,'a'},{2,2.0,'b'}}, {{3,3.0,'c'},{4,4.0,'d'}}}; 
    foo((struct abc *)a,2,2); 
    return 0; 
} 

希望する.... !!!!!

+1

あなたのコードが質問を解決する方法を説明するために、いくつかのコメントを追加する必要があります。 – moggi

+1

答えを詳しく記入してください – UmarZaii

関連する問題