1

私はCを初めて使用しますが(少しの苦痛の後でそれが好きになり始めます)、マトリックスを送信するのに少し問題があります。私は自分のメイン関数ですべてを構築し始めました、そしてそれはうまくいきました。私はこのようなリストを作成しました:int list[sizeOfBuckets][30];次にデータを追加し、それを読みたいときに次のようなことをしました:

    int x;
    int xx;
    for (x=0;x<sizeof(current_list) / sizeof(current_list[0]); x++) {
        printf("we are in the list \n");
        for (xx=0;xx<sizeof(current_list[x]) / sizeof(current_list[x][0]); xx++) {
            printf("item: %i \n", current_list[x][xx]);
        } 
    }

それはうまくいきました、それは私にマトリックスの内容を与えるでしょう。しかし、今はそれを関数に送信したいのですが、問題が発生しています。いくつか読んで、Cが事前に次元を知る必要があるため、行列は配列を送信することと同じではないことを学びましたが、これは動的に変化するため、両方のサイズを監視する2つの変数を作成し、それらを配列に送信します(私のテストでは、それらが正しいことを確認しました。listはlistです[2][30])。これが私の関数です:

void process_list(int **current_list, int num_of_rows, int num_items_in_row) {
    printf("hello from function \n");
    //test the list
    int x;
    int xx;
    for (x=0;x<num_of_rows; x++) {
        printf("we are in the list \n");
        for (xx=0;xx<num_items_in_row; xx++) {
            printf("item: %i \n", current_list[x][xx]);
        } 
    }
}

それは私にはうまくいきません。we are in the list私が期待するように、実際のアイテム(以下のforループから)ではなく、単に印刷します。GCCでコンパイルすると、次の警告が表示されます。

./learningC.c: In function ‘main’:
./learningC.c:169: warning: passing argument 1 of ‘process_list’ from incompatible pointer type

私は何が間違っているのだろうか?それが役立つ場合は、配列を変更する必要はありません。関数にコンテンツを送信するだけで、関数は別の結果を出力します。

更新:これが私が送っているマトリックスです:

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 4],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 4],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 4],

期待される結果は次のとおりです。

hello from function 
we are in the list 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 2 
item: 2 
item: 2 
item: 4 
we are in the list 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 1 
item: 1 
item: 2 
item: 2 
item: 4 
we are in the list 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 0 
item: 1 
item: 2 
item: 1 
item: 2 
item: 4 
4

5 に答える 5

5

最新の C コンパイラをお持ちの場合は、C99 から始めると、このように可変長 (専門用語は「VLA」) の行列を渡すことができます。

void process_list(size_t num_of_rows, size_t num_items_in_row, int current_list[num_of_rows][num_items_in_row]) {
... access the elements as current_list[i][j] here ...
}

配列パラメーターの宣言で認識されるように、配列の前にサイズがあることに注意してください。

ところで、あなたの試み**はまったく正しくありません。2D マトリックスとポインターの配列は、まったく別のものです。

于 2012-06-03T23:08:46.993 に答える
3

n次元配列は、依然として1次元メモリ空間の配列です。したがって、ポインタへのポインタではなく、ポインタのみを使用してください。

void process_list(int *current_list, int num_of_rows, int num_items_in_row) {
    printf("hello from function \n");
    //test the list
    int x;
    int xx;
    for (x=0;x<num_of_rows; x++) {
        printf("we are in the list \n");
        for (xx=0;xx<num_items_in_row; xx++) {
            printf("item: %i \n", current_list[x*num_items_in_row + xx]); % previously it was x*num_of_rows + xx
        } 
    }
}

要素へのアクセス方法も変更しました。次に、次のような関数呼び出しを行う必要があります。

process_list(*current_list,3,3);
于 2012-06-03T22:26:34.653 に答える
2

2D 配列を渡す方法はいくつかあります。最初にこれらの例をいくつか見てから、コードの根本的なエラーを指摘します。

/*
 * Array with empty first dimension.
 * Note the y value passed is redundant in this case.
 */
void process_matrix(int matrix[][4], int x, int y)
{
    for(int i = 0; i < x; i++) {
        for(int j = 0; j < y; j++) {
            printf("[%d][%d] = %d\n", i, j, matrix[i][j]);
        }

        puts("");
    }
}

この関数は、最初の次元が空の配列を受け取ります。これにより、指定した不明なサイズを渡すことができます。yなどのマクロを使用して元に戻すことができるため、この場合は冗長ARRAY_SIZEです。

/*
 * Pointer to array with explicitly specified second dimension.
 * Again the y value passed is redundant in this case.
 */
void process_matrix2(int (* matrix)[4], int x, int y)
{
    for(int i = 0; i < x; i++) {
        for(int j = 0; j < y; j++) {
            printf("[%d][%d] = %d\n", i, j, matrix[i][j]);
        }

        puts("");
    }
} 

これは、2 番目の次元が明示的に指定されている配列へのポインターです。この場合、非常に重要なブラケットに注意してください。角かっこのない同じコードは依然として有効な C ですが、まったく異なる意味を持ちます。上記と同様の議論により、yパラメーターは冗長です。

/*
 * Both dimensions known.
 * Note the x and y value passed are both redundant in this case.
 */
void process_matrix3(int matrix[2][4], int x, int y)
{
    for(int i = 0; i < x; i++) {
        for(int j = 0; j < y; j++) {
            printf("[%d][%d] = %d\n", i, j, matrix[i][j]);
        }

        puts("");
    }
}

このケースはあなたには当てはまらないかもしれませんが、完全を期すためにここに記載されています。両方の次元がわかっている場合は、関数プロトタイプの一部として指定できます。上記と同様の議論により、ここxyは冗長です。

上記の関数は、次のコードでテストできます (必ず でコンパイルして-std=c99ください)。

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

int main(void)
{
    int matrix[2][4] = {{1,2,3,4}, {8,7,6,5}};

    process_matrix(matrix, 2, 4);
    process_matrix2(matrix, 2, 4);
    process_matrix3(matrix, 2, 4);
    process_matrix4(matrix, 2, 4);
    return EXIT_SUCCESS;
}

元のコードに戻ると、ダブル ポインターを 2D 配列として使用できないという問題があります。この記事から引用するには、必ず読む必要があります。

...「int **mat」と宣言してから、「mat」を 2D 配列として使用するのは間違っています。これらは 2 つの非常に異なるデータ型であり、それらを使用してメモリ内の異なる場所にアクセスします。正常なマシン (VAX/VMS など) では、この間違いによりプログラムが「メモリ アクセス違反」エラーで中止されます。

減衰規則を同じ配列に再帰的に (複数回) 適用してはならないことを忘れがちであるため、この間違いはよくあります。2D 配列は double ポインターと同等ではありません。「T のポインターへのポインター」は、「T の 2D 配列」として機能できません。2D 配列は「T の行へのポインター」と「同等」であり、これは「T のポインターへのポインター」とは大きく異なります。

この記事では、配列をフラット化するなど、私が示していない 2D 配列を渡すいくつかの方法を示しています

于 2012-06-03T22:57:57.923 に答える
2

C で静的に割り当てられた多次元配列と動的に割り当てられた多次元配列の間には微妙な違いがあり、それらを正確に覚えているかどうかはわかりません。そうは言っても、行列の正しい型は、実際には 1 次元の 30 要素の整数配列へのポインターだと思います。関数宣言を read: void process_list(int current_list[][30], int num_of_rows, int num_items_in_row)、またはおそらくに変更してみてくださいvoid process_list(int *current_list[30], int num_of_rows, int num_items_in_row)

于 2012-06-03T22:58:18.973 に答える
0

私はすべて、静的配列をオブジェクト対ポインターとして扱うことに賛成です。ただし、既存のコードの修正に関する場合は、Cキャストのトリックを[慎重に]適用することができます。

静的配列をprocess_list関数に渡す元の例では、次のようにすることができます。

int **arrptr;
int static_arr[3][4] = {...};  /* init static array */
...
*arrptr = (int *)&static_arr;    /* put the static_arr address into arrptr */

process_list(arrptr, num_rows,num_cols);

これにより、静的配列がmallocされたかのように効果的に処理されます。つまり、ポインタarrptrには、コンパイル時に割り当てられる実際のアドレスではなく、static_arrのメモリアドレスへの参照が含まれます。

注:私はそのような手法を推奨していません。コードに適用する場合は、キャストの意図に関するコメントを提供する必要があります。そうしないと、誰かが無意識のうちにそのようなポインタを「解放」しようとしたり、スコープの問題などが発生したりする可能性があります。

于 2012-06-08T21:12:29.573 に答える